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!");
|
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 libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>();
|
||||||
let rpaths = get_rpaths(config, &libs);
|
let rpaths = get_rpaths(config, &libs);
|
||||||
let mut flags = rpaths_to_flags(&rpaths);
|
let mut flags = rpaths_to_flags(&rpaths);
|
||||||
|
|
|
@ -57,6 +57,7 @@ mod methods;
|
||||||
mod non_ascii_idents;
|
mod non_ascii_idents;
|
||||||
mod non_fmt_panic;
|
mod non_fmt_panic;
|
||||||
mod nonstandard_style;
|
mod nonstandard_style;
|
||||||
|
mod noop_method_call;
|
||||||
mod passes;
|
mod passes;
|
||||||
mod redundant_semicolon;
|
mod redundant_semicolon;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
@ -81,6 +82,7 @@ use methods::*;
|
||||||
use non_ascii_idents::*;
|
use non_ascii_idents::*;
|
||||||
use non_fmt_panic::NonPanicFmt;
|
use non_fmt_panic::NonPanicFmt;
|
||||||
use nonstandard_style::*;
|
use nonstandard_style::*;
|
||||||
|
use noop_method_call::*;
|
||||||
use redundant_semicolon::*;
|
use redundant_semicolon::*;
|
||||||
use traits::*;
|
use traits::*;
|
||||||
use types::*;
|
use types::*;
|
||||||
|
@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
|
||||||
DropTraitConstraints: DropTraitConstraints,
|
DropTraitConstraints: DropTraitConstraints,
|
||||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
||||||
NonPanicFmt: NonPanicFmt,
|
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::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
|
||||||
pub struct ExpectedFound<T> {
|
pub struct ExpectedFound<T> {
|
||||||
|
@ -548,7 +547,6 @@ impl<T> Trait<T> for X {
|
||||||
TargetFeatureCast(def_id) => {
|
TargetFeatureCast(def_id) => {
|
||||||
let attrs = self.get_attrs(*def_id);
|
let attrs = self.get_attrs(*def_id);
|
||||||
let target_spans = attrs
|
let target_spans = attrs
|
||||||
.deref()
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| attr.has_name(sym::target_feature))
|
.filter(|attr| attr.has_name(sym::target_feature))
|
||||||
.map(|attr| attr.span);
|
.map(|attr| attr.span);
|
||||||
|
|
|
@ -10,16 +10,18 @@ use rustc_middle::mir::{
|
||||||
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
|
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
|
||||||
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
|
use rustc_span::source_map::DesugaringKind;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::dataflow::drop_flag_effects;
|
use crate::dataflow::drop_flag_effects;
|
||||||
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
||||||
use crate::util::borrowck_errors;
|
use crate::util::borrowck_errors;
|
||||||
|
|
||||||
use crate::borrow_check::{
|
use crate::borrow_check::{
|
||||||
borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt,
|
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||||
PrefixSet, WriteKind,
|
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -1267,6 +1269,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
if return_span != borrow_span {
|
if return_span != borrow_span {
|
||||||
err.span_label(borrow_span, note);
|
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)
|
Some(err)
|
||||||
|
|
|
@ -165,7 +165,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
self.consume_operand(location, value);
|
self.consume_operand(location, value);
|
||||||
|
|
||||||
// Invalidate all borrows of local places
|
// 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());
|
let resume = self.location_table.start_index(resume.start_location());
|
||||||
for (i, data) in borrow_set.iter_enumerated() {
|
for (i, data) in borrow_set.iter_enumerated() {
|
||||||
if borrow_of_local_data(data.borrowed_place) {
|
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 => {
|
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
||||||
// Invalidate all borrows of local places
|
// 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);
|
let start = self.location_table.start_index(location);
|
||||||
for (i, data) in borrow_set.iter_enumerated() {
|
for (i, data) in borrow_set.iter_enumerated() {
|
||||||
if borrow_of_local_data(data.borrowed_place) {
|
if borrow_of_local_data(data.borrowed_place) {
|
||||||
|
@ -369,7 +369,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
);
|
);
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let body = self.body;
|
let body = self.body;
|
||||||
let borrow_set = self.borrow_set.clone();
|
let borrow_set = self.borrow_set;
|
||||||
let indices = self.borrow_set.indices();
|
let indices = self.borrow_set.indices();
|
||||||
each_borrow_involving_path(
|
each_borrow_involving_path(
|
||||||
self,
|
self,
|
||||||
|
@ -377,7 +377,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
body,
|
body,
|
||||||
location,
|
location,
|
||||||
(sd, place),
|
(sd, place),
|
||||||
&borrow_set.clone(),
|
borrow_set,
|
||||||
indices,
|
indices,
|
||||||
|this, borrow_index, borrow| {
|
|this, borrow_index, borrow| {
|
||||||
match (rw, borrow.kind) {
|
match (rw, borrow.kind) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
|
|
||||||
PatKind::Constant { value } => Test {
|
PatKind::Constant { value } => Test {
|
||||||
span: match_pair.pattern.span,
|
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) => {
|
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> {
|
impl<'a> Resolver<'a> {
|
||||||
crate fn resolve_ident_in_module_unadjusted(
|
crate fn resolve_ident_in_module_unadjusted(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -263,10 +278,7 @@ impl<'a> Resolver<'a> {
|
||||||
return Err((Determined, Weak::No));
|
return Err((Determined, Weak::No));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `extern crate` are always usable for backwards compatibility, see issue #37020,
|
let usable = this.is_accessible_from(binding.vis, parent_scope.module);
|
||||||
// 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();
|
|
||||||
if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
|
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) ||
|
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()))
|
|
||||||
{
|
|
||||||
self.privacy_errors.push(PrivacyError {
|
self.privacy_errors.push(PrivacyError {
|
||||||
ident,
|
ident,
|
||||||
binding,
|
binding,
|
||||||
|
@ -455,9 +464,8 @@ impl<'a> Resolver<'a> {
|
||||||
binding: &'a NameBinding<'a>,
|
binding: &'a NameBinding<'a>,
|
||||||
import: &'a Import<'a>,
|
import: &'a Import<'a>,
|
||||||
) -> &'a NameBinding<'a> {
|
) -> &'a NameBinding<'a> {
|
||||||
let vis = if binding.vis.is_at_least(import.vis.get(), self) ||
|
let vis = if binding.vis.is_at_least(import.vis.get(), self)
|
||||||
// cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
|| pub_use_of_private_extern_crate_hack(import, binding)
|
||||||
!import.is_glob() && binding.is_extern_crate()
|
|
||||||
{
|
{
|
||||||
import.vis.get()
|
import.vis.get()
|
||||||
} else {
|
} 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.
|
// All namespaces must be re-exported with extra visibility for an error to occur.
|
||||||
if !any_successful_reexport {
|
if !any_successful_reexport {
|
||||||
let (ns, binding) = reexport_error.unwrap();
|
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!(
|
let msg = format!(
|
||||||
"extern crate `{}` is private, and cannot be \
|
"extern crate `{}` is private, and cannot be \
|
||||||
re-exported (error E0365), consider declaring with \
|
re-exported (error E0365), consider declaring with \
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
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! {
|
symbols! {
|
||||||
// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
|
// 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.
|
// this should be rarely necessary though if the keywords are kept in alphabetic order.
|
||||||
|
@ -129,6 +129,7 @@ symbols! {
|
||||||
BTreeMap,
|
BTreeMap,
|
||||||
BTreeSet,
|
BTreeSet,
|
||||||
BinaryHeap,
|
BinaryHeap,
|
||||||
|
Borrow,
|
||||||
C,
|
C,
|
||||||
CString,
|
CString,
|
||||||
Center,
|
Center,
|
||||||
|
@ -141,6 +142,7 @@ symbols! {
|
||||||
Decodable,
|
Decodable,
|
||||||
Decoder,
|
Decoder,
|
||||||
Default,
|
Default,
|
||||||
|
Deref,
|
||||||
Encodable,
|
Encodable,
|
||||||
Encoder,
|
Encoder,
|
||||||
Eq,
|
Eq,
|
||||||
|
@ -789,6 +791,9 @@ symbols! {
|
||||||
none_error,
|
none_error,
|
||||||
nontemporal_store,
|
nontemporal_store,
|
||||||
nontrapping_dash_fptoint: "nontrapping-fptoint",
|
nontrapping_dash_fptoint: "nontrapping-fptoint",
|
||||||
|
noop_method_borrow,
|
||||||
|
noop_method_clone,
|
||||||
|
noop_method_deref,
|
||||||
noreturn,
|
noreturn,
|
||||||
nostack,
|
nostack,
|
||||||
not,
|
not,
|
||||||
|
|
|
@ -819,7 +819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
sig.decl
|
sig.decl
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| match arg.clone().kind {
|
.map(|arg| match arg.kind {
|
||||||
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
||||||
Some(arg.span),
|
Some(arg.span),
|
||||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||||
|
|
|
@ -165,7 +165,7 @@ crate fn evaluate_goal<'tcx>(
|
||||||
// let's just ignore that
|
// let's just ignore that
|
||||||
let sol = Canonical {
|
let sol = Canonical {
|
||||||
max_universe: ty::UniverseIndex::from_usize(0),
|
max_universe: ty::UniverseIndex::from_usize(0),
|
||||||
variables: obligation.variables.clone(),
|
variables: obligation.variables,
|
||||||
value: QueryResponse {
|
value: QueryResponse {
|
||||||
var_values: CanonicalVarValues { var_values: IndexVec::new() }
|
var_values: CanonicalVarValues { var_values: IndexVec::new() }
|
||||||
.make_identity(tcx),
|
.make_identity(tcx),
|
||||||
|
|
|
@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||||
call_expr.span,
|
call_expr.span,
|
||||||
expected,
|
expected,
|
||||||
fn_sig.output().clone(),
|
fn_sig.output(),
|
||||||
fn_sig.inputs(),
|
fn_sig.inputs(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -711,7 +711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
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(
|
ret_coercion.borrow_mut().coerce(
|
||||||
self,
|
self,
|
||||||
&self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
|
&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::*;
|
use super::search::SearchResult::*;
|
||||||
|
|
||||||
mod entry;
|
mod entry;
|
||||||
pub use entry::{Entry, OccupiedEntry, VacantEntry};
|
pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
|
||||||
use Entry::*;
|
use Entry::*;
|
||||||
|
|
||||||
/// Minimum number of elements in nodes that are not a root.
|
/// 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
|
/// Removes a key from the map, returning the value at the key if the key
|
||||||
/// was previously in the map.
|
/// 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> {
|
impl<'a, K: Ord, V> Entry<'a, K, V> {
|
||||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||||
/// a mutable reference to the value in the entry.
|
/// a mutable reference to the value in the entry.
|
||||||
|
|
|
@ -1801,11 +1801,11 @@ fn test_occupied_entry_key() {
|
||||||
let key = "hello there";
|
let key = "hello there";
|
||||||
let value = "value goes here";
|
let value = "value goes here";
|
||||||
assert!(a.is_empty());
|
assert!(a.is_empty());
|
||||||
a.insert(key.clone(), value.clone());
|
a.insert(key, value);
|
||||||
assert_eq!(a.len(), 1);
|
assert_eq!(a.len(), 1);
|
||||||
assert_eq!(a[key], value);
|
assert_eq!(a[key], value);
|
||||||
|
|
||||||
match a.entry(key.clone()) {
|
match a.entry(key) {
|
||||||
Vacant(_) => panic!(),
|
Vacant(_) => panic!(),
|
||||||
Occupied(e) => assert_eq!(key, *e.key()),
|
Occupied(e) => assert_eq!(key, *e.key()),
|
||||||
}
|
}
|
||||||
|
@ -1821,11 +1821,11 @@ fn test_vacant_entry_key() {
|
||||||
let value = "value goes here";
|
let value = "value goes here";
|
||||||
|
|
||||||
assert!(a.is_empty());
|
assert!(a.is_empty());
|
||||||
match a.entry(key.clone()) {
|
match a.entry(key) {
|
||||||
Occupied(_) => panic!(),
|
Occupied(_) => panic!(),
|
||||||
Vacant(e) => {
|
Vacant(e) => {
|
||||||
assert_eq!(key, *e.key());
|
assert_eq!(key, *e.key());
|
||||||
e.insert(value.clone());
|
e.insert(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(a.len(), 1);
|
assert_eq!(a.len(), 1);
|
||||||
|
|
|
@ -153,6 +153,7 @@
|
||||||
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
|
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
|
||||||
/// [`String`]: ../../std/string/struct.String.html
|
/// [`String`]: ../../std/string/struct.String.html
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_diagnostic_item = "Borrow"]
|
||||||
pub trait Borrow<Borrowed: ?Sized> {
|
pub trait Borrow<Borrowed: ?Sized> {
|
||||||
/// Immutably borrows from an owned value.
|
/// Immutably borrows from an owned value.
|
||||||
///
|
///
|
||||||
|
@ -205,6 +206,7 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> Borrow<T> for T {
|
impl<T: ?Sized> Borrow<T> for T {
|
||||||
|
#[rustc_diagnostic_item = "noop_method_borrow"]
|
||||||
fn borrow(&self) -> &T {
|
fn borrow(&self) -> &T {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,12 +104,14 @@
|
||||||
/// [impls]: #implementors
|
/// [impls]: #implementors
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[lang = "clone"]
|
#[lang = "clone"]
|
||||||
|
#[rustc_diagnostic_item = "Clone"]
|
||||||
pub trait Clone: Sized {
|
pub trait Clone: Sized {
|
||||||
/// Returns a copy of the value.
|
/// Returns a copy of the value.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #![allow(noop_method_call)]
|
||||||
/// let hello = "Hello"; // &str implements Clone
|
/// let hello = "Hello"; // &str implements Clone
|
||||||
///
|
///
|
||||||
/// assert_eq!("Hello", hello.clone());
|
/// assert_eq!("Hello", hello.clone());
|
||||||
|
@ -221,6 +223,7 @@ mod impls {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: ?Sized> Clone for &T {
|
impl<T: ?Sized> Clone for &T {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[rustc_diagnostic_item = "noop_method_clone"]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
/// bar: f32,
|
/// bar: f32,
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub trait Default: Sized {
|
pub trait Default: Sized {
|
||||||
/// Returns the "default value" for a type.
|
/// Returns the "default value" for a type.
|
||||||
|
|
|
@ -200,6 +200,7 @@ where
|
||||||
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a.size() {
|
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a.size() {
|
||||||
let i = self.index;
|
let i = self.index;
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
|
self.len += 1;
|
||||||
// match the base implementation's potential side effects
|
// match the base implementation's potential side effects
|
||||||
// SAFETY: we just checked that `i` < `self.a.len()`
|
// SAFETY: we just checked that `i` < `self.a.len()`
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -258,7 +259,7 @@ where
|
||||||
if sz_a != sz_b {
|
if sz_a != sz_b {
|
||||||
let sz_a = self.a.size();
|
let sz_a = self.a.size();
|
||||||
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
|
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();
|
self.a.next_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
|
||||||
message = "`{Self}` is not an iterator"
|
message = "`{Self}` is not an iterator"
|
||||||
)]
|
)]
|
||||||
#[doc(spotlight)]
|
#[doc(spotlight)]
|
||||||
|
#[rustc_diagnostic_item = "Iterator"]
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
pub trait Iterator {
|
pub trait Iterator {
|
||||||
/// The type of the elements being iterated over.
|
/// 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.
|
/// Asserts that a boolean expression is `true` at runtime.
|
||||||
///
|
///
|
||||||
/// This will invoke the [`panic!`] macro if the provided expression cannot be
|
/// 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)*); })
|
($($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.
|
/// Returns whether the given expression matches any of the given patterns.
|
||||||
///
|
///
|
||||||
/// Like in a `match` expression, the pattern can be optionally followed by `if`
|
/// Like in a `match` expression, the pattern can be optionally followed by `if`
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
#[doc(alias = "*")]
|
#[doc(alias = "*")]
|
||||||
#[doc(alias = "&*")]
|
#[doc(alias = "&*")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_diagnostic_item = "Deref"]
|
||||||
pub trait Deref {
|
pub trait Deref {
|
||||||
/// The resulting type after dereferencing.
|
/// The resulting type after dereferencing.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -78,6 +79,7 @@ pub trait Deref {
|
||||||
impl<T: ?Sized> Deref for &T {
|
impl<T: ?Sized> Deref for &T {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
|
#[rustc_diagnostic_item = "noop_method_deref"]
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,7 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
||||||
pub enum AssertKind {
|
pub enum AssertKind {
|
||||||
Eq,
|
Eq,
|
||||||
Ne,
|
Ne,
|
||||||
|
Match,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal function for `assert_eq!` and `assert_ne!` macros
|
/// Internal function for `assert_eq!` and `assert_ne!` macros
|
||||||
|
@ -113,32 +114,54 @@ where
|
||||||
T: fmt::Debug + ?Sized,
|
T: fmt::Debug + ?Sized,
|
||||||
U: fmt::Debug + ?Sized,
|
U: fmt::Debug + ?Sized,
|
||||||
{
|
{
|
||||||
#[track_caller]
|
assert_failed_inner(kind, &left, &right, args)
|
||||||
fn inner(
|
}
|
||||||
kind: AssertKind,
|
|
||||||
left: &dyn fmt::Debug,
|
|
||||||
right: &dyn fmt::Debug,
|
|
||||||
args: Option<fmt::Arguments<'_>>,
|
|
||||||
) -> ! {
|
|
||||||
let op = match kind {
|
|
||||||
AssertKind::Eq => "==",
|
|
||||||
AssertKind::Ne => "!=",
|
|
||||||
};
|
|
||||||
|
|
||||||
match args {
|
/// Internal function for `assert_match!`
|
||||||
Some(args) => panic!(
|
#[cold]
|
||||||
r#"assertion failed: `(left {} right)`
|
#[track_caller]
|
||||||
left: `{:?}`,
|
#[doc(hidden)]
|
||||||
right: `{:?}: {}`"#,
|
pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
|
||||||
op, left, right, args
|
left: &T,
|
||||||
),
|
right: &str,
|
||||||
None => panic!(
|
args: Option<fmt::Arguments<'_>>,
|
||||||
r#"assertion failed: `(left {} right)`
|
) -> ! {
|
||||||
left: `{:?}`,
|
// Use the Display implementation to display the pattern.
|
||||||
right: `{:?}`"#,
|
struct Pattern<'a>(&'a str);
|
||||||
op, left, right,
|
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]);
|
assert_eq!(v, vec![1]);
|
||||||
|
|
||||||
let xs = ["a", "", "b", "c"];
|
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();
|
let text: String = v.concat();
|
||||||
assert_eq!(text, "a, , b, c".to_string());
|
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)));
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||||
|
|
||||||
let xs = ["a", "", "b", "c"];
|
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.size_hint(), (7, Some(7)));
|
||||||
|
|
||||||
assert_eq!(iter.next(), Some("a"));
|
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_back(), Some((3, 3)));
|
||||||
assert_eq!(it.next(), None);
|
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)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
@ -842,6 +844,37 @@ where
|
||||||
self.base.insert(k, v)
|
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
|
/// Removes a key from the map, returning the value at the key if the key
|
||||||
/// was previously in the map.
|
/// 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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
|
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
|
||||||
type Item = (&'a K, &'a V);
|
type Item = (&'a K, &'a V);
|
||||||
|
|
|
@ -774,11 +774,11 @@ fn test_occupied_entry_key() {
|
||||||
let key = "hello there";
|
let key = "hello there";
|
||||||
let value = "value goes here";
|
let value = "value goes here";
|
||||||
assert!(a.is_empty());
|
assert!(a.is_empty());
|
||||||
a.insert(key.clone(), value.clone());
|
a.insert(key, value);
|
||||||
assert_eq!(a.len(), 1);
|
assert_eq!(a.len(), 1);
|
||||||
assert_eq!(a[key], value);
|
assert_eq!(a[key], value);
|
||||||
|
|
||||||
match a.entry(key.clone()) {
|
match a.entry(key) {
|
||||||
Vacant(_) => panic!(),
|
Vacant(_) => panic!(),
|
||||||
Occupied(e) => assert_eq!(key, *e.key()),
|
Occupied(e) => assert_eq!(key, *e.key()),
|
||||||
}
|
}
|
||||||
|
@ -793,11 +793,11 @@ fn test_vacant_entry_key() {
|
||||||
let value = "value goes here";
|
let value = "value goes here";
|
||||||
|
|
||||||
assert!(a.is_empty());
|
assert!(a.is_empty());
|
||||||
match a.entry(key.clone()) {
|
match a.entry(key) {
|
||||||
Occupied(_) => panic!(),
|
Occupied(_) => panic!(),
|
||||||
Vacant(e) => {
|
Vacant(e) => {
|
||||||
assert_eq!(key, *e.key());
|
assert_eq!(key, *e.key());
|
||||||
e.insert(value.clone());
|
e.insert(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(a.len(), 1);
|
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")]
|
#[stable(feature = "box_error", since = "1.8.0")]
|
||||||
impl<T: Error> Error for Box<T> {
|
impl<T: Error> Error for Box<T> {
|
||||||
#[allow(deprecated, deprecated_in_future)]
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::cmp;
|
use crate::cmp;
|
||||||
use crate::fmt;
|
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.
|
/// 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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
|
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut buffer = Vec::with_capacity(capacity);
|
let mut buf = Box::new_uninit_slice(capacity).assume_init();
|
||||||
buffer.set_len(capacity);
|
inner.initializer().initialize(&mut buf);
|
||||||
inner.initializer().initialize(&mut buffer);
|
BufReader { inner, buf, pos: 0, cap: 0 }
|
||||||
BufReader { inner, buf: buffer.into_boxed_slice(), 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.
|
/// Reader adaptor which limits the bytes read from an underlying reader.
|
||||||
///
|
///
|
||||||
/// This struct is generally created by calling [`take`] on a 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
|
/// An iterator over the contents of an instance of `BufRead` split on a
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::{repeat, Cursor, SeekFrom};
|
use super::{repeat, Cursor, SeekFrom};
|
||||||
use crate::cmp::{self, min};
|
use crate::cmp::{self, min};
|
||||||
use crate::io::{self, IoSlice, IoSliceMut};
|
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;
|
use crate::ops::Deref;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -198,6 +198,53 @@ fn chain_bufread() {
|
||||||
cmp_bufread(chain1, chain2, &testdata[..]);
|
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]
|
#[test]
|
||||||
fn chain_zero_length_read_is_not_eof() {
|
fn chain_zero_length_read_is_not_eof() {
|
||||||
let a = b"A";
|
let a = b"A";
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::fmt;
|
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.
|
/// 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...
|
/// 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
|
/// This struct is generally created by calling [`repeat()`]. Please
|
||||||
|
|
|
@ -228,6 +228,7 @@
|
||||||
#![feature(arbitrary_self_types)]
|
#![feature(arbitrary_self_types)]
|
||||||
#![feature(array_error_internals)]
|
#![feature(array_error_internals)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(atomic_mut_ptr)]
|
#![feature(atomic_mut_ptr)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
@ -281,6 +282,7 @@
|
||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
#![feature(llvm_asm)]
|
#![feature(llvm_asm)]
|
||||||
#![feature(log_syntax)]
|
#![feature(log_syntax)]
|
||||||
|
#![feature(map_try_insert)]
|
||||||
#![feature(maybe_uninit_extra)]
|
#![feature(maybe_uninit_extra)]
|
||||||
#![feature(maybe_uninit_ref)]
|
#![feature(maybe_uninit_ref)]
|
||||||
#![feature(maybe_uninit_slice)]
|
#![feature(maybe_uninit_slice)]
|
||||||
|
@ -289,6 +291,7 @@
|
||||||
#![feature(needs_panic_runtime)]
|
#![feature(needs_panic_runtime)]
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
#![feature(new_uninit)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(nonnull_slice_from_raw_parts)]
|
#![feature(nonnull_slice_from_raw_parts)]
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
|
@ -550,8 +553,8 @@ pub use std_detect::detect;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow(deprecated, deprecated_in_future)]
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
pub use core::{
|
pub use core::{
|
||||||
assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo,
|
assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches,
|
||||||
unimplemented, unreachable, write, writeln,
|
debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Re-export built-in macros defined through libcore.
|
// Re-export built-in macros defined through libcore.
|
||||||
|
|
|
@ -843,7 +843,6 @@ function defocusSearchBar() {
|
||||||
function checkGenerics(obj, val) {
|
function checkGenerics(obj, val) {
|
||||||
// The names match, but we need to be sure that all generics kinda
|
// The names match, but we need to be sure that all generics kinda
|
||||||
// match as well.
|
// match as well.
|
||||||
var lev_distance = MAX_LEV_DISTANCE + 1;
|
|
||||||
if (val.generics.length > 0) {
|
if (val.generics.length > 0) {
|
||||||
if (obj.length > GENERICS_DATA &&
|
if (obj.length > GENERICS_DATA &&
|
||||||
obj[GENERICS_DATA].length >= val.generics.length) {
|
obj[GENERICS_DATA].length >= val.generics.length) {
|
||||||
|
@ -866,7 +865,6 @@ function defocusSearchBar() {
|
||||||
}
|
}
|
||||||
if (lev.pos !== -1) {
|
if (lev.pos !== -1) {
|
||||||
elems.splice(lev.pos, 1);
|
elems.splice(lev.pos, 1);
|
||||||
lev_distance = Math.min(lev.lev, lev_distance);
|
|
||||||
total += lev.lev;
|
total += lev.lev;
|
||||||
done += 1;
|
done += 1;
|
||||||
} else {
|
} 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.
|
// delayed sidebar rendering.
|
||||||
window.initSidebarItems = function(items) {
|
window.initSidebarItems = function(items) {
|
||||||
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
|
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#![crate_name = "foo"]
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
extern crate extern_links;
|
pub extern crate extern_links;
|
||||||
|
|
||||||
// @!has foo/index.html '//a' 'extern_links'
|
// @!has foo/index.html '//a' 'extern_links'
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
// aux-build:issue-28927-1.rs
|
// aux-build:issue-28927-1.rs
|
||||||
// ignore-cross-compile
|
// ignore-cross-compile
|
||||||
|
|
||||||
extern crate issue_28927_1 as inner1;
|
pub extern crate issue_28927_1 as inner1;
|
||||||
pub use inner1 as foo;
|
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;
|
extern crate core;
|
||||||
pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported
|
pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported
|
||||||
//~^ WARN this was previously accepted
|
//~^ WARN this was previously accepted
|
||||||
|
@ -9,16 +7,14 @@ mod foo1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod foo2 {
|
mod foo2 {
|
||||||
use foo1::core; //~ ERROR `core` is private, and cannot be re-exported
|
use foo1::core; //~ ERROR crate import `core` is private
|
||||||
//~^ WARN this was previously accepted
|
|
||||||
pub mod bar {
|
pub mod bar {
|
||||||
extern crate core;
|
extern crate core;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod baz {
|
mod baz {
|
||||||
pub use foo2::bar::core; //~ ERROR `core` is private, and cannot be re-exported
|
pub use foo2::bar::core; //~ ERROR crate import `core` is private
|
||||||
//~^ WARN this was previously accepted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
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`
|
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;
|
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!
|
= 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>
|
= 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
|
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
|
| | ------------------------------ temporary value created here
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^ returns a value referencing data owned by the current function
|
| |_____^ returns a value referencing data owned by the current function
|
||||||
|
|
|
||||||
|
= help: use `.collect()` to allocate the iterator
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -29,5 +29,6 @@ m!(y);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
use crate::y::*;
|
use crate::y::*;
|
||||||
|
#[allow(noop_method_call)]
|
||||||
(&()).deref();
|
(&()).deref();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue