]> git.lizzy.rs Git - rust.git/commitdiff
selection failure: recompute applicable impls
authorlcnr <rust@lcnr.de>
Wed, 19 Oct 2022 15:17:19 +0000 (17:17 +0200)
committerlcnr <rust@lcnr.de>
Tue, 8 Nov 2022 13:48:07 +0000 (14:48 +0100)
21 files changed:
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
compiler/rustc_trait_selection/src/traits/engine.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
src/test/ui/error-codes/E0282.rs
src/test/ui/error-codes/E0401.rs
src/test/ui/error-codes/E0401.stderr
src/test/ui/impl-trait/cross-return-site-inference.rs
src/test/ui/impl-trait/cross-return-site-inference.stderr
src/test/ui/inference/cannot-infer-async.rs
src/test/ui/inference/cannot-infer-closure.rs
src/test/ui/inference/issue-71732.rs
src/test/ui/inference/issue-72616.rs
src/test/ui/inference/issue-72616.stderr
src/test/ui/inference/question-mark-type-infer.rs
src/test/ui/issues/issue-71584.rs
src/test/ui/traits/issue-77982.stderr

index a29f0722ff705056ee9535f5ad3e0a6a158b4246..05382bd887cd9e2bb92b4c706109b21953e43e9c 100644 (file)
@@ -576,9 +576,6 @@ pub enum SelectionError<'tcx> {
     /// Signaling that an error has already been emitted, to avoid
     /// multiple errors being shown.
     ErrorReporting,
-    /// Multiple applicable `impl`s where found. The `DefId`s correspond to
-    /// all the `impl`s' Items.
-    Ambiguous(Vec<DefId>),
 }
 
 /// When performing resolution, it is typically the case that there
index 27090c62d21ed135d895f4c702651ea280a006e3..b509ae6dd3b8527f67b2dcdcf22d160bfc4a2a63 100644 (file)
@@ -2550,11 +2550,11 @@ pub fn is_builtin_derive(self, def_id: DefId) -> bool {
 
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
     /// with the name of the crate containing the impl.
-    pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
-        if let Some(impl_did) = impl_did.as_local() {
-            Ok(self.def_span(impl_did))
+    pub fn span_of_impl(self, impl_def_id: DefId) -> Result<Span, Symbol> {
+        if let Some(impl_def_id) = impl_def_id.as_local() {
+            Ok(self.def_span(impl_def_id))
         } else {
-            Err(self.crate_name(impl_did.krate))
+            Err(self.crate_name(impl_def_id.krate))
         }
     }
 
index 81e1d64493e14f3e84e497865ad19e9a27b2e725..d32a990f182dc45409d12f6ea9077df6e1686626 100644 (file)
@@ -14,6 +14,8 @@ pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
 
     relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+
+    usable_in_snapshot: bool,
 }
 
 impl FulfillmentContext<'_> {
@@ -21,8 +23,13 @@ pub(crate) fn new() -> Self {
         FulfillmentContext {
             obligations: FxIndexSet::default(),
             relationships: FxHashMap::default(),
+            usable_in_snapshot: false,
         }
     }
+
+    pub(crate) fn new_in_snapshot() -> Self {
+        FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
+    }
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
@@ -41,7 +48,9 @@ fn register_predicate_obligation(
         infcx: &InferCtxt<'tcx>,
         obligation: PredicateObligation<'tcx>,
     ) {
-        assert!(!infcx.is_in_snapshot());
+        if !self.usable_in_snapshot {
+            assert!(!infcx.is_in_snapshot());
+        }
         let obligation = infcx.resolve_vars_if_possible(obligation);
 
         super::relationships::update(self, infcx, &obligation);
@@ -72,7 +81,9 @@ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentErr
     }
 
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
-        assert!(!infcx.is_in_snapshot());
+        if !self.usable_in_snapshot {
+            assert!(!infcx.is_in_snapshot());
+        }
 
         let mut errors = Vec::new();
         let mut next_round = FxIndexSet::default();
index 21516c93efb53aa8b33e681938a61c1701f54d35..0eafc49816d49cbbef1bc84a93546fc3bbdb0f0c 100644 (file)
@@ -38,7 +38,7 @@ fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
 
     fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
         if tcx.sess.opts.unstable_opts.chalk {
-            Box::new(ChalkFulfillmentContext::new())
+            Box::new(ChalkFulfillmentContext::new_in_snapshot())
         } else {
             Box::new(FulfillmentContext::new_in_snapshot())
         }
@@ -119,13 +119,10 @@ pub fn eq<T: ToTrace<'tcx>>(
         expected: T,
         actual: T,
     ) -> Result<(), TypeError<'tcx>> {
-        match self.infcx.at(cause, param_env).eq(expected, actual) {
-            Ok(InferOk { obligations, value: () }) => {
-                self.register_obligations(obligations);
-                Ok(())
-            }
-            Err(e) => Err(e),
-        }
+        self.infcx
+            .at(cause, param_env)
+            .eq(expected, actual)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
     pub fn sup<T: ToTrace<'tcx>>(
@@ -144,6 +141,10 @@ pub fn sup<T: ToTrace<'tcx>>(
         }
     }
 
+    pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
+        self.engine.borrow_mut().select_where_possible(self.infcx)
+    }
+
     pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
         self.engine.borrow_mut().select_all_or_error(self.infcx)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
new file mode 100644 (file)
index 0000000..58da54a
--- /dev/null
@@ -0,0 +1,52 @@
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
+use rustc_span::DUMMY_SP;
+
+use crate::traits::ObligationCtxt;
+
+pub fn recompute_applicable_impls<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &TraitObligation<'tcx>,
+) -> Vec<DefId> {
+    let tcx = infcx.tcx;
+    let param_env = obligation.param_env;
+    let dummy_cause = ObligationCause::dummy();
+    let impl_may_apply = |impl_def_id| {
+        let ocx = ObligationCtxt::new_in_snapshot(infcx);
+        let placeholder_obligation =
+            infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+        let obligation_trait_ref =
+            ocx.normalize(dummy_cause.clone(), param_env, placeholder_obligation.trait_ref);
+
+        let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+        let impl_trait_ref = ocx.normalize(ObligationCause::dummy(), param_env, impl_trait_ref);
+
+        if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
+            return false;
+        }
+
+        let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
+        ocx.register_obligations(
+            impl_predicates
+                .predicates
+                .iter()
+                .map(|&predicate| Obligation::new(dummy_cause.clone(), param_env, predicate)),
+        );
+
+        ocx.select_where_possible().is_empty()
+    };
+
+    let mut impls = Vec::new();
+    tcx.for_each_relevant_impl(
+        obligation.predicate.def_id(),
+        obligation.predicate.skip_binder().trait_ref.self_ty(),
+        |impl_def_id| {
+            if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
+                impls.push(impl_def_id)
+            }
+        },
+    );
+    impls
+}
index c7dee4a18ac5dd9ba7f95d949dfb7a9102a6e051..bcb00796cbaba98c380ae063db365868b855c298 100644 (file)
@@ -1,3 +1,4 @@
+mod ambiguity;
 pub mod on_unimplemented;
 pub mod suggestions;
 
@@ -535,15 +536,6 @@ fn report_selection_error(
         let mut span = obligation.cause.span;
 
         let mut err = match *error {
-            SelectionError::Ambiguous(ref impls) => {
-                let mut err = self.tcx.sess.struct_span_err(
-                    obligation.cause.span,
-                    &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
-                );
-                self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
-                err.emit();
-                return;
-            }
             SelectionError::Unimplemented => {
                 // If this obligation was generated as a result of well-formedness checking, see if we
                 // can get a better error message by performing HIR-based well-formedness checking.
@@ -2144,8 +2136,21 @@ fn maybe_report_ambiguity(
                     crate::traits::TraitQueryMode::Standard,
                 );
                 match selcx.select_from_obligation(&obligation) {
-                    Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
-                        self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                    Ok(None) => {
+                        let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+                        let has_non_region_infer =
+                            trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
+                        // It doesn't make sense to talk about applicable impls if there are more
+                        // than a handful of them.
+                        if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
+                            self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                        } else {
+                            if self.is_tainted_by_errors() {
+                                err.cancel();
+                                return;
+                            }
+                            err.note(&format!("cannot satisfy `{}`", predicate));
+                        }
                     }
                     _ => {
                         if self.is_tainted_by_errors() {
@@ -2441,7 +2446,6 @@ fn annotate_source_of_ambiguity(
                 }
             }
         }
-        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
         let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
         crate_names.sort();
         crate_names.dedup();
@@ -2462,13 +2466,9 @@ fn annotate_source_of_ambiguity(
             err.downgrade_to_delayed_bug();
             return;
         }
-        let post = if post.len() > 4 {
-            format!(
-                ":\n{}\nand {} more",
-                post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
-                post.len() - 4,
-            )
-        } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+
+        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
             format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
         } else if post.len() == 1 {
             format!(": `{}`", post[0])
index 4c5bc333961dc76345898a8a8284cf1a53cd7284..3671a0d87df57408b3f5db09a6c032019f5f53cd 100644 (file)
@@ -20,7 +20,7 @@
 use crate::traits::coherence::Conflict;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{util, SelectionResult};
-use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{ErrorReporting, Overflow, Unimplemented};
 
 use super::BuiltinImplConditions;
 use super::IntercrateAmbiguityCause;
@@ -200,15 +200,7 @@ fn candidate_from_obligation_no_cache<'o>(
                     // and report ambiguity.
                     if i > 1 {
                         debug!("multiple matches, ambig");
-                        return Err(Ambiguous(
-                            candidates
-                                .into_iter()
-                                .filter_map(|c| match c.candidate {
-                                    SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
-                                    _ => None,
-                                })
-                                .collect(),
-                        ));
+                        return Ok(None);
                     }
                 }
             }
index 84be1ced520febd20370d7188a7252ad12c377ba..2954a2c163f4072c52e5d17c70f6b429309f27cc 100644 (file)
@@ -294,9 +294,6 @@ pub fn select(
                 assert!(self.query_mode == TraitQueryMode::Canonical);
                 return Err(SelectionError::Overflow(OverflowError::Canonical));
             }
-            Err(SelectionError::Ambiguous(_)) => {
-                return Ok(None);
-            }
             Err(e) => {
                 return Err(e);
             }
@@ -931,7 +928,6 @@ fn evaluate_stack<'o>(
 
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
-            Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
             Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
index 9bd16abb7bb83ab17f4f334c99efcccb8a2a43cd..f1f93b3aed61508d603cad311ebb80ed1d05a80a 100644 (file)
@@ -1,3 +1,4 @@
 fn main() {
-    let x = "hello".chars().rev().collect(); //~ ERROR E0282
+    let x = "hello".chars().rev().collect();
+    //~^ ERROR E0282
 }
index c30e5f47188715df6f6d9d083e4f552ce5095205..8f8d6b87ef209e016d41479d6c6e5553c32aeb76 100644 (file)
@@ -8,7 +8,9 @@ fn baz<U,
            W: Fn()>
            (y: T) { //~ ERROR E0401
     }
-    bfnr(x); //~ ERROR type annotations needed
+    bfnr(x);
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
 }
 
 
index b0e2ef5b6f7e3d65c101e62994552805c9775500..9687eca61fab0b5d16a1968fda5f18defde0bfd9 100644 (file)
@@ -21,7 +21,7 @@ LL |            (y: T) {
    |                ^ use of generic parameter from outer function
 
 error[E0401]: can't use generic parameters from outer function
-  --> $DIR/E0401.rs:22:25
+  --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
    | ---- `Self` type implicitly declared here, by this `impl`
@@ -43,7 +43,28 @@ help: consider specifying the generic arguments
 LL |     bfnr::<U, V, W>(x);
    |         +++++++++++
 
-error: aborting due to 4 previous errors
+error[E0283]: type annotations needed
+  --> $DIR/E0401.rs:11:5
+   |
+LL |     bfnr(x);
+   |     ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
+   |
+   = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`:
+           - impl<A, F> Fn<A> for &F
+             where A: Tuple, F: Fn<A>, F: ?Sized;
+           - impl<Args, F, A> Fn<Args> for Box<F, A>
+             where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
+note: required by a bound in `bfnr`
+  --> $DIR/E0401.rs:4:30
+   |
+LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
+   |                              ^^^^ required by this bound in `bfnr`
+help: consider specifying the type arguments in the function call
+   |
+LL |     bfnr::<U, V, W>(x);
+   |         +++++++++++
+
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0282, E0401.
+Some errors have detailed explanations: E0282, E0283, E0401.
 For more information about an error, try `rustc --explain E0282`.
index d881af9ed8fe13c655fed5ecff9544c72fbb4bf1..00aed2ad95a283c642fbc39e880e130dcba53212 100644 (file)
@@ -30,16 +30,19 @@ fn baa(b: bool) -> impl std::fmt::Debug {
 
 fn muh() -> Result<(), impl std::fmt::Debug> {
     Err("whoops")?;
-    Ok(()) //~ ERROR type annotations needed
+    Ok(())
+    //~^ ERROR type annotations needed
 }
 
 fn muh2() -> Result<(), impl std::fmt::Debug> {
-    return Err(From::from("foo")); //~ ERROR type annotations needed
+    return Err(From::from("foo"));
+    //~^ ERROR type annotations needed
     Ok(())
 }
 
 fn muh3() -> Result<(), impl std::fmt::Debug> {
-    Err(From::from("foo")) //~ ERROR type annotations needed
+    Err(From::from("foo"))
+    //~^ ERROR type annotations needed
 }
 
 fn main() {}
index 1ff777e65037c11b9872c7ded5cee41a4033637d..766614e9e50ffcc9cb2cc5eec08ba336b255375a 100644 (file)
@@ -10,7 +10,7 @@ LL |     Ok::<(), E>(())
    |       +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:37:12
+  --> $DIR/cross-return-site-inference.rs:38:12
    |
 LL |     return Err(From::from("foo"));
    |            ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
@@ -21,7 +21,7 @@ LL |     return Err::<(), E>(From::from("foo"));
    |               +++++++++
 
 error[E0282]: type annotations needed
-  --> $DIR/cross-return-site-inference.rs:42:5
+  --> $DIR/cross-return-site-inference.rs:44:5
    |
 LL |     Err(From::from("foo"))
    |     ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
index e7fabd0ffbc8bd178b4457d0c82598b9c5fbccf7..b5152d04f6959fe511a9db9b2ab52f53a96427b7 100644 (file)
@@ -10,6 +10,7 @@ fn main() {
     let fut = async {
         make_unit()?;
 
-        Ok(()) //~ ERROR type annotations needed
+        Ok(())
+        //~^ ERROR type annotations needed
     };
 }
index 1c350b18f5a6fa0f9ccd457c483e2aa6d5e4fcef..bd5d10b417342ff42205cc35280047474256e2bb 100644 (file)
@@ -1,6 +1,7 @@
 fn main() {
     let x = |a: (), b: ()| {
         Err(a)?;
-        Ok(b) //~ ERROR type annotations needed
+        Ok(b)
+        //~^ ERROR type annotations needed
     };
 }
index 30063a0957c749e42f43372a96b57356ebc1b692..8a9d2b235f0e43c2b63787410cc100f78c405f44 100644 (file)
@@ -15,7 +15,8 @@
 
 fn foo(parameters: &HashMap<String, String>) -> bool {
     parameters
-        .get(&"key".into()) //~ ERROR: type annotations needed
+        .get(&"key".into())
+        //~^ ERROR type annotations needed
         .and_then(|found: &String| Some(false))
         .unwrap_or(false)
 }
index 5e5a3babfe02038a1bc9e784ab3327bc14baa1e0..7b0f5936d84ec15f095e6069eb8ba8177c293085 100644 (file)
@@ -18,7 +18,8 @@ pub fn main() {
     }
     {
         if String::from("a") == "a".try_into().unwrap() {}
-        //~^ ERROR: type annotations needed
+        //~^ ERROR type annotations needed
+        //~| ERROR type annotations needed
     }
     {
         let _: String = match "_".try_into() {
index a71ce9a8ef27af725cbd111f92027f71ee94288d..da1a7ccdee15e5b8e974d74856c8ffa36c4e8629 100644 (file)
@@ -16,6 +16,22 @@ help: try using a fully qualified path to specify the expected types
 LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
    |                                 +++++++++++++++++++++++++++++++   ~
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/issue-72616.rs:20:37
+   |
+LL |         if String::from("a") == "a".try_into().unwrap() {}
+   |                                     ^^^^^^^^
+   |
+   = note: multiple `impl`s satisfying `_: TryFrom<&str>` found in the following crates: `core`, `std`:
+           - impl<> TryFrom<&str> for std::sys_common::net::LookupHost;
+           - impl<T, U> TryFrom<U> for T
+             where U: Into<T>;
+   = note: required for `&str` to implement `TryInto<_>`
+help: try using a fully qualified path to specify the expected types
+   |
+LL |         if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+   |                                 +++++++++++++++++++++++++++++++   ~
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0283`.
index 64333a29313b349d2187441020d27c7326be8c5b..10560f85ed480a67d4012043c9e2f7b6504c28ea 100644 (file)
@@ -7,7 +7,8 @@ fn f(x: &i32) -> Result<i32, ()> {
 
 fn g() -> Result<Vec<i32>, ()> {
     let l = [1, 2, 3, 4];
-    l.iter().map(f).collect()? //~ ERROR type annotations needed
+    l.iter().map(f).collect()?
+    //~^ ERROR type annotations needed
 }
 
 fn main() {
index c96cd598f0ce067dab8619991fc3ad9a72767a1c..7bf3ed60ec104e83e8e83d74d824dadee0d3d4ee 100644 (file)
@@ -1,5 +1,6 @@
 fn main() {
     let n: u32 = 1;
     let mut d: u64 = 2;
-    d = d % n.into(); //~ ERROR type annotations needed
+    d = d % n.into();
+    //~^ ERROR type annotations needed
 }
index e210f11b3e0c12a49439fc5f7144d2c7453802c4..b6a04585583c933079d52ac7c76cffeefe53938e 100644 (file)
@@ -46,12 +46,7 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
    |                                            |
    |                                            required by a bound introduced by this call
    |
-   = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
-           - impl From<Ipv4Addr> for u32;
-           - impl From<NonZeroU32> for u32;
-           - impl From<bool> for u32;
-           - impl From<char> for u32;
-           and 3 more
+   = note: cannot satisfy `u32: From<_>`
 help: try using a fully qualified path to specify the expected types
    |
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();