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.
This commit is contained in:
parent
b6e334d873
commit
41f9f38d6e
4 changed files with 23 additions and 15 deletions
|
@ -104,11 +104,5 @@ pub fn report_object_safety_error(
|
||||||
to be resolvable dynamically; for more information visit \
|
to be resolvable dynamically; for more information visit \
|
||||||
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
|
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
|
||||||
);
|
);
|
||||||
|
|
||||||
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
|
err
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,9 +189,6 @@ pub struct Session {
|
||||||
/// Cap lint level specified by a driver specifically.
|
/// Cap lint level specified by a driver specifically.
|
||||||
pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||||
|
|
||||||
/// `Span`s of trait methods that weren't found to avoid emitting object safety errors
|
|
||||||
pub trait_methods_not_found: Lock<FxHashSet<Span>>,
|
|
||||||
|
|
||||||
/// Mapping from ident span to path span for paths that don't exist as written, but that
|
/// 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`.
|
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
|
||||||
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
|
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
|
||||||
|
@ -1353,7 +1350,6 @@ pub fn build_session(
|
||||||
print_fuel,
|
print_fuel,
|
||||||
jobserver: jobserver::client(),
|
jobserver: jobserver::client(),
|
||||||
driver_lint_caps,
|
driver_lint_caps,
|
||||||
trait_methods_not_found: Lock::new(Default::default()),
|
|
||||||
confused_type_with_std_module: Lock::new(Default::default()),
|
confused_type_with_std_module: Lock::new(Default::default()),
|
||||||
ctfe_backtrace,
|
ctfe_backtrace,
|
||||||
miri_unleashed_features: Lock::new(Default::default()),
|
miri_unleashed_features: Lock::new(Default::default()),
|
||||||
|
|
|
@ -858,13 +858,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
path.segments,
|
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.
|
||||||
|
(<dyn AstConv<'_>>::ast_ty_to_ty(self, qself), qself, segment)
|
||||||
|
}
|
||||||
QPath::LangItem(..) => {
|
QPath::LangItem(..) => {
|
||||||
bug!("`resolve_ty_and_res_fully_qualified_call` called on `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)
|
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
|
// Return directly on cache hit. This is useful to avoid doubly reporting
|
||||||
// errors with default match binding modes. See #44614.
|
// errors with default match binding modes. See #44614.
|
||||||
let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
|
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)),
|
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
|
||||||
_ => Err(ErrorReported),
|
_ => 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 item_name.name != kw::Empty {
|
||||||
if let Some(mut e) = self.report_method_error(
|
if let Some(mut e) = self.report_method_error(
|
||||||
span,
|
span,
|
||||||
|
@ -895,6 +915,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.maybe_lint_bare_trait(qpath, hir_id);
|
self.maybe_lint_bare_trait(qpath, hir_id);
|
||||||
|
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write back the new resolution.
|
// Write back the new resolution.
|
||||||
|
|
|
@ -70,15 +70,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
pub fn report_method_error(
|
pub fn report_method_error(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
mut span: Span,
|
||||||
rcvr_ty: Ty<'tcx>,
|
rcvr_ty: Ty<'tcx>,
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
error: MethodError<'tcx>,
|
error: MethodError<'tcx>,
|
||||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||||
) -> Option<DiagnosticBuilder<'_>> {
|
) -> Option<DiagnosticBuilder<'_>> {
|
||||||
let orig_span = span;
|
|
||||||
let mut span = span;
|
|
||||||
// Avoid suggestions when we don't know what's going on.
|
// Avoid suggestions when we don't know what's going on.
|
||||||
if rcvr_ty.references_error() {
|
if rcvr_ty.references_error() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -545,7 +543,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
|
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,
|
// If the method name is the name of a field with a function or closure type,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue