From 41f9f38d6e19c669a14432b9ec56f26425c6c9e2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 21 Aug 2021 18:45:56 -0500 Subject: [PATCH] Remove `Session.trait_methods_not_found` Instead, avoid registering the problematic well-formed obligation to begin with. This removes global untracked mutable state, and avoids potential issues with incremental compilation. --- .../src/traits/error_reporting/mod.rs | 6 ----- compiler/rustc_session/src/session.rs | 4 ---- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 23 ++++++++++++++++++- .../rustc_typeck/src/check/method/suggest.rs | 5 +--- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 0ac4b6b25bb..d0bd508bc25 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -104,11 +104,5 @@ pub fn report_object_safety_error( to be resolvable dynamically; for more information visit \ ", ); - - if tcx.sess.trait_methods_not_found.borrow().iter().any(|full_span| full_span.contains(span)) { - // Avoid emitting error caused by non-existing method (#58734) - err.cancel(); - } - err } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5b163603d5f..fabdebfb212 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -189,9 +189,6 @@ pub struct Session { /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, - /// `Span`s of trait methods that weren't found to avoid emitting object safety errors - pub trait_methods_not_found: Lock>, - /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: Lock>, @@ -1353,7 +1350,6 @@ pub fn build_session( print_fuel, jobserver: jobserver::client(), driver_lint_caps, - trait_methods_not_found: Lock::new(Default::default()), confused_type_with_std_module: Lock::new(Default::default()), ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index bb80f0879a4..8be57e4b3ca 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -858,13 +858,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path.segments, ); } - QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::TypeRelative(ref qself, ref segment) => { + // Don't use `self.to_ty`, since this will register a WF obligation. + // If we're trying to call a non-existent method on a trait + // (e.g. `MyTrait::missing_method`), then resolution will + // give us a `QPath::TypeRelative` with a trait object as + // `qself`. In that case, we want to avoid registering a WF obligation + // for `dyn MyTrait`, since we don't actually need the trait + // to be object-safe. + // We manually call `register_wf_obligation` in the success path + // below. + (>::ast_ty_to_ty(self, qself), qself, segment) + } QPath::LangItem(..) => { bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`") } }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); @@ -878,6 +890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(ErrorReported), }; + + // If we have a path like `MyTrait::missing_method`, then don't register + // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, + // register a WF obligation so that we can detect any additional + // errors in the self type. + if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) { + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); + } if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -895,6 +915,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if result.is_ok() { self.maybe_lint_bare_trait(qpath, hir_id); + self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None)); } // Write back the new resolution. diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 1d5a9e3e1f9..afe274a2a79 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -70,15 +70,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn report_method_error( &self, - span: Span, + mut span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> Option> { - let orig_span = span; - let mut span = span; // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; @@ -545,7 +543,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); } - self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span); }; // If the method name is the name of a field with a function or closure type,