Auto merge of #82795 - m-ou-se:rollup-uzx0b92, r=m-ou-se
Rollup of 10 pull requests Successful merges: - #80723 (Implement NOOP_METHOD_CALL lint) - #80763 (resolve: Reduce scope of `pub_use_of_private_extern_crate` deprecation lint) - #81136 (Improved IO Bytes Size Hint) - #81939 (Add suggestion `.collect()` for iterators in iterators) - #82289 (Fix underflow in specialized ZipImpl::size_hint) - #82728 (Avoid unnecessary Vec construction in BufReader) - #82764 (Add {BTreeMap,HashMap}::try_insert) - #82770 (Add assert_matches macro.) - #82773 (Add diagnostic item to `Default` trait) - #82787 (Remove unused code from main.js) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8fd946c63a
46 changed files with 781 additions and 122 deletions
|
@ -24,7 +24,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
|
|||
|
||||
debug!("preparing the RPATH!");
|
||||
|
||||
let libs = config.used_crates.clone();
|
||||
let libs = config.used_crates;
|
||||
let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>();
|
||||
let rpaths = get_rpaths(config, &libs);
|
||||
let mut flags = rpaths_to_flags(&rpaths);
|
||||
|
|
|
@ -57,6 +57,7 @@ mod methods;
|
|||
mod non_ascii_idents;
|
||||
mod non_fmt_panic;
|
||||
mod nonstandard_style;
|
||||
mod noop_method_call;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod traits;
|
||||
|
@ -81,6 +82,7 @@ use methods::*;
|
|||
use non_ascii_idents::*;
|
||||
use non_fmt_panic::NonPanicFmt;
|
||||
use nonstandard_style::*;
|
||||
use noop_method_call::*;
|
||||
use redundant_semicolon::*;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
|
@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
|
|||
DropTraitConstraints: DropTraitConstraints,
|
||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
||||
NonPanicFmt: NonPanicFmt,
|
||||
NoopMethodCall: NoopMethodCall,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
|
111
compiler/rustc_lint/src/noop_method_call.rs
Normal file
111
compiler/rustc_lint/src/noop_method_call.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use crate::context::LintContext;
|
||||
use crate::rustc_middle::ty::TypeFoldable;
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
/// The `noop_method_call` lint detects specific calls to noop methods
|
||||
/// such as a calling `<&T as Clone>::clone` where `T: !Clone`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// #![warn(noop_method_call)]
|
||||
/// struct Foo;
|
||||
/// let foo = &Foo;
|
||||
/// let clone: &Foo = foo.clone();
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Some method calls are noops meaning that they do nothing. Usually such methods
|
||||
/// are the result of blanket implementations that happen to create some method invocations
|
||||
/// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but
|
||||
/// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything
|
||||
/// as references are copy. This lint detects these calls and warns the user about them.
|
||||
pub NOOP_METHOD_CALL,
|
||||
Allow,
|
||||
"detects the use of well-known noop methods"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// We only care about method calls.
|
||||
let (call, elements) = match expr.kind {
|
||||
ExprKind::MethodCall(call, _, elements, _) => (call, elements),
|
||||
_ => return,
|
||||
};
|
||||
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
||||
// traits and ignore any other method call.
|
||||
let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) {
|
||||
// Verify we are dealing with a method/associated function.
|
||||
Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
|
||||
// Check that we're dealing with a trait method for one of the traits we care about.
|
||||
Some(trait_id)
|
||||
if [sym::Clone, sym::Deref, sym::Borrow]
|
||||
.iter()
|
||||
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
|
||||
{
|
||||
(trait_id, did)
|
||||
}
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
||||
if substs.needs_subst() {
|
||||
// We can't resolve on types that require monomorphization, so we don't handle them if
|
||||
// we need to perfom substitution.
|
||||
return;
|
||||
}
|
||||
let param_env = cx.tcx.param_env(trait_id);
|
||||
// Resolve the trait method instance.
|
||||
let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
|
||||
Ok(Some(i)) => i,
|
||||
_ => return,
|
||||
};
|
||||
// (Re)check that it implements the noop diagnostic.
|
||||
for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() {
|
||||
if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
|
||||
let method = &call.ident.name;
|
||||
let receiver = &elements[0];
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||
if receiver_ty != expr_ty {
|
||||
// This lint will only trigger if the receiver type and resulting expression \
|
||||
// type are the same, implying that the method call is unnecessary.
|
||||
return;
|
||||
}
|
||||
let expr_span = expr.span;
|
||||
let note = format!(
|
||||
"the type `{:?}` which `{}` is being called on is the same as \
|
||||
the type returned from `{}`, so the method call does not do \
|
||||
anything and can be removed",
|
||||
receiver_ty, method, method,
|
||||
);
|
||||
|
||||
let span = expr_span.with_lo(receiver.span.hi());
|
||||
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
|
||||
let method = &call.ident.name;
|
||||
let message = format!(
|
||||
"call to `.{}()` on a reference in this situation does nothing",
|
||||
&method,
|
||||
);
|
||||
lint.build(&message)
|
||||
.span_label(span, "unnecessary method call")
|
||||
.note(¬e)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ use rustc_target::spec::abi;
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
|
||||
pub struct ExpectedFound<T> {
|
||||
|
@ -548,7 +547,6 @@ impl<T> Trait<T> for X {
|
|||
TargetFeatureCast(def_id) => {
|
||||
let attrs = self.get_attrs(*def_id);
|
||||
let target_spans = attrs
|
||||
.deref()
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::target_feature))
|
||||
.map(|attr| attr.span);
|
||||
|
|
|
@ -10,16 +10,18 @@ use rustc_middle::mir::{
|
|||
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
|
||||
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::dataflow::drop_flag_effects;
|
||||
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
||||
use crate::util::borrowck_errors;
|
||||
|
||||
use crate::borrow_check::{
|
||||
borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt,
|
||||
PrefixSet, WriteKind,
|
||||
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -1267,6 +1269,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
if return_span != borrow_span {
|
||||
err.span_label(borrow_span, note);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let ty_params = ty::List::empty();
|
||||
|
||||
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
let return_ty = tcx.erase_regions(return_ty);
|
||||
|
||||
// to avoid panics
|
||||
if !return_ty.has_infer_types() {
|
||||
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
|
||||
if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
|
||||
{
|
||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
|
||||
err.span_suggestion_hidden(
|
||||
return_span,
|
||||
"use `.collect()` to allocate the iterator",
|
||||
format!("{}{}", snippet, ".collect::<Vec<_>>()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(err)
|
||||
|
|
|
@ -165,7 +165,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
self.consume_operand(location, value);
|
||||
|
||||
// Invalidate all borrows of local places
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let resume = self.location_table.start_index(resume.start_location());
|
||||
for (i, data) in borrow_set.iter_enumerated() {
|
||||
if borrow_of_local_data(data.borrowed_place) {
|
||||
|
@ -177,7 +177,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
}
|
||||
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
||||
// Invalidate all borrows of local places
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let start = self.location_table.start_index(location);
|
||||
for (i, data) in borrow_set.iter_enumerated() {
|
||||
if borrow_of_local_data(data.borrowed_place) {
|
||||
|
@ -369,7 +369,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
);
|
||||
let tcx = self.tcx;
|
||||
let body = self.body;
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let indices = self.borrow_set.indices();
|
||||
each_borrow_involving_path(
|
||||
self,
|
||||
|
@ -377,7 +377,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
body,
|
||||
location,
|
||||
(sd, place),
|
||||
&borrow_set.clone(),
|
||||
borrow_set,
|
||||
indices,
|
||||
|this, borrow_index, borrow| {
|
||||
match (rw, borrow.kind) {
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
PatKind::Constant { value } => Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() },
|
||||
kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
|
||||
},
|
||||
|
||||
PatKind::Range(range) => {
|
||||
|
|
|
@ -156,6 +156,21 @@ impl<'a> NameResolution<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
|
||||
// are permitted for backward-compatibility under a deprecation lint.
|
||||
fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool {
|
||||
match (&import.kind, &binding.kind) {
|
||||
(
|
||||
ImportKind::Single { .. },
|
||||
NameBindingKind::Import {
|
||||
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
|
||||
..
|
||||
},
|
||||
) => import.vis.get() == ty::Visibility::Public,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
crate fn resolve_ident_in_module_unadjusted(
|
||||
&mut self,
|
||||
|
@ -263,10 +278,7 @@ impl<'a> Resolver<'a> {
|
|||
return Err((Determined, Weak::No));
|
||||
}
|
||||
}
|
||||
// `extern crate` are always usable for backwards compatibility, see issue #37020,
|
||||
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
|
||||
let usable = this.is_accessible_from(binding.vis, parent_scope.module)
|
||||
|| binding.is_extern_crate();
|
||||
let usable = this.is_accessible_from(binding.vis, parent_scope.module);
|
||||
if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
|
||||
};
|
||||
|
||||
|
@ -309,10 +321,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if !(self.is_accessible_from(binding.vis, parent_scope.module) ||
|
||||
// Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
(self.last_import_segment && binding.is_extern_crate()))
|
||||
{
|
||||
if !self.is_accessible_from(binding.vis, parent_scope.module) {
|
||||
self.privacy_errors.push(PrivacyError {
|
||||
ident,
|
||||
binding,
|
||||
|
@ -455,9 +464,8 @@ impl<'a> Resolver<'a> {
|
|||
binding: &'a NameBinding<'a>,
|
||||
import: &'a Import<'a>,
|
||||
) -> &'a NameBinding<'a> {
|
||||
let vis = if binding.vis.is_at_least(import.vis.get(), self) ||
|
||||
// cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
!import.is_glob() && binding.is_extern_crate()
|
||||
let vis = if binding.vis.is_at_least(import.vis.get(), self)
|
||||
|| pub_use_of_private_extern_crate_hack(import, binding)
|
||||
{
|
||||
import.vis.get()
|
||||
} else {
|
||||
|
@ -1188,7 +1196,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// All namespaces must be re-exported with extra visibility for an error to occur.
|
||||
if !any_successful_reexport {
|
||||
let (ns, binding) = reexport_error.unwrap();
|
||||
if ns == TypeNS && binding.is_extern_crate() {
|
||||
if pub_use_of_private_extern_crate_hack(import, binding) {
|
||||
let msg = format!(
|
||||
"extern crate `{}` is private, and cannot be \
|
||||
re-exported (error E0365), consider declaring with \
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS};
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// The proc macro code for this is in `src/librustc_macros/src/symbols.rs`.
|
||||
// The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`.
|
||||
symbols! {
|
||||
// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
|
||||
// this should be rarely necessary though if the keywords are kept in alphabetic order.
|
||||
|
@ -129,6 +129,7 @@ symbols! {
|
|||
BTreeMap,
|
||||
BTreeSet,
|
||||
BinaryHeap,
|
||||
Borrow,
|
||||
C,
|
||||
CString,
|
||||
Center,
|
||||
|
@ -141,6 +142,7 @@ symbols! {
|
|||
Decodable,
|
||||
Decoder,
|
||||
Default,
|
||||
Deref,
|
||||
Encodable,
|
||||
Encoder,
|
||||
Eq,
|
||||
|
@ -789,6 +791,9 @@ symbols! {
|
|||
none_error,
|
||||
nontemporal_store,
|
||||
nontrapping_dash_fptoint: "nontrapping-fptoint",
|
||||
noop_method_borrow,
|
||||
noop_method_clone,
|
||||
noop_method_deref,
|
||||
noreturn,
|
||||
nostack,
|
||||
not,
|
||||
|
|
|
@ -819,7 +819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
sig.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg.clone().kind {
|
||||
.map(|arg| match arg.kind {
|
||||
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
||||
Some(arg.span),
|
||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||
|
|
|
@ -165,7 +165,7 @@ crate fn evaluate_goal<'tcx>(
|
|||
// let's just ignore that
|
||||
let sol = Canonical {
|
||||
max_universe: ty::UniverseIndex::from_usize(0),
|
||||
variables: obligation.variables.clone(),
|
||||
variables: obligation.variables,
|
||||
value: QueryResponse {
|
||||
var_values: CanonicalVarValues { var_values: IndexVec::new() }
|
||||
.make_identity(tcx),
|
||||
|
|
|
@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
call_expr.span,
|
||||
expected,
|
||||
fn_sig.output().clone(),
|
||||
fn_sig.output(),
|
||||
fn_sig.inputs(),
|
||||
);
|
||||
|
||||
|
|
|
@ -711,7 +711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone());
|
||||
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
|
||||
ret_coercion.borrow_mut().coerce(
|
||||
self,
|
||||
&self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
|
||||
|
|
|
@ -14,7 +14,7 @@ use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
|
|||
use super::search::SearchResult::*;
|
||||
|
||||
mod entry;
|
||||
pub use entry::{Entry, OccupiedEntry, VacantEntry};
|
||||
pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
|
||||
use Entry::*;
|
||||
|
||||
/// Minimum number of elements in nodes that are not a root.
|
||||
|
@ -836,6 +836,40 @@ impl<K, V> BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tries to insert a key-value pair into the map, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
///
|
||||
/// If the map already had this key present, nothing is updated, and
|
||||
/// an error containing the occupied entry and the value is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_try_insert)]
|
||||
///
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
|
||||
///
|
||||
/// let err = map.try_insert(37, "b").unwrap_err();
|
||||
/// assert_eq!(err.entry.key(), &37);
|
||||
/// assert_eq!(err.entry.get(), &"a");
|
||||
/// assert_eq!(err.value, "b");
|
||||
/// ```
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>>
|
||||
where
|
||||
K: Ord,
|
||||
{
|
||||
match self.entry(key) {
|
||||
Occupied(entry) => Err(OccupiedError { entry, value }),
|
||||
Vacant(entry) => Ok(entry.insert(value)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a key from the map, returning the value at the key if the key
|
||||
/// was previously in the map.
|
||||
///
|
||||
|
|
|
@ -71,6 +71,41 @@ impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The error returned by [`try_insert`](BTreeMap::try_insert) when the key already exists.
|
||||
///
|
||||
/// Contains the occupied entry, and the value that was not inserted.
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
pub struct OccupiedError<'a, K: 'a, V: 'a> {
|
||||
/// The entry in the map that was already occupied.
|
||||
pub entry: OccupiedEntry<'a, K, V>,
|
||||
/// The value which was not inserted, because the entry was already occupied.
|
||||
pub value: V,
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<K: Debug + Ord, V: Debug> Debug for OccupiedError<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OccupiedError")
|
||||
.field("key", self.entry.key())
|
||||
.field("old_value", self.entry.get())
|
||||
.field("new_value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<'a, K: Debug + Ord, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"failed to insert {:?}, key {:?} already exists with value {:?}",
|
||||
self.value,
|
||||
self.entry.key(),
|
||||
self.entry.get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Entry<'a, K, V> {
|
||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
|
|
|
@ -1801,11 +1801,11 @@ fn test_occupied_entry_key() {
|
|||
let key = "hello there";
|
||||
let value = "value goes here";
|
||||
assert!(a.is_empty());
|
||||
a.insert(key.clone(), value.clone());
|
||||
a.insert(key, value);
|
||||
assert_eq!(a.len(), 1);
|
||||
assert_eq!(a[key], value);
|
||||
|
||||
match a.entry(key.clone()) {
|
||||
match a.entry(key) {
|
||||
Vacant(_) => panic!(),
|
||||
Occupied(e) => assert_eq!(key, *e.key()),
|
||||
}
|
||||
|
@ -1821,11 +1821,11 @@ fn test_vacant_entry_key() {
|
|||
let value = "value goes here";
|
||||
|
||||
assert!(a.is_empty());
|
||||
match a.entry(key.clone()) {
|
||||
match a.entry(key) {
|
||||
Occupied(_) => panic!(),
|
||||
Vacant(e) => {
|
||||
assert_eq!(key, *e.key());
|
||||
e.insert(value.clone());
|
||||
e.insert(value);
|
||||
}
|
||||
}
|
||||
assert_eq!(a.len(), 1);
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_diagnostic_item = "Borrow"]
|
||||
pub trait Borrow<Borrowed: ?Sized> {
|
||||
/// Immutably borrows from an owned value.
|
||||
///
|
||||
|
@ -205,6 +206,7 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Borrow<T> for T {
|
||||
#[rustc_diagnostic_item = "noop_method_borrow"]
|
||||
fn borrow(&self) -> &T {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -104,12 +104,14 @@
|
|||
/// [impls]: #implementors
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "clone"]
|
||||
#[rustc_diagnostic_item = "Clone"]
|
||||
pub trait Clone: Sized {
|
||||
/// Returns a copy of the value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(noop_method_call)]
|
||||
/// let hello = "Hello"; // &str implements Clone
|
||||
///
|
||||
/// assert_eq!("Hello", hello.clone());
|
||||
|
@ -221,6 +223,7 @@ mod impls {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for &T {
|
||||
#[inline]
|
||||
#[rustc_diagnostic_item = "noop_method_clone"]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
/// bar: f32,
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Default: Sized {
|
||||
/// Returns the "default value" for a type.
|
||||
|
|
|
@ -200,6 +200,7 @@ where
|
|||
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a.size() {
|
||||
let i = self.index;
|
||||
self.index += 1;
|
||||
self.len += 1;
|
||||
// match the base implementation's potential side effects
|
||||
// SAFETY: we just checked that `i` < `self.a.len()`
|
||||
unsafe {
|
||||
|
@ -258,7 +259,7 @@ where
|
|||
if sz_a != sz_b {
|
||||
let sz_a = self.a.size();
|
||||
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
|
||||
for _ in 0..sz_a - cmp::max(self.len, self.index) {
|
||||
for _ in 0..sz_a - self.len {
|
||||
self.a.next_back();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
|
|||
message = "`{Self}` is not an iterator"
|
||||
)]
|
||||
#[doc(spotlight)]
|
||||
#[rustc_diagnostic_item = "Iterator"]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub trait Iterator {
|
||||
/// The type of the elements being iterated over.
|
||||
|
|
|
@ -110,6 +110,60 @@ macro_rules! assert_ne {
|
|||
});
|
||||
}
|
||||
|
||||
/// Asserts that an expression matches any of the given patterns.
|
||||
///
|
||||
/// Like in a `match` expression, the pattern can be optionally followed by `if`
|
||||
/// and a guard expression that has access to names bound by the pattern.
|
||||
///
|
||||
/// On panic, this macro will print the value of the expression with its
|
||||
/// debug representation.
|
||||
///
|
||||
/// Like [`assert!`], this macro has a second form, where a custom
|
||||
/// panic message can be provided.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(assert_matches)]
|
||||
///
|
||||
/// let a = 1u32.checked_add(2);
|
||||
/// let b = 1u32.checked_sub(2);
|
||||
/// assert_matches!(a, Some(_));
|
||||
/// assert_matches!(b, None);
|
||||
///
|
||||
/// let c = Ok("abc".to_string());
|
||||
/// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[unstable(feature = "assert_matches", issue = "82775")]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
macro_rules! assert_matches {
|
||||
($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
|
||||
match $left {
|
||||
$( $pattern )|+ $( if $guard )? => {}
|
||||
ref left_val => {
|
||||
$crate::panicking::assert_matches_failed(
|
||||
left_val,
|
||||
$crate::stringify!($($pattern)|+ $(if $guard)?),
|
||||
$crate::option::Option::None
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
|
||||
match $left {
|
||||
$( $pattern )|+ $( if $guard )? => {}
|
||||
ref left_val => {
|
||||
$crate::panicking::assert_matches_failed(
|
||||
left_val,
|
||||
$crate::stringify!($($pattern)|+ $(if $guard)?),
|
||||
$crate::option::Option::Some($crate::format_args!($($arg)+))
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Asserts that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// This will invoke the [`panic!`] macro if the provided expression cannot be
|
||||
|
@ -208,6 +262,42 @@ macro_rules! debug_assert_ne {
|
|||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Asserts that an expression matches any of the given patterns.
|
||||
///
|
||||
/// Like in a `match` expression, the pattern can be optionally followed by `if`
|
||||
/// and a guard expression that has access to names bound by the pattern.
|
||||
///
|
||||
/// On panic, this macro will print the value of the expression with its
|
||||
/// debug representation.
|
||||
///
|
||||
/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only
|
||||
/// enabled in non optimized builds by default. An optimized build will not
|
||||
/// execute `debug_assert_matches!` statements unless `-C debug-assertions` is
|
||||
/// passed to the compiler. This makes `debug_assert_matches!` useful for
|
||||
/// checks that are too expensive to be present in a release build but may be
|
||||
/// helpful during development. The result of expanding `debug_assert_matches!`
|
||||
/// is always type checked.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(assert_matches)]
|
||||
///
|
||||
/// let a = 1u32.checked_add(2);
|
||||
/// let b = 1u32.checked_sub(2);
|
||||
/// debug_assert_matches!(a, Some(_));
|
||||
/// debug_assert_matches!(b, None);
|
||||
///
|
||||
/// let c = Ok("abc".to_string());
|
||||
/// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[unstable(feature = "assert_matches", issue = "82775")]
|
||||
#[allow_internal_unstable(assert_matches)]
|
||||
macro_rules! debug_assert_matches {
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_matches!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Returns whether the given expression matches any of the given patterns.
|
||||
///
|
||||
/// Like in a `match` expression, the pattern can be optionally followed by `if`
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#[doc(alias = "*")]
|
||||
#[doc(alias = "&*")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_diagnostic_item = "Deref"]
|
||||
pub trait Deref {
|
||||
/// The resulting type after dereferencing.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -78,6 +79,7 @@ pub trait Deref {
|
|||
impl<T: ?Sized> Deref for &T {
|
||||
type Target = T;
|
||||
|
||||
#[rustc_diagnostic_item = "noop_method_deref"]
|
||||
fn deref(&self) -> &T {
|
||||
*self
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
|||
pub enum AssertKind {
|
||||
Eq,
|
||||
Ne,
|
||||
Match,
|
||||
}
|
||||
|
||||
/// Internal function for `assert_eq!` and `assert_ne!` macros
|
||||
|
@ -113,32 +114,54 @@ where
|
|||
T: fmt::Debug + ?Sized,
|
||||
U: fmt::Debug + ?Sized,
|
||||
{
|
||||
#[track_caller]
|
||||
fn inner(
|
||||
kind: AssertKind,
|
||||
left: &dyn fmt::Debug,
|
||||
right: &dyn fmt::Debug,
|
||||
args: Option<fmt::Arguments<'_>>,
|
||||
) -> ! {
|
||||
let op = match kind {
|
||||
AssertKind::Eq => "==",
|
||||
AssertKind::Ne => "!=",
|
||||
};
|
||||
assert_failed_inner(kind, &left, &right, args)
|
||||
}
|
||||
|
||||
match args {
|
||||
Some(args) => panic!(
|
||||
r#"assertion failed: `(left {} right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}: {}`"#,
|
||||
op, left, right, args
|
||||
),
|
||||
None => panic!(
|
||||
r#"assertion failed: `(left {} right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}`"#,
|
||||
op, left, right,
|
||||
),
|
||||
/// Internal function for `assert_match!`
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
|
||||
left: &T,
|
||||
right: &str,
|
||||
args: Option<fmt::Arguments<'_>>,
|
||||
) -> ! {
|
||||
// Use the Display implementation to display the pattern.
|
||||
struct Pattern<'a>(&'a str);
|
||||
impl fmt::Debug for Pattern<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self.0, f)
|
||||
}
|
||||
}
|
||||
inner(kind, &left, &right, args)
|
||||
assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
|
||||
}
|
||||
|
||||
/// Non-generic version of the above functions, to avoid code bloat.
|
||||
#[track_caller]
|
||||
fn assert_failed_inner(
|
||||
kind: AssertKind,
|
||||
left: &dyn fmt::Debug,
|
||||
right: &dyn fmt::Debug,
|
||||
args: Option<fmt::Arguments<'_>>,
|
||||
) -> ! {
|
||||
let op = match kind {
|
||||
AssertKind::Eq => "==",
|
||||
AssertKind::Ne => "!=",
|
||||
AssertKind::Match => "matches",
|
||||
};
|
||||
|
||||
match args {
|
||||
Some(args) => panic!(
|
||||
r#"assertion failed: `(left {} right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}: {}`"#,
|
||||
op, left, right, args
|
||||
),
|
||||
None => panic!(
|
||||
r#"assertion failed: `(left {} right)`
|
||||
left: `{:?}`,
|
||||
right: `{:?}`"#,
|
||||
op, left, right,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ fn test_intersperse() {
|
|||
assert_eq!(v, vec![1]);
|
||||
|
||||
let xs = ["a", "", "b", "c"];
|
||||
let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
|
||||
let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect();
|
||||
let text: String = v.concat();
|
||||
assert_eq!(text, "a, , b, c".to_string());
|
||||
|
||||
|
@ -24,7 +24,7 @@ fn test_intersperse_size_hint() {
|
|||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
|
||||
let xs = ["a", "", "b", "c"];
|
||||
let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
|
||||
let mut iter = xs.iter().map(|x| *x).intersperse(", ");
|
||||
assert_eq!(iter.size_hint(), (7, Some(7)));
|
||||
|
||||
assert_eq!(iter.next(), Some("a"));
|
||||
|
|
|
@ -245,3 +245,23 @@ fn test_double_ended_zip() {
|
|||
assert_eq!(it.next_back(), Some((3, 3)));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_82282() {
|
||||
fn overflowed_zip(arr: &[i32]) -> impl Iterator<Item = (i32, &())> {
|
||||
static UNIT_EMPTY_ARR: [(); 0] = [];
|
||||
|
||||
let mapped = arr.into_iter().map(|i| *i);
|
||||
let mut zipped = mapped.zip(UNIT_EMPTY_ARR.iter());
|
||||
zipped.next();
|
||||
zipped
|
||||
}
|
||||
|
||||
let arr = [1, 2, 3];
|
||||
let zip = overflowed_zip(&arr).zip(overflowed_zip(&arr));
|
||||
|
||||
assert_eq!(zip.size_hint(), (0, Some(0)));
|
||||
for _ in zip {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// ignore-tidy-filelength
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
@ -842,6 +844,37 @@ where
|
|||
self.base.insert(k, v)
|
||||
}
|
||||
|
||||
/// Tries to insert a key-value pair into the map, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
///
|
||||
/// If the map already had this key present, nothing is updated, and
|
||||
/// an error containing the occupied entry and the value is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_try_insert)]
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map = HashMap::new();
|
||||
/// assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
|
||||
///
|
||||
/// let err = map.try_insert(37, "b").unwrap_err();
|
||||
/// assert_eq!(err.entry.key(), &37);
|
||||
/// assert_eq!(err.entry.get(), &"a");
|
||||
/// assert_eq!(err.value, "b");
|
||||
/// ```
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> {
|
||||
match self.entry(key) {
|
||||
Occupied(entry) => Err(OccupiedError { entry, value }),
|
||||
Vacant(entry) => Ok(entry.insert(value)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes a key from the map, returning the value at the key if the key
|
||||
/// was previously in the map.
|
||||
///
|
||||
|
@ -1851,6 +1884,41 @@ impl<K: Debug, V> Debug for VacantEntry<'_, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists.
|
||||
///
|
||||
/// Contains the occupied entry, and the value that was not inserted.
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
pub struct OccupiedError<'a, K: 'a, V: 'a> {
|
||||
/// The entry in the map that was already occupied.
|
||||
pub entry: OccupiedEntry<'a, K, V>,
|
||||
/// The value which was not inserted, because the entry was already occupied.
|
||||
pub value: V,
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<K: Debug, V: Debug> Debug for OccupiedError<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OccupiedError")
|
||||
.field("key", self.entry.key())
|
||||
.field("old_value", self.entry.get())
|
||||
.field("new_value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"failed to insert {:?}, key {:?} already exists with value {:?}",
|
||||
self.value,
|
||||
self.entry.key(),
|
||||
self.entry.get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
|
|
@ -774,11 +774,11 @@ fn test_occupied_entry_key() {
|
|||
let key = "hello there";
|
||||
let value = "value goes here";
|
||||
assert!(a.is_empty());
|
||||
a.insert(key.clone(), value.clone());
|
||||
a.insert(key, value);
|
||||
assert_eq!(a.len(), 1);
|
||||
assert_eq!(a[key], value);
|
||||
|
||||
match a.entry(key.clone()) {
|
||||
match a.entry(key) {
|
||||
Vacant(_) => panic!(),
|
||||
Occupied(e) => assert_eq!(key, *e.key()),
|
||||
}
|
||||
|
@ -793,11 +793,11 @@ fn test_vacant_entry_key() {
|
|||
let value = "value goes here";
|
||||
|
||||
assert!(a.is_empty());
|
||||
match a.entry(key.clone()) {
|
||||
match a.entry(key) {
|
||||
Occupied(_) => panic!(),
|
||||
Vacant(e) => {
|
||||
assert_eq!(key, *e.key());
|
||||
e.insert(value.clone());
|
||||
e.insert(value);
|
||||
}
|
||||
}
|
||||
assert_eq!(a.len(), 1);
|
||||
|
|
|
@ -470,6 +470,24 @@ impl Error for char::DecodeUtf16Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<'a, K: Debug + Ord, V: Debug> Error
|
||||
for crate::collections::btree_map::OccupiedError<'a, K, V>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
"key already exists"
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_try_insert", issue = "82766")]
|
||||
impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> {
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
"key already exists"
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "box_error", since = "1.8.0")]
|
||||
impl<T: Error> Error for Box<T> {
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::cmp;
|
||||
use crate::fmt;
|
||||
use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
|
||||
use crate::io::{
|
||||
self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
|
||||
};
|
||||
|
||||
/// The `BufReader<R>` struct adds buffering to any reader.
|
||||
///
|
||||
|
@ -90,10 +92,9 @@ impl<R: Read> BufReader<R> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
|
||||
unsafe {
|
||||
let mut buffer = Vec::with_capacity(capacity);
|
||||
buffer.set_len(capacity);
|
||||
inner.initializer().initialize(&mut buffer);
|
||||
BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
|
||||
let mut buf = Box::new_uninit_slice(capacity).assume_init();
|
||||
inner.initializer().initialize(&mut buf);
|
||||
BufReader { inner, buf, pos: 0, cap: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,3 +436,9 @@ impl<R: Seek> Seek for BufReader<R> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SizeHint for BufReader<T> {
|
||||
fn lower_bound(&self) -> usize {
|
||||
self.buffer().len()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2238,6 +2238,19 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, U> SizeHint for Chain<T, U> {
|
||||
fn lower_bound(&self) -> usize {
|
||||
SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
|
||||
}
|
||||
|
||||
fn upper_bound(&self) -> Option<usize> {
|
||||
match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
|
||||
(Some(first), Some(second)) => Some(first + second),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reader adaptor which limits the bytes read from an underlying reader.
|
||||
///
|
||||
/// This struct is generally created by calling [`take`] on a reader.
|
||||
|
@ -2464,6 +2477,30 @@ impl<R: Read> Iterator for Bytes<R> {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
SizeHint::size_hint(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
trait SizeHint {
|
||||
fn lower_bound(&self) -> usize;
|
||||
|
||||
fn upper_bound(&self) -> Option<usize>;
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.lower_bound(), self.upper_bound())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SizeHint for T {
|
||||
default fn lower_bound(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
default fn upper_bound(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the contents of an instance of `BufRead` split on a
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{repeat, Cursor, SeekFrom};
|
||||
use crate::cmp::{self, min};
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::io::{BufRead, Read, Seek, Write};
|
||||
use crate::io::{BufRead, BufReader, Read, Seek, Write};
|
||||
use crate::ops::Deref;
|
||||
|
||||
#[test]
|
||||
|
@ -198,6 +198,53 @@ fn chain_bufread() {
|
|||
cmp_bufread(chain1, chain2, &testdata[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bufreader_size_hint() {
|
||||
let testdata = b"ABCDEFGHIJKL";
|
||||
let mut buf_reader = BufReader::new(&testdata[..]);
|
||||
assert_eq!(buf_reader.buffer().len(), 0);
|
||||
|
||||
let buffer_length = testdata.len();
|
||||
buf_reader.fill_buf().unwrap();
|
||||
|
||||
// Check that size hint matches buffer contents
|
||||
let mut buffered_bytes = buf_reader.bytes();
|
||||
let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
|
||||
assert_eq!(lower_bound, buffer_length);
|
||||
|
||||
// Check that size hint matches buffer contents after advancing
|
||||
buffered_bytes.next().unwrap().unwrap();
|
||||
let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
|
||||
assert_eq!(lower_bound, buffer_length - 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_size_hint() {
|
||||
let size_hint = io::empty().bytes().size_hint();
|
||||
assert_eq!(size_hint, (0, Some(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_empty_size_hint() {
|
||||
let chain = io::empty().chain(io::empty());
|
||||
let size_hint = chain.bytes().size_hint();
|
||||
assert_eq!(size_hint, (0, Some(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_size_hint() {
|
||||
let testdata = b"ABCDEFGHIJKL";
|
||||
let mut buf_reader_1 = BufReader::new(&testdata[..6]);
|
||||
let mut buf_reader_2 = BufReader::new(&testdata[6..]);
|
||||
|
||||
buf_reader_1.fill_buf().unwrap();
|
||||
buf_reader_2.fill_buf().unwrap();
|
||||
|
||||
let chain = buf_reader_1.chain(buf_reader_2);
|
||||
let size_hint = chain.bytes().size_hint();
|
||||
assert_eq!(size_hint, (testdata.len(), None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_zero_length_read_is_not_eof() {
|
||||
let a = b"A";
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
mod tests;
|
||||
|
||||
use crate::fmt;
|
||||
use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||
use crate::io::{
|
||||
self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
|
||||
};
|
||||
|
||||
/// A reader which is always at EOF.
|
||||
///
|
||||
|
@ -80,6 +82,12 @@ impl fmt::Debug for Empty {
|
|||
}
|
||||
}
|
||||
|
||||
impl SizeHint for Empty {
|
||||
fn upper_bound(&self) -> Option<usize> {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A reader which yields one byte over and over and over and over and over and...
|
||||
///
|
||||
/// This struct is generally created by calling [`repeat()`]. Please
|
||||
|
|
|
@ -228,6 +228,7 @@
|
|||
#![feature(arbitrary_self_types)]
|
||||
#![feature(array_error_internals)]
|
||||
#![feature(asm)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(atomic_mut_ptr)]
|
||||
#![feature(box_syntax)]
|
||||
|
@ -281,6 +282,7 @@
|
|||
#![feature(linkage)]
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(maybe_uninit_ref)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
|
@ -289,6 +291,7 @@
|
|||
#![feature(needs_panic_runtime)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(nll)]
|
||||
#![feature(nonnull_slice_from_raw_parts)]
|
||||
#![feature(once_cell)]
|
||||
|
@ -550,8 +553,8 @@ pub use std_detect::detect;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
pub use core::{
|
||||
assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo,
|
||||
unimplemented, unreachable, write, writeln,
|
||||
assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches,
|
||||
debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln,
|
||||
};
|
||||
|
||||
// Re-export built-in macros defined through libcore.
|
||||
|
|
|
@ -843,7 +843,6 @@ function defocusSearchBar() {
|
|||
function checkGenerics(obj, val) {
|
||||
// The names match, but we need to be sure that all generics kinda
|
||||
// match as well.
|
||||
var lev_distance = MAX_LEV_DISTANCE + 1;
|
||||
if (val.generics.length > 0) {
|
||||
if (obj.length > GENERICS_DATA &&
|
||||
obj[GENERICS_DATA].length >= val.generics.length) {
|
||||
|
@ -866,7 +865,6 @@ function defocusSearchBar() {
|
|||
}
|
||||
if (lev.pos !== -1) {
|
||||
elems.splice(lev.pos, 1);
|
||||
lev_distance = Math.min(lev.lev, lev_distance);
|
||||
total += lev.lev;
|
||||
done += 1;
|
||||
} else {
|
||||
|
@ -2054,24 +2052,6 @@ function defocusSearchBar() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HTML to plaintext:
|
||||
*
|
||||
* * Replace "<code>foo</code>" with "`foo`"
|
||||
* * Strip all other HTML tags
|
||||
*
|
||||
* Used by the dynamic sidebar crate list renderer.
|
||||
*
|
||||
* @param {[string]} html [The HTML to convert]
|
||||
* @return {[string]} [The resulting plaintext]
|
||||
*/
|
||||
function convertHTMLToPlaintext(html) {
|
||||
var x = document.createElement("div");
|
||||
x.innerHTML = html.replace('<code>', '`').replace('</code>', '`');
|
||||
return x.innerText;
|
||||
}
|
||||
|
||||
|
||||
// delayed sidebar rendering.
|
||||
window.initSidebarItems = function(items) {
|
||||
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
extern crate extern_links;
|
||||
pub extern crate extern_links;
|
||||
|
||||
// @!has foo/index.html '//a' 'extern_links'
|
||||
#[doc(no_inline)]
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
// aux-build:issue-28927-1.rs
|
||||
// ignore-cross-compile
|
||||
|
||||
extern crate issue_28927_1 as inner1;
|
||||
pub extern crate issue_28927_1 as inner1;
|
||||
pub use inner1 as foo;
|
||||
|
|
8
src/test/ui/issues/issue-81584.fixed
Normal file
8
src/test/ui/issues/issue-81584.fixed
Normal file
|
@ -0,0 +1,8 @@
|
|||
// run-rustfix
|
||||
fn main() {
|
||||
let _ = vec![vec![0, 1], vec![2]]
|
||||
.into_iter()
|
||||
.map(|y| y.iter().map(|x| x + 1).collect::<Vec<_>>())
|
||||
//~^ ERROR cannot return value referencing function parameter `y`
|
||||
.collect::<Vec<_>>();
|
||||
}
|
8
src/test/ui/issues/issue-81584.rs
Normal file
8
src/test/ui/issues/issue-81584.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
// run-rustfix
|
||||
fn main() {
|
||||
let _ = vec![vec![0, 1], vec![2]]
|
||||
.into_iter()
|
||||
.map(|y| y.iter().map(|x| x + 1))
|
||||
//~^ ERROR cannot return value referencing function parameter `y`
|
||||
.collect::<Vec<_>>();
|
||||
}
|
14
src/test/ui/issues/issue-81584.stderr
Normal file
14
src/test/ui/issues/issue-81584.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error[E0515]: cannot return value referencing function parameter `y`
|
||||
--> $DIR/issue-81584.rs:5:22
|
||||
|
|
||||
LL | .map(|y| y.iter().map(|x| x + 1))
|
||||
| -^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| returns a value referencing data owned by the current function
|
||||
| `y` is borrowed here
|
||||
|
|
||||
= help: use `.collect()` to allocate the iterator
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0515`.
|
54
src/test/ui/lint/noop-method-call.rs
Normal file
54
src/test/ui/lint/noop-method-call.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
// check-pass
|
||||
|
||||
#![allow(unused)]
|
||||
#![warn(noop_method_call)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::ops::Deref;
|
||||
|
||||
struct PlainType<T>(T);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CloneType<T>(T);
|
||||
|
||||
fn main() {
|
||||
let non_clone_type_ref = &PlainType(1u32);
|
||||
let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
|
||||
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
|
||||
|
||||
let clone_type_ref = &CloneType(1u32);
|
||||
let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();
|
||||
|
||||
// Calling clone on a double reference doesn't warn since the method call itself
|
||||
// peels the outer reference off
|
||||
let clone_type_ref = &&CloneType(1u32);
|
||||
let clone_type_ref_clone: &CloneType<u32> = clone_type_ref.clone();
|
||||
|
||||
let non_deref_type = &PlainType(1u32);
|
||||
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
|
||||
//~^ WARNING call to `.deref()` on a reference in this situation does nothing
|
||||
|
||||
// Dereferencing a &&T does not warn since it has collapsed the double reference
|
||||
let non_deref_type = &&PlainType(1u32);
|
||||
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
|
||||
|
||||
let non_borrow_type = &PlainType(1u32);
|
||||
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
|
||||
//~^ WARNING call to `.borrow()` on a reference in this situation does nothing
|
||||
|
||||
// Borrowing a &&T does not warn since it has collapsed the double reference
|
||||
let non_borrow_type = &&PlainType(1u32);
|
||||
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
|
||||
|
||||
let xs = ["a", "b", "c"];
|
||||
let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead
|
||||
}
|
||||
|
||||
fn generic<T>(non_clone_type: &PlainType<T>) {
|
||||
non_clone_type.clone();
|
||||
}
|
||||
|
||||
fn non_generic(non_clone_type: &PlainType<u32>) {
|
||||
non_clone_type.clone();
|
||||
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
|
||||
}
|
39
src/test/ui/lint/noop-method-call.stderr
Normal file
39
src/test/ui/lint/noop-method-call.stderr
Normal file
|
@ -0,0 +1,39 @@
|
|||
warning: call to `.clone()` on a reference in this situation does nothing
|
||||
--> $DIR/noop-method-call.rs:16:71
|
||||
|
|
||||
LL | let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
|
||||
| ^^^^^^^^ unnecessary method call
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/noop-method-call.rs:4:9
|
||||
|
|
||||
LL | #![warn(noop_method_call)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
|
||||
|
||||
warning: call to `.deref()` on a reference in this situation does nothing
|
||||
--> $DIR/noop-method-call.rs:28:63
|
||||
|
|
||||
LL | let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
|
||||
| ^^^^^^^^ unnecessary method call
|
||||
|
|
||||
= note: the type `&PlainType<u32>` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed
|
||||
|
||||
warning: call to `.borrow()` on a reference in this situation does nothing
|
||||
--> $DIR/noop-method-call.rs:36:66
|
||||
|
|
||||
LL | let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
|
||||
| ^^^^^^^^^ unnecessary method call
|
||||
|
|
||||
= note: the type `&PlainType<u32>` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed
|
||||
|
||||
warning: call to `.clone()` on a reference in this situation does nothing
|
||||
--> $DIR/noop-method-call.rs:52:19
|
||||
|
|
||||
LL | non_clone_type.clone();
|
||||
| ^^^^^^^^ unnecessary method call
|
||||
|
|
||||
= note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
|
||||
|
||||
warning: 4 warnings emitted
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
#![allow(unused)]
|
||||
|
||||
extern crate core;
|
||||
pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported
|
||||
//~^ WARN this was previously accepted
|
||||
|
@ -9,16 +7,14 @@ mod foo1 {
|
|||
}
|
||||
|
||||
mod foo2 {
|
||||
use foo1::core; //~ ERROR `core` is private, and cannot be re-exported
|
||||
//~^ WARN this was previously accepted
|
||||
use foo1::core; //~ ERROR crate import `core` is private
|
||||
pub mod bar {
|
||||
extern crate core;
|
||||
}
|
||||
}
|
||||
|
||||
mod baz {
|
||||
pub use foo2::bar::core; //~ ERROR `core` is private, and cannot be re-exported
|
||||
//~^ WARN this was previously accepted
|
||||
pub use foo2::bar::core; //~ ERROR crate import `core` is private
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,29 @@
|
|||
error[E0603]: crate import `core` is private
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:10:15
|
||||
|
|
||||
LL | use foo1::core;
|
||||
| ^^^^ private crate import
|
||||
|
|
||||
note: the crate import `core` is defined here
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:6:5
|
||||
|
|
||||
LL | extern crate core;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0603]: crate import `core` is private
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:17:24
|
||||
|
|
||||
LL | pub use foo2::bar::core;
|
||||
| ^^^^ private crate import
|
||||
|
|
||||
note: the crate import `core` is defined here
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:12:9
|
||||
|
|
||||
LL | extern crate core;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:4:9
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:2:9
|
||||
|
|
||||
LL | pub use core as reexported_core;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -8,23 +32,6 @@ LL | pub use core as reexported_core;
|
|||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
|
||||
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:12:9
|
||||
|
|
||||
LL | use foo1::core;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
|
||||
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
|
||||
--> $DIR/pub-reexport-priv-extern-crate.rs:20:13
|
||||
|
|
||||
LL | pub use foo2::bar::core;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0603`.
|
||||
|
|
|
@ -40,6 +40,8 @@ LL | | statefn: &id(state1 as StateMachineFunc)
|
|||
| | ------------------------------ temporary value created here
|
||||
LL | | }
|
||||
| |_____^ returns a value referencing data owned by the current function
|
||||
|
|
||||
= help: use `.collect()` to allocate the iterator
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -29,5 +29,6 @@ m!(y);
|
|||
|
||||
fn main() {
|
||||
use crate::y::*;
|
||||
#[allow(noop_method_call)]
|
||||
(&()).deref();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue