about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2023-05-23 18:10:30 +0200
committerlcnr <rust@lcnr.de>2023-05-30 12:40:35 +0200
commit0a6ae29fe855a07b204c5b0e490c59c3ab3d443a (patch)
treecf963bc458d6921e31d211224b887b8d2f019eaf
parent200ed9f8cd49e823c788b6ce1096030d9c40ec02 (diff)
downloadrust-0a6ae29fe855a07b204c5b0e490c59c3ab3d443a.tar.gz
rust-0a6ae29fe855a07b204c5b0e490c59c3ab3d443a.zip
coherence: don't add hidden types for opaques
we can otherwise assign a hidden type to the opaque which
causes ICE if we don't use `take_opaque_types` during
coherence. This is annoying so I didn't bother. Added a test
showing the behavior this prevents.
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs32
-rw-r--r--tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs25
-rw-r--r--tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr12
3 files changed, 59 insertions, 10 deletions
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 9d5ec228d82..105a3f08c82 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -533,17 +533,29 @@ impl<'tcx> InferCtxt<'tcx> {
         // these are the same span, but not in cases like `-> (impl
         // Foo, impl Bar)`.
         let span = cause.span;
-        let prev = self.inner.borrow_mut().opaque_types().register(
-            opaque_type_key,
-            OpaqueHiddenType { ty: hidden_ty, span },
-            origin,
-        );
-        let mut obligations = if let Some(prev) = prev {
-            self.at(&cause, param_env)
-                .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
-                .obligations
+        let mut obligations = if self.intercrate {
+            // During intercrate we do not define opaque types but instead always
+            // force ambiguity unless the hidden type is known to not implement
+            // our trait.
+            vec![traits::Obligation::new(
+                self.tcx,
+                cause.clone(),
+                param_env,
+                ty::PredicateKind::Ambiguous,
+            )]
         } else {
-            Vec::new()
+            let prev = self.inner.borrow_mut().opaque_types().register(
+                opaque_type_key,
+                OpaqueHiddenType { ty: hidden_ty, span },
+                origin,
+            );
+            if let Some(prev) = prev {
+                self.at(&cause, param_env)
+                    .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
+                    .obligations
+            } else {
+                Vec::new()
+            }
         };
 
         self.add_item_bounds_for_hidden_type(
diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs
new file mode 100644
index 00000000000..39b3d535ad4
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs
@@ -0,0 +1,25 @@
+// When checking whether these two impls overlap, we could detect that we
+// would require the hidden type of `TAIT` to be equal to both `u32` and `i32`
+// and therefore accept them as disjoint. That is annoying to implement with
+// the current system because we would have to add the following to each
+// returning branch in coherence.
+//
+//    let _ = infcx.take_opaque_types();
+//
+// @lcnr: Because of this I decided to not bother and cause this to fail instead.
+// In the future we can definitely modify the compiler to accept this
+// again.
+#![feature(type_alias_impl_trait)]
+
+trait Trait {}
+
+type TAIT = impl Sized;
+
+impl Trait for (TAIT, TAIT) {}
+
+impl Trait for (u32, i32) {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `(TAIT, TAIT)`
+
+fn define() -> TAIT {}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr
new file mode 100644
index 00000000000..f2aee798608
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `(TAIT, TAIT)`
+  --> $DIR/coherence_different_hidden_ty.rs:20:1
+   |
+LL | impl Trait for (TAIT, TAIT) {}
+   | --------------------------- first implementation here
+LL |
+LL | impl Trait for (u32, i32) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(TAIT, TAIT)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.