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.
This commit is contained in:
lcnr 2023-05-23 18:10:30 +02:00
parent 200ed9f8cd
commit 0a6ae29fe8
3 changed files with 59 additions and 10 deletions

View file

@ -533,17 +533,29 @@ fn register_hidden_type(
// 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(

View file

@ -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() {}

View file

@ -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`.