From 3ae974f025d4376c720e3b2773ccd2c201f098dc Mon Sep 17 00:00:00 2001 From: YI Date: Tue, 25 Feb 2020 18:15:23 +0800 Subject: [PATCH 01/12] fix misleading type annotation diagonstics This solves the method call part of issue https://github.com/rust-lang/rust/issues/69455 I added a `target_span` field so as to pin down the exact location of the error. We need a dedicated field `found_exact_method_call` to prioritize situations like the test case `issue-69455.rs`. If we reuse `found_method_call`, `found_local_pattern` will show up first. We can not move `found_method_call` up, it is undesirable in various situations. --- .../infer/error_reporting/need_type_info.rs | 58 +++++++++++++++++-- src/test/ui/issues/issue-69455.rs | 30 ++++++++++ src/test/ui/issues/issue-69455.stderr | 17 ++++++ 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/issues/issue-69455.rs create mode 100644 src/test/ui/issues/issue-69455.stderr diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index bb6e5700ccad4..53f52038ed022 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -17,23 +17,27 @@ use std::borrow::Cow; struct FindHirNodeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, + target_span: Span, found_node_ty: Option>, found_local_pattern: Option<&'tcx Pat<'tcx>>, found_arg_pattern: Option<&'tcx Pat<'tcx>>, found_closure: Option<&'tcx Expr<'tcx>>, found_method_call: Option<&'tcx Expr<'tcx>>, + found_exact_method_call: Option<&'tcx Expr<'tcx>>, } impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self { Self { infcx, target, + target_span, found_node_ty: None, found_local_pattern: None, found_arg_pattern: None, found_closure: None, found_method_call: None, + found_exact_method_call: None, } } @@ -103,6 +107,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind { + if call_span == self.target_span + && Some(self.target) + == self.infcx.in_progress_tables.and_then(|tables| { + tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into) + }) + { + self.found_exact_method_call = Some(&expr); + return; + } + } if self.node_ty_contains_target(expr.hir_id).is_some() { match expr.kind { ExprKind::Closure(..) => self.found_closure = Some(&expr), @@ -234,7 +249,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into()); + let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -287,14 +302,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) }; - let ty_msg = match local_visitor.found_node_ty { - Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { + let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { + (_, Some(_)) => String::new(), + (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => { let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); let ret = fn_sig.output().skip_binder().to_string(); format!(" for the closure `fn({}) -> {}`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) => { + (Some(ty), _) if is_named_and_not_impl_trait(ty) => { let ty = ty_to_string(ty); format!(" for `{}`", ty) } @@ -370,7 +386,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => "a type".to_string(), }; - if let Some(pattern) = local_visitor.found_arg_pattern { + if let Some(e) = local_visitor.found_exact_method_call { + if let ExprKind::MethodCall(segment, ..) = &e.kind { + // Suggest specifying type params or point out the return type of the call: + // + // error[E0282]: type annotations needed + // --> $DIR/type-annotations-needed-expr.rs:2:39 + // | + // LL | let _ = x.into_iter().sum() as f64; + // | ^^^ + // | | + // | cannot infer type for `S` + // | help: consider specifying the type argument in + // | the method call: `sum::` + // | + // = note: type must be known at this point + // + // or + // + // error[E0282]: type annotations needed + // --> $DIR/issue-65611.rs:59:20 + // | + // LL | let x = buffer.last().unwrap().0.clone(); + // | -------^^^^-- + // | | | + // | | cannot infer type for `T` + // | this method call resolves to `std::option::Option<&T>` + // | + // = note: type must be known at this point + self.annotate_method_call(segment, e, &mut err); + } + } else if let Some(pattern) = local_visitor.found_arg_pattern { // We don't want to show the default label for closures. // // So, before clearing, the output would look something like this: diff --git a/src/test/ui/issues/issue-69455.rs b/src/test/ui/issues/issue-69455.rs new file mode 100644 index 0000000000000..017654554be16 --- /dev/null +++ b/src/test/ui/issues/issue-69455.rs @@ -0,0 +1,30 @@ +// Regression test for #69455: projection predicate was not satisfied. +// Compiler should indicate the correct location of the +// unsatisfied projection predicate + +pub trait Test { + type Output; + + fn test(self, rhs: Rhs) -> Self::Output; +} + +impl Test for u64 { + type Output = u64; + + fn test(self, other: u32) -> u64 { + self + (other as u64) + } +} + +impl Test for u64 { + type Output = u64; + + fn test(self, other: u64) -> u64 { + (self + other) as u64 + } +} + +fn main() { + let xs: Vec = vec![1, 2, 3]; + println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284] +} diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr new file mode 100644 index 0000000000000..4caa1aca9fd21 --- /dev/null +++ b/src/test/ui/issues/issue-69455.stderr @@ -0,0 +1,17 @@ +error[E0284]: type annotations needed + --> $DIR/issue-69455.rs:29:26 + | +LL | type Output; + | ------------ `>::Output` defined here +... +LL | println!("{}", 23u64.test(xs.iter().sum())); + | ------^^^^----------------- + | | | + | | cannot infer type for type `u64` + | this method call resolves to `>::Output` + | + = note: cannot satisfy `>::Output == _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. From a75c79288879fe9b87284ac897428c046d174ade Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 19 Apr 2020 10:23:05 -0700 Subject: [PATCH 02/12] Make type alias private --- src/librustc_mir/transform/check_consts/validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 45d8e1d08b721..7b76590b7c028 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -28,7 +28,7 @@ use crate::dataflow::{self, Analysis}; // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated // through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` // kills locals upon `StorageDead` because a local will never be used after a `StorageDead`. -pub type IndirectlyMutableResults<'mir, 'tcx> = +type IndirectlyMutableResults<'mir, 'tcx> = dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>; struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> { From 274c85f5c80f6a8ae800bf9054e49bb111824278 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 19 Apr 2020 10:23:57 -0700 Subject: [PATCH 03/12] Don't cache result of `in_any_value_of_ty` for locals This was needed by an early version of dataflow-based const qualification where `QualifCursor` needed to return a full `BitSet` with the current state. --- .../transform/check_consts/validation.rs | 104 +++++++++--------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 7b76590b7c028..5b37edd01b37c 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -3,7 +3,6 @@ use rustc_errors::struct_span_err; use rustc_hir::lang_items; use rustc_hir::{def_id::DefId, HirId}; -use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -31,37 +30,22 @@ use crate::dataflow::{self, Analysis}; type IndirectlyMutableResults<'mir, 'tcx> = dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>; -struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> { - cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>, - in_any_value_of_ty: BitSet, -} - -impl QualifCursor<'a, 'mir, 'tcx, Q> { - pub fn new(q: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self { - let cursor = FlowSensitiveAnalysis::new(q, ccx) - .into_engine(ccx.tcx, ccx.body, ccx.def_id) - .iterate_to_fixpoint() - .into_results_cursor(ccx.body); - - let mut in_any_value_of_ty = BitSet::new_empty(ccx.body.local_decls.len()); - for (local, decl) in ccx.body.local_decls.iter_enumerated() { - if Q::in_any_value_of_ty(ccx, decl.ty) { - in_any_value_of_ty.insert(local); - } - } - - QualifCursor { cursor, in_any_value_of_ty } - } -} +type QualifResults<'mir, 'tcx, Q> = + dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; -pub struct Qualifs<'a, 'mir, 'tcx> { - has_mut_interior: QualifCursor<'a, 'mir, 'tcx, HasMutInterior>, - needs_drop: QualifCursor<'a, 'mir, 'tcx, NeedsDrop>, +pub struct Qualifs<'mir, 'tcx> { + has_mut_interior: QualifResults<'mir, 'tcx, HasMutInterior>, + needs_drop: QualifResults<'mir, 'tcx, NeedsDrop>, indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>, } -impl Qualifs<'a, 'mir, 'tcx> { - fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool { +impl Qualifs<'mir, 'tcx> { + fn indirectly_mutable( + &mut self, + _: &Item<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { self.indirectly_mutable.seek_before(location); self.indirectly_mutable.get().contains(local) } @@ -69,29 +53,36 @@ impl Qualifs<'a, 'mir, 'tcx> { /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. /// /// Only updates the cursor if absolutely necessary - fn needs_drop(&mut self, local: Local, location: Location) -> bool { - if !self.needs_drop.in_any_value_of_ty.contains(local) { + fn needs_drop(&mut self, item: &Item<'mir, 'tcx>, local: Local, location: Location) -> bool { + let ty = item.body.local_decls[local].ty; + if !NeedsDrop::in_any_value_of_ty(item, ty) { return false; } - self.needs_drop.cursor.seek_before(location); - self.needs_drop.cursor.get().contains(local) || self.indirectly_mutable(local, location) + self.needs_drop.seek_before(location); + self.needs_drop.get().contains(local) || self.indirectly_mutable(item, local, location) } /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. /// /// Only updates the cursor if absolutely necessary. - fn has_mut_interior(&mut self, local: Local, location: Location) -> bool { - if !self.has_mut_interior.in_any_value_of_ty.contains(local) { + fn has_mut_interior( + &mut self, + item: &Item<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !HasMutInterior::in_any_value_of_ty(ccx, ty) { return false; } - self.has_mut_interior.cursor.seek_before(location); - self.has_mut_interior.cursor.get().contains(local) - || self.indirectly_mutable(local, location) + self.has_mut_interior.seek_before(location); + self.has_mut_interior.get().contains(local) + || self.indirectly_mutable(item, local, location) } - fn in_return_place(&mut self, ccx: &ConstCx<'_, 'tcx>) -> ConstQualifs { + fn in_return_place(&mut self, item: &Item<'mir, 'tcx>) -> ConstQualifs { // Find the `Return` terminator if one exists. // // If no `Return` terminator exists, this MIR is divergent. Just return the conservative @@ -114,21 +105,21 @@ impl Qualifs<'a, 'mir, 'tcx> { let return_loc = ccx.body.terminator_loc(return_block); ConstQualifs { - needs_drop: self.needs_drop(RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(RETURN_PLACE, return_loc), + needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), + has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), } } } -pub struct Validator<'a, 'mir, 'tcx> { - ccx: &'a ConstCx<'mir, 'tcx>, - qualifs: Qualifs<'a, 'mir, 'tcx>, +pub struct Validator<'mir, 'tcx> { + ccx: &'mir ConstCx<'mir, 'tcx>, + qualifs: Qualifs<'mir, 'tcx>, /// The span of the current statement. span: Span, } -impl Deref for Validator<'_, 'mir, 'tcx> { +impl Deref for Validator<'mir, 'tcx> { type Target = ConstCx<'mir, 'tcx>; fn deref(&self) -> &Self::Target { @@ -136,12 +127,9 @@ impl Deref for Validator<'_, 'mir, 'tcx> { } } -impl Validator<'a, 'mir, 'tcx> { - pub fn new(ccx: &'a ConstCx<'mir, 'tcx>) -> Self { - let ConstCx { tcx, body, def_id, param_env, .. } = *ccx; - - let needs_drop = QualifCursor::new(NeedsDrop, ccx); - let has_mut_interior = QualifCursor::new(HasMutInterior, ccx); +impl Validator<'mir, 'tcx> { + pub fn new(item: &'mir Item<'mir, 'tcx>) -> Self { + let Item { tcx, body, def_id, param_env, .. } = *item; // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not // allowed in a const. @@ -154,6 +142,16 @@ impl Validator<'a, 'mir, 'tcx> { .iterate_to_fixpoint() .into_results_cursor(body); + let needs_drop = FlowSensitiveAnalysis::new(NeedsDrop, item) + .into_engine(item.tcx, &item.body, item.def_id) + .iterate_to_fixpoint() + .into_results_cursor(*item.body); + + let has_mut_interior = FlowSensitiveAnalysis::new(HasMutInterior, item) + .into_engine(item.tcx, &item.body, item.def_id) + .iterate_to_fixpoint() + .into_results_cursor(*item.body); + let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable }; Validator { span: ccx.body.span, ccx, qualifs } @@ -239,7 +237,7 @@ impl Validator<'a, 'mir, 'tcx> { } } -impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { +impl Visitor<'tcx> for Validator<'mir, 'tcx> { fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) { trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); @@ -345,7 +343,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { | Rvalue::AddressOf(Mutability::Not, ref place) => { let borrowed_place_has_mut_interior = qualifs::in_place::( &self.ccx, - &mut |local| self.qualifs.has_mut_interior(local, location), + &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), place.as_ref(), ); @@ -571,7 +569,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { let needs_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_drop(local, location) + self.qualifs.needs_drop(self.ccx, local, location) } else { true }; From 1343797859d9d2204b7d19e97acbe83c4744578c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 19 Apr 2020 11:02:35 -0700 Subject: [PATCH 04/12] Lazily run dataflow for const qualification --- .../transform/check_consts/validation.rs | 99 +++++++++++-------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 5b37edd01b37c..f47fd8239dea5 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -33,34 +33,64 @@ type IndirectlyMutableResults<'mir, 'tcx> = type QualifResults<'mir, 'tcx, Q> = dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; +#[derive(Default)] pub struct Qualifs<'mir, 'tcx> { - has_mut_interior: QualifResults<'mir, 'tcx, HasMutInterior>, - needs_drop: QualifResults<'mir, 'tcx, NeedsDrop>, - indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>, + has_mut_interior: Option>, + needs_drop: Option>, + indirectly_mutable: Option>, } impl Qualifs<'mir, 'tcx> { fn indirectly_mutable( &mut self, - _: &Item<'mir, 'tcx>, + ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, ) -> bool { - self.indirectly_mutable.seek_before(location); - self.indirectly_mutable.get().contains(local) + let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| { + let ConstCx { tcx, body, def_id, param_env, .. } = *ccx; + + // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not + // allowed in a const. + // + // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this + // without breaking stable code? + MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) + .unsound_ignore_borrow_on_drop() + .into_engine(tcx, &body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + indirectly_mutable.seek_before(location); + indirectly_mutable.get().contains(local) } /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. /// /// Only updates the cursor if absolutely necessary - fn needs_drop(&mut self, item: &Item<'mir, 'tcx>, local: Local, location: Location) -> bool { - let ty = item.body.local_decls[local].ty; - if !NeedsDrop::in_any_value_of_ty(item, ty) { + fn needs_drop( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !NeedsDrop::in_any_value_of_ty(ccx, ty) { return false; } - self.needs_drop.seek_before(location); - self.needs_drop.get().contains(local) || self.indirectly_mutable(item, local, location) + let needs_drop = self.needs_drop.get_or_insert_with(|| { + let ConstCx { tcx, body, def_id, .. } = *ccx; + + FlowSensitiveAnalysis::new(NeedsDrop, ccx) + .into_engine(tcx, &body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + needs_drop.seek_before(location); + needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) } /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. @@ -68,7 +98,7 @@ impl Qualifs<'mir, 'tcx> { /// Only updates the cursor if absolutely necessary. fn has_mut_interior( &mut self, - item: &Item<'mir, 'tcx>, + ccx: &'mir ConstCx<'mir, 'tcx>, local: Local, location: Location, ) -> bool { @@ -77,12 +107,20 @@ impl Qualifs<'mir, 'tcx> { return false; } - self.has_mut_interior.seek_before(location); - self.has_mut_interior.get().contains(local) - || self.indirectly_mutable(item, local, location) + let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { + let ConstCx { tcx, body, def_id, .. } = *ccx; + + FlowSensitiveAnalysis::new(HasMutInterior, ccx) + .into_engine(tcx, &body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + has_mut_interior.seek_before(location); + has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location) } - fn in_return_place(&mut self, item: &Item<'mir, 'tcx>) -> ConstQualifs { + fn in_return_place(&mut self, ccx: &'mir ConstCx<'mir, 'tcx>) -> ConstQualifs { // Find the `Return` terminator if one exists. // // If no `Return` terminator exists, this MIR is divergent. Just return the conservative @@ -128,33 +166,8 @@ impl Deref for Validator<'mir, 'tcx> { } impl Validator<'mir, 'tcx> { - pub fn new(item: &'mir Item<'mir, 'tcx>) -> Self { - let Item { tcx, body, def_id, param_env, .. } = *item; - - // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not - // allowed in a const. - // - // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this - // without breaking stable code? - let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env) - .unsound_ignore_borrow_on_drop() - .into_engine(tcx, body, def_id) - .iterate_to_fixpoint() - .into_results_cursor(body); - - let needs_drop = FlowSensitiveAnalysis::new(NeedsDrop, item) - .into_engine(item.tcx, &item.body, item.def_id) - .iterate_to_fixpoint() - .into_results_cursor(*item.body); - - let has_mut_interior = FlowSensitiveAnalysis::new(HasMutInterior, item) - .into_engine(item.tcx, &item.body, item.def_id) - .iterate_to_fixpoint() - .into_results_cursor(*item.body); - - let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable }; - - Validator { span: ccx.body.span, ccx, qualifs } + pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { + Validator { span: ccx.body.span, ccx, qualifs: Default::default() } } pub fn check_body(&mut self) { From 15f95b145e8ca9aaf2e8690f64db24b05153f851 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 19 Apr 2020 12:42:24 -0700 Subject: [PATCH 05/12] Cycle errors now occur during const-eval, not checking --- src/test/ui/issues/issue-17252.stderr | 21 ++++++++++--- src/test/ui/issues/issue-23302-1.stderr | 17 ++++++++-- src/test/ui/issues/issue-23302-2.stderr | 17 ++++++++-- src/test/ui/issues/issue-23302-3.stderr | 36 +++++++++++++++------ src/test/ui/issues/issue-36163.stderr | 42 ++++++++++++++++++++----- 5 files changed, 106 insertions(+), 27 deletions(-) diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 8fd67b19d6a5a..ee621a8cb1473 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,11 +1,22 @@ -error[E0391]: cycle detected when const checking `FOO` - --> $DIR/issue-17252.rs:1:20 +error[E0391]: cycle detected when normalizing `FOO` + | +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/issue-17252.rs:1:1 + | +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating `FOO`... + --> $DIR/issue-17252.rs:1:1 | - = note: ...which again requires const checking `FOO`, completing the cycle -note: cycle used when const checking `main::{{constant}}#0` +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires normalizing `FOO`, completing the cycle +note: cycle used when const-evaluating `main::{{constant}}#0` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index f2457774326dd..b6c85b9e22749 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,15 +1,26 @@ -error[E0391]: cycle detected when const checking `X::A::{{constant}}#0` +error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | - = note: ...which again requires const checking `X::A::{{constant}}#0`, completing the cycle -note: cycle used when processing `X::A::{{constant}}#0` +note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ +note: ...which requires const-evaluating `X::A::{{constant}}#0`... + --> $DIR/issue-23302-1.rs:4:9 + | +LL | A = X::A as isize, + | ^^^^^^^^^^^^^ + = note: ...which requires normalizing `X::A as isize`... + = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-23302-1.rs:3:1 + | +LL | enum X { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index c121c17b904ea..d014922fe2069 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,15 +1,26 @@ -error[E0391]: cycle detected when const checking `Y::A::{{constant}}#0` +error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | - = note: ...which again requires const checking `Y::A::{{constant}}#0`, completing the cycle -note: cycle used when processing `Y::A::{{constant}}#0` +note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ +note: ...which requires const-evaluating `Y::A::{{constant}}#0`... + --> $DIR/issue-23302-2.rs:4:9 + | +LL | A = Y::B as isize, + | ^^^^^^^^^^^^^ + = note: ...which requires normalizing `Y::B as isize`... + = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-23302-2.rs:3:1 + | +LL | enum Y { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index 0229469f04140..b30b1214271a0 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,20 +1,38 @@ -error[E0391]: cycle detected when const checking `A` - --> $DIR/issue-23302-3.rs:1:16 +error[E0391]: cycle detected when const-evaluating + checking `A` + --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; - | ^ + | ^^^^^^^^^^^^^^^^^ | -note: ...which requires const checking `B`... - --> $DIR/issue-23302-3.rs:3:16 +note: ...which requires const-evaluating + checking `A`... + --> $DIR/issue-23302-3.rs:1:1 | -LL | const B: i32 = A; - | ^ - = note: ...which again requires const checking `A`, completing the cycle -note: cycle used when processing `A` +LL | const A: i32 = B; + | ^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating `A`... --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ + = note: ...which requires normalizing `B`... +note: ...which requires const-evaluating + checking `B`... + --> $DIR/issue-23302-3.rs:3:1 + | +LL | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `B`... + --> $DIR/issue-23302-3.rs:3:1 + | +LL | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating `B`... + --> $DIR/issue-23302-3.rs:3:1 + | +LL | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ + = note: ...which requires normalizing `A`... + = note: ...which again requires const-evaluating + checking `A`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 3866243914b89..7c2da9dce6e9d 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,20 +1,48 @@ -error[E0391]: cycle detected when const checking `Foo::B::{{constant}}#0` +error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const checking `A`... - --> $DIR/issue-36163.rs:1:18 +note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... + --> $DIR/issue-36163.rs:4:9 | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^ - = note: ...which again requires const checking `Foo::B::{{constant}}#0`, completing the cycle -note: cycle used when processing `Foo::B::{{constant}}#0` +LL | B = A, + | ^ +note: ...which requires const-evaluating `Foo::B::{{constant}}#0`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ + = note: ...which requires normalizing `A`... +note: ...which requires const-evaluating + checking `A`... + --> $DIR/issue-36163.rs:1:1 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `A`... + --> $DIR/issue-36163.rs:1:1 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating `A`... + --> $DIR/issue-36163.rs:1:1 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires normalizing `A`... + = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-36163.rs:1:1 + | +LL | / const A: isize = Foo::B as isize; +LL | | +LL | | enum Foo { +LL | | B = A, +LL | | } +LL | | +LL | | fn main() {} + | |____________^ error: aborting due to previous error From 03817ec78917d37d8d41b57029f2fb8e9474108c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Apr 2020 20:18:14 +0200 Subject: [PATCH 06/12] Improve PanicInfo examples readability --- src/libcore/panic.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index dbfcbca3ffcbf..575f51d0a7d56 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -77,7 +77,11 @@ impl<'a> PanicInfo<'a> { /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { - /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); + /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { + /// println!("panic occurred: {:?}", s); + /// } else { + /// println!("panic occurred"); + /// } /// })); /// /// panic!("Normal panic"); @@ -112,8 +116,10 @@ impl<'a> PanicInfo<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}' at line {}", location.file(), - /// location.line()); + /// println!("panic occurred in file '{}' at line {}", + /// location.file(), + /// location.line(), + /// ); /// } else { /// println!("panic occurred but can't get location information..."); /// } From 787eddc1ab49766204c35d2a60c3d75b6ea7413c Mon Sep 17 00:00:00 2001 From: arlo Date: Thu, 23 Apr 2020 14:07:50 -0500 Subject: [PATCH 07/12] Add BinaryHeap::retain as suggested in #42849 --- src/liballoc/collections/binary_heap.rs | 28 +++++++++++++++++++++++++ src/liballoc/tests/binary_heap.rs | 8 +++++++ src/liballoc/tests/lib.rs | 1 + 3 files changed, 37 insertions(+) diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 03c9164fb9095..8e170d970bc57 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -665,6 +665,34 @@ impl BinaryHeap { pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> { DrainSorted { inner: self } } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns + /// `false`. The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(binary_heap_retain)] + /// use std::collections::BinaryHeap; + /// + /// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]); + /// + /// heap.retain(|x| x % 2 == 0); // only keep even numbers + /// + /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4]) + /// ``` + #[unstable(feature = "binary_heap_retain", issue = "71503")] + pub fn retain(&mut self, f: F) + where + F: FnMut(&T) -> bool, + { + self.data.retain(f); + self.rebuild(); + } } impl BinaryHeap { diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index be5516f54f37b..08ed5447772a1 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -372,6 +372,14 @@ fn assert_covariance() { } } +#[test] +fn test_retain() { + let mut a = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]); + a.retain(|x| x % 2 == 0); + + assert_eq!(a.into_sorted_vec(), [-10, 2, 4]) +} + // old binaryheap failed this test // // Integrity means that all elements are present after a comparison panics, diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index ad6feaeebc67f..78d49558262e3 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(binary_heap_drain_sorted)] #![feature(vec_remove_item)] #![feature(split_inclusive)] +#![feature(binary_heap_retain)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; From a62a8b00e9e071ea2739141ad5b3eaf479d97873 Mon Sep 17 00:00:00 2001 From: Rustin-Liu Date: Fri, 24 Apr 2020 22:26:10 +0800 Subject: [PATCH 08/12] Remove useless "" args Signed-off-by: Rustin-Liu --- src/bootstrap/toolstate.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 095c3c03c307b..e6560771c0ee7 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -93,12 +93,12 @@ static NIGHTLY_TOOLS: &[(&str, &str)] = &[ ]; fn print_error(tool: &str, submodule: &str) { - eprintln!(""); + eprintln!(); eprintln!("We detected that this PR updated '{}', but its tests failed.", tool); - eprintln!(""); + eprintln!(); eprintln!("If you do intend to update '{}', please check the error messages above and", tool); eprintln!("commit another update."); - eprintln!(""); + eprintln!(); eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool); eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule); eprintln!("proper steps."); From 5a49578b28a3804e9f62fc23b021e1d42445fce3 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 24 Apr 2020 12:07:33 -0700 Subject: [PATCH 09/12] Use `debug` to print illegal operations in a const context --- src/librustc_mir/transform/check_consts/validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 45d8e1d08b721..90dafe9c359fd 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -205,7 +205,7 @@ impl Validator<'a, 'mir, 'tcx> { where O: NonConstOp, { - trace!("check_op: op={:?}", op); + debug!("check_op: op={:?}", op); if op.is_allowed_in_item(self) { return; From 0e34cb2bdd21bf00d557c3769a6e2ce490e4f6ac Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 24 Apr 2020 12:07:44 -0700 Subject: [PATCH 10/12] Remove unused `visit_local` --- src/librustc_mir/transform/check_consts/validation.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 90dafe9c359fd..d794599f9982f 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -386,15 +386,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } } - fn visit_local(&mut self, place_local: &Local, context: PlaceContext, location: Location) { - trace!( - "visit_local: place_local={:?} context={:?} location={:?}", - place_local, - context, - location, - ); - } - fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { self.super_operand(op, location); if let Operand::Constant(c) = op { From 2325c209257a8ce6c11200ebfc152907566f7a04 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 24 Apr 2020 13:58:41 -0700 Subject: [PATCH 11/12] Avoid unused Option::map results These are changes that would be needed if we add `#[must_use]` to `Option::map`, per #71484. --- src/librustc_attr/builtin.rs | 4 +- src/librustc_expand/expand.rs | 8 ++-- src/librustc_hir/definitions.rs | 2 +- .../infer/error_reporting/mod.rs | 4 +- src/librustc_metadata/creader.rs | 12 ++++-- src/librustc_mir_build/build/matches/mod.rs | 4 +- src/librustc_parse/parser/mod.rs | 4 +- src/librustc_passes/loops.rs | 4 +- src/librustc_query_system/query/job.rs | 6 ++- src/librustc_resolve/late.rs | 4 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_target/spec/mod.rs | 37 ++++++++++--------- src/librustc_typeck/astconv.rs | 8 +++- src/librustc_typeck/check/demand.rs | 4 +- src/librustc_typeck/check/mod.rs | 7 ++-- src/librustc_typeck/check/pat.rs | 16 +++++--- src/librustc_typeck/check/writeback.rs | 16 +++++--- src/librustdoc/clean/mod.rs | 11 +++--- src/librustdoc/html/toc.rs | 4 +- src/libstd/sync/mpsc/shared.rs | 4 +- src/libstd/sync/mpsc/sync.rs | 12 ++++-- 21 files changed, 111 insertions(+), 64 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index ab5a844e58f7a..c2b2e7ce59f37 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -98,7 +98,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op } } - diagnostic.map(|d| { + if let Some(d) = diagnostic { struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input") .span_label(attr.span, "invalid argument") .span_suggestions( @@ -110,7 +110,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op Applicability::MachineApplicable, ) .emit(); - }); + }; } } } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 2618c758ca5da..972e75d201b90 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1172,10 +1172,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // ignore derives so they remain unused let (attr, after_derive) = self.classify_nonitem(&mut expr); - if attr.is_some() { + if let Some(ref attr_value) = attr { // Collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later. - attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); + self.cfg.maybe_emit_expr_attr_err(attr_value); // AstFragmentKind::Expr requires the macro to emit an expression. return self @@ -1322,8 +1322,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // Ignore derives so they remain unused. let (attr, after_derive) = self.classify_nonitem(&mut expr); - if attr.is_some() { - attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); + if let Some(ref attr_value) = attr { + self.cfg.maybe_emit_expr_attr_err(attr_value); return self .collect_attr( diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 033c2973af6ee..30cddac6aac91 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -246,7 +246,7 @@ impl DefPath { let mut opt_delimiter = None; for component in &self.data { - opt_delimiter.map(|d| s.push(d)); + s.extend(opt_delimiter); opt_delimiter = Some('-'); if component.disambiguator == 0 { write!(s, "{}", component.data.as_symbol()).unwrap(); diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index dd1d08a75ae19..8b53019106537 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -755,7 +755,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { err.span_label(then, "expected because of this"); - outer.map(|sp| err.span_label(sp, "`if` and `else` have incompatible types")); + if let Some(sp) = outer { + err.span_label(sp, "`if` and `else` have incompatible types"); + } if let Some(sp) = semicolon { err.span_suggestion_short( sp, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index fe8fbd50627d3..e7a863c63ccaa 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -101,9 +101,15 @@ fn dump_crates(cstore: &CStore) { info!(" hash: {}", data.hash()); info!(" reqd: {:?}", data.dep_kind()); let CrateSource { dylib, rlib, rmeta } = data.source(); - dylib.as_ref().map(|dl| info!(" dylib: {}", dl.0.display())); - rlib.as_ref().map(|rl| info!(" rlib: {}", rl.0.display())); - rmeta.as_ref().map(|rl| info!(" rmeta: {}", rl.0.display())); + if let Some(dylib) = dylib { + info!(" dylib: {}", dylib.0.display()); + } + if let Some(rlib) = rlib { + info!(" rlib: {}", rlib.0.display()); + } + if let Some(rmeta) = rmeta { + info!(" rmeta: {}", rmeta.0.display()); + } }); } diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 10ffc81f179d1..b9d61458a839b 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -1388,7 +1388,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Insert a Shallow borrow of any places that is switched on. - fake_borrows.as_mut().map(|fb| fb.insert(match_place)); + if let Some(fb) = fake_borrows { + fb.insert(match_place); + } // perform the test, branching to one of N blocks. For each of // those N possible outcomes, create a (initially empty) diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index b987813e38d98..9264fc8a73518 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1206,8 +1206,8 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa *sess.reached_eof.borrow_mut() |= unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()); for unmatched in unclosed_delims.drain(..) { - make_unclosed_delims_error(unmatched, sess).map(|mut e| { + if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) { e.emit(); - }); + } } } diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 23a605bef0cd3..09b3d44020d81 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -68,7 +68,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(LabeledBlock, |v| v.visit_block(&b)); } hir::ExprKind::Break(label, ref opt_expr) => { - opt_expr.as_ref().map(|e| self.visit_expr(e)); + if let Some(e) = opt_expr { + self.visit_expr(e); + } if self.require_label_in_labeled_block(e.span, &label, "break") { // If we emitted an error about an unlabeled break in a labeled diff --git a/src/librustc_query_system/query/job.rs b/src/librustc_query_system/query/job.rs index de6dc81d8687a..5150b278a7722 100644 --- a/src/librustc_query_system/query/job.rs +++ b/src/librustc_query_system/query/job.rs @@ -133,7 +133,11 @@ impl QueryJob { /// as there are no concurrent jobs which could be waiting on us pub fn signal_complete(self) { #[cfg(parallel_compiler)] - self.latch.map(|latch| latch.set()); + { + if let Some(latch) = self.latch { + latch.set(); + } + } } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 67713b5636965..f369e827a402b 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1996,7 +1996,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.visit_expr(cond); this.visit_block(then); }); - opt_else.as_ref().map(|expr| self.visit_expr(expr)); + if let Some(expr) = opt_else { + self.visit_expr(expr); + } } ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e94d7d6a85fb4..77aa7230aa893 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -499,7 +499,9 @@ impl<'a> ModuleData<'a> { F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding)); + if let Some(binding) = name_resolution.borrow().binding { + f(resolver, key.ident, key.ns, binding); + } } } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 8f3097ad4233e..d904046331723 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -979,20 +979,21 @@ impl Target { macro_rules! key { ($key_name:ident) => ( { let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]).map(|o| o.as_string() - .map(|s| base.options.$key_name = s.to_string())); + if let Some(s) = obj.find(&name).and_then(Json::as_string) { + base.options.$key_name = s.to_string(); + } } ); ($key_name:ident, bool) => ( { let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]) - .map(|o| o.as_boolean() - .map(|s| base.options.$key_name = s)); + if let Some(s) = obj.find(&name).and_then(Json::as_boolean) { + base.options.$key_name = s; + } } ); ($key_name:ident, Option) => ( { let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]) - .map(|o| o.as_u64() - .map(|s| base.options.$key_name = Some(s))); + if let Some(s) = obj.find(&name).and_then(Json::as_u64) { + base.options.$key_name = Some(s); + } } ); ($key_name:ident, MergeFunctions) => ( { let name = (stringify!($key_name)).replace("_", "-"); @@ -1034,19 +1035,19 @@ impl Target { } ); ($key_name:ident, list) => ( { let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]).map(|o| o.as_array() - .map(|v| base.options.$key_name = v.iter() - .map(|a| a.as_string().unwrap().to_string()).collect() - ) - ); + if let Some(v) = obj.find(&name).and_then(Json::as_array) { + base.options.$key_name = v.iter() + .map(|a| a.as_string().unwrap().to_string()) + .collect(); + } } ); ($key_name:ident, opt_list) => ( { let name = (stringify!($key_name)).replace("_", "-"); - obj.find(&name[..]).map(|o| o.as_array() - .map(|v| base.options.$key_name = Some(v.iter() - .map(|a| a.as_string().unwrap().to_string()).collect()) - ) - ); + if let Some(v) = obj.find(&name).and_then(Json::as_array) { + base.options.$key_name = Some(v.iter() + .map(|a| a.as_string().unwrap().to_string()) + .collect()); + } } ); ($key_name:ident, optional) => ( { let name = (stringify!($key_name)).replace("_", "-"); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 706dca999fa32..c7d749815febb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -213,7 +213,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { None, ); - assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span)); + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } substs } @@ -1095,7 +1097,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> ty::TraitRef<'tcx> { let (substs, assoc_bindings, _) = self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); - assoc_bindings.first().map(|b| AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span)); + if let Some(b) = assoc_bindings.first() { + AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span); + } ty::TraitRef::new(trait_def_id, substs) } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 7db376b20aaa8..c75283e419a6d 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -36,7 +36,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - self.demand_suptype_diag(sp, expected, actual).map(|mut e| e.emit()); + if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) { + e.emit(); + } } pub fn demand_suptype_diag( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 51e3bc4cae406..b7e86c0791f63 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4492,15 +4492,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => Err(ErrorReported), }; if item_name.name != kw::Invalid { - self.report_method_error( + if let Some(mut e) = self.report_method_error( span, ty, item_name, SelfSource::QPath(qself), error, None, - ) - .map(|mut e| e.emit()); + ) { + e.emit(); + } } result }); diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index b53ae6acdebbb..8e109efbcb576 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -104,7 +104,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { actual: Ty<'tcx>, ti: TopInfo<'tcx>, ) { - self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map(|mut err| err.emit()); + if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { + err.emit(); + } } } @@ -449,12 +451,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x, y| { if let Some((_, x_ty, x_span)) = x { - self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| { + if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); } err.emit(); - }); + }; } }; demand_eqtype(lhs, rhs); @@ -852,8 +854,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti); - let had_err = diag.is_some(); - diag.map(|mut err| err.emit()); + let had_err = if let Some(mut err) = diag { + err.emit(); + true + } else { + false + }; // Type-check subpatterns. if subpats.len() == variant.fields.len() diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 56714a4fa6793..c5bf151bc1e11 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -165,12 +165,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hir::ExprKind::Binary(..) => { if !op.node.is_by_value() { let mut adjustments = tables.adjustments_mut(); - adjustments.get_mut(lhs.hir_id).map(|a| a.pop()); - adjustments.get_mut(rhs.hir_id).map(|a| a.pop()); + if let Some(a) = adjustments.get_mut(lhs.hir_id) { + a.pop(); + } + if let Some(a) = adjustments.get_mut(rhs.hir_id) { + a.pop(); + } } } hir::ExprKind::AssignOp(..) => { - tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop()); + if let Some(a) = tables.adjustments_mut().get_mut(lhs.hir_id) { + a.pop(); + } } _ => {} } @@ -215,7 +221,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { tables.type_dependent_defs_mut().remove(e.hir_id); tables.node_substs_mut().remove(e.hir_id); - tables.adjustments_mut().get_mut(base.hir_id).map(|a| { + if let Some(a) = tables.adjustments_mut().get_mut(base.hir_id) { // Discard the need for a mutable borrow // Extra adjustment made when indexing causes a drop @@ -229,7 +235,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // So the borrow discard actually happens here a.pop(); } - }); + } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4d03bb21cb3ec..63ab0ef5f1728 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1599,7 +1599,9 @@ impl<'tcx> Clean for Ty<'tcx> { inline::record_extern_fqn(cx, did, TypeKind::Trait); let mut param_names = vec![]; - reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b))); + if let Some(b) = reg.clean(cx) { + param_names.push(GenericBound::Outlives(b)); + } for did in dids { let empty = cx.tcx.intern_substs(&[]); let path = @@ -1662,10 +1664,9 @@ impl<'tcx> Clean for Ty<'tcx> { tr } else if let ty::Predicate::TypeOutlives(pred) = *predicate { // these should turn up at the end - pred.skip_binder() - .1 - .clean(cx) - .map(|r| regions.push(GenericBound::Outlives(r))); + if let Some(r) = pred.skip_binder().1.clean(cx) { + regions.push(GenericBound::Outlives(r)); + } return None; } else { return None; diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 034fb27300027..3754029577475 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -94,7 +94,7 @@ impl TocBuilder { loop { match self.chain.pop() { Some(mut next) => { - this.map(|e| next.children.entries.push(e)); + next.children.entries.extend(this); if next.level < level { // this is the parent we want, so return it to // its rightful place. @@ -105,7 +105,7 @@ impl TocBuilder { } } None => { - this.map(|e| self.top_level.entries.push(e)); + self.top_level.entries.extend(this); return; } } diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index c4e929624d7a4..fd9d61e99c2cd 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -91,7 +91,7 @@ impl Packet { // // This can only be called at channel-creation time pub fn inherit_blocker(&self, token: Option, guard: MutexGuard<'_, ()>) { - token.map(|token| { + if let Some(token) = token { assert_eq!(self.cnt.load(Ordering::SeqCst), 0); assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst); @@ -118,7 +118,7 @@ impl Packet { unsafe { *self.steals.get() = -1; } - }); + } // When the shared packet is constructed, we grabbed this lock. The // purpose of this lock is to ensure that abort_selection() doesn't diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 3e2050799ccb4..79123903e92a5 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -343,8 +343,12 @@ impl Packet { mem::drop(guard); // only outside of the lock do we wake up the pending threads - pending_sender1.map(|t| t.signal()); - pending_sender2.map(|t| t.signal()); + if let Some(token) = pending_sender1 { + token.signal(); + } + if let Some(token) = pending_sender2 { + token.signal(); + } } // Prepares this shared packet for a channel clone, essentially just bumping @@ -410,7 +414,9 @@ impl Packet { while let Some(token) = queue.dequeue() { token.signal(); } - waiter.map(|t| t.signal()); + if let Some(token) = waiter { + token.signal(); + } } } From 0689efc41144cbaec3052eea1816323384639a00 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 24 Apr 2020 13:07:57 -0700 Subject: [PATCH 12/12] Fix typos in docs for keyword "in" --- src/libstd/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 314424631fcbf..6fbb0139b0eca 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -685,12 +685,12 @@ mod impl_keyword {} /// ## Literal Examples: /// /// * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3. -/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and includeing 3. +/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and including 3. /// /// (Read more about [range patterns]) /// /// [`Iterator`]: ../book/ch13-04-performance.html -/// [`range patterns`]: ../reference/patterns.html?highlight=range#range-patterns +/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns /// [`for`]: keyword.for.html mod in_keyword {}