From afe36507e84e8b7805717bc1c5054dcf4346df92 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 May 2023 00:10:06 +0000 Subject: [PATCH] Don't structurally resolve during method ambiguity in probe --- compiler/rustc_hir_typeck/src/method/probe.rs | 19 ++++++--- .../deref-ambiguity-becomes-nonambiguous.rs | 40 +++++++++++++++++++ ...eref-ambiguity-becomes-nonambiguous.stderr | 17 ++++++++ 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs create mode 100644 tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e759fd6bc948a..762176ecfc795 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,6 +12,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; @@ -448,15 +449,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else { - // Encountered a real ambiguity, so abort the lookup. If `ty` is not - // an `Err`, report the right "type annotations needed" error pointing - // to it. + // Ended up encountering a type variable when doing autoderef, + // but it may not be a type variable after processing obligations + // in our local `FnCtxt`, so don't call `structurally_resolved_type`. let ty = &bad_ty.ty; let ty = self .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); - let ty = self.structurally_resolved_type(span, ty.value); - assert!(matches!(ty.kind(), ty::Error(_))); + let ty = self.resolve_vars_if_possible(ty.value); + let guar = match *ty.kind() { + ty::Infer(ty::TyVar(_)) => self + .err_ctxt() + .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true) + .emit(), + ty::Error(guar) => guar, + _ => bug!("unexpected bad final type in method autoderef"), + }; + self.demand_eqtype(span, ty, self.tcx.ty_error(guar)); return Err(MethodError::NoMatch(NoMatchData { static_candidates: Vec::new(), unsatisfied_predicates: Vec::new(), diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs new file mode 100644 index 0000000000000..d8034d57e8d56 --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.rs @@ -0,0 +1,40 @@ +use std::ops::Deref; +use std::rc::Rc; + +struct Value(T); + +pub trait Wrap { + fn wrap() -> Self; +} + +impl Wrap R> for Value R> { + fn wrap() -> Self { + todo!() + } +} + +impl Wrap for Value R>> { + fn wrap() -> Self { + todo!() + } +} + +impl Deref for Value> { + type Target = F; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +fn main() { + let var_fn = Value::wrap(); + //~^ ERROR type annotations needed for `Value>` + + // The combination of `Value: Wrap` obligation plus the autoderef steps + // (caused by the `Deref` impl above) actually means that the self type + // of the method fn below is constrained to be `Value ?2>>`. + // However, that's only known to us on the error path -- we still need + // to emit an ambiguity error, though. + let _ = var_fn.clone(); +} diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr new file mode 100644 index 0000000000000..06a7e90858ce7 --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `Value>` + --> $DIR/deref-ambiguity-becomes-nonambiguous.rs:31:9 + | +LL | let var_fn = Value::wrap(); + | ^^^^^^ +... +LL | let _ = var_fn.clone(); + | ----- type must be known at this point + | +help: consider giving `var_fn` an explicit type, where the placeholders `_` are specified + | +LL | let var_fn: Value> = Value::wrap(); + | ++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`.