about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-02-17 16:58:18 +0100
committerLeón Orell Valerian Liehr <me@fmease.dev>2023-02-19 18:35:35 +0100
commit6065867a7e4379a12e495912a41318f871104270 (patch)
tree095b05e57a8486ac81744e40bcb9102b3dfb3339
parent3dc38fbc9115f0e8cf61848938e05e1964ee29bf (diff)
downloadrust-6065867a7e4379a12e495912a41318f871104270.tar.gz
rust-6065867a7e4379a12e495912a41318f871104270.zip
Use InferCtxt::probe to properly detect ambiguous candidates
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs47
-rw-r--r--tests/ui/associated-inherent-types/ambiguity.rs16
-rw-r--r--tests/ui/associated-inherent-types/ambiguity.stderr20
3 files changed, 62 insertions, 21 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index c8ff609dea5..c22ebc1c659 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2235,35 +2235,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let mut applicable_candidates: Vec<_> = candidates
             .iter()
             .filter_map(|&(impl_, (assoc_item, def_scope))| {
-                let ocx = ObligationCtxt::new(&infcx);
+                infcx.probe(|_| {
+                    let ocx = ObligationCtxt::new_in_snapshot(&infcx);
 
-                let impl_ty = tcx.type_of(impl_);
-                let impl_substs = self.fresh_item_substs(impl_, &infcx);
-                let impl_ty = impl_ty.subst(tcx, impl_substs);
-                let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
+                    let impl_ty = tcx.type_of(impl_);
+                    let impl_substs = self.fresh_item_substs(impl_, &infcx);
+                    let impl_ty = impl_ty.subst(tcx, impl_substs);
+                    let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
 
-                // Check that the Self-types can be related.
-                // FIXME(fmease): Should we use `eq` here?
-                ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
+                    // Check that the Self-types can be related.
+                    // FIXME(fmease): Should we use `eq` here?
+                    ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
 
-                // Check whether the impl imposes obligations we have to worry about.
-                let impl_bounds = tcx.predicates_of(impl_);
-                let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
+                    // Check whether the impl imposes obligations we have to worry about.
+                    let impl_bounds = tcx.predicates_of(impl_);
+                    let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
 
-                let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
+                    let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
 
-                let impl_obligations =
-                    traits::predicates_for_generics(|_, _| cause.clone(), param_env, impl_bounds);
+                    let impl_obligations = traits::predicates_for_generics(
+                        |_, _| cause.clone(),
+                        param_env,
+                        impl_bounds,
+                    );
 
-                ocx.register_obligations(impl_obligations);
+                    ocx.register_obligations(impl_obligations);
 
-                let errors = ocx.select_where_possible();
-                if !errors.is_empty() {
-                    fulfillment_errors = errors;
-                    return None;
-                }
+                    let errors = ocx.select_where_possible();
+                    if !errors.is_empty() {
+                        fulfillment_errors = errors;
+                        return None;
+                    }
 
-                Some((assoc_item, def_scope))
+                    Some((assoc_item, def_scope))
+                })
             })
             .collect();
 
diff --git a/tests/ui/associated-inherent-types/ambiguity.rs b/tests/ui/associated-inherent-types/ambiguity.rs
new file mode 100644
index 00000000000..73920555b3e
--- /dev/null
+++ b/tests/ui/associated-inherent-types/ambiguity.rs
@@ -0,0 +1,16 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct Wrapper<T>(T);
+
+impl Wrapper<i32> {
+    type Foo = i32;
+}
+
+impl Wrapper<()> {
+    type Foo = ();
+}
+
+fn main() {
+    let _: Wrapper<_>::Foo = (); //~ ERROR multiple applicable items in scope
+}
diff --git a/tests/ui/associated-inherent-types/ambiguity.stderr b/tests/ui/associated-inherent-types/ambiguity.stderr
new file mode 100644
index 00000000000..155c296cbb3
--- /dev/null
+++ b/tests/ui/associated-inherent-types/ambiguity.stderr
@@ -0,0 +1,20 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/ambiguity.rs:15:24
+   |
+LL |     let _: Wrapper<_>::Foo = ();
+   |                        ^^^ multiple `Foo` found
+   |
+note: candidate #1 is defined in an impl for the type `Wrapper<i32>`
+  --> $DIR/ambiguity.rs:7:5
+   |
+LL |     type Foo = i32;
+   |     ^^^^^^^^
+note: candidate #2 is defined in an impl for the type `Wrapper<()>`
+  --> $DIR/ambiguity.rs:11:5
+   |
+LL |     type Foo = ();
+   |     ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0034`.