Skip to content

Commit 65f918b

Browse files
authored
Rollup merge of rust-lang#99666 - compiler-errors:issue-99663, r=lcnr
Restore `Opaque` behavior to coherence check Fixes rust-lang#99663. This broke in 84c3fcd. I'm not exactly certain that adding this behavior back is necessarily correct, but at least the UI test I provided may stimulate some thoughts. I think delaying a bug here is certainly not correct in the case of opaques -- if we want to change coherence behavior for opaques, then we should at least be emitting a new error. r? `@lcnr`
2 parents a35e26d + b7cf9f7 commit 65f918b

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -703,13 +703,42 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
703703
}
704704
}
705705
ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
706-
ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
706+
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
707707
self.tcx.sess.delay_span_bug(
708708
DUMMY_SP,
709709
format!("ty_is_local invoked on closure or generator: {:?}", ty),
710710
);
711711
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
712712
}
713+
ty::Opaque(..) => {
714+
// This merits some explanation.
715+
// Normally, opaque types are not involved when performing
716+
// coherence checking, since it is illegal to directly
717+
// implement a trait on an opaque type. However, we might
718+
// end up looking at an opaque type during coherence checking
719+
// if an opaque type gets used within another type (e.g. as
720+
// the type of a field) when checking for auto trait or `Sized`
721+
// impls. This requires us to decide whether or not an opaque
722+
// type should be considered 'local' or not.
723+
//
724+
// We choose to treat all opaque types as non-local, even
725+
// those that appear within the same crate. This seems
726+
// somewhat surprising at first, but makes sense when
727+
// you consider that opaque types are supposed to hide
728+
// the underlying type *within the same crate*. When an
729+
// opaque type is used from outside the module
730+
// where it is declared, it should be impossible to observe
731+
// anything about it other than the traits that it implements.
732+
//
733+
// The alternative would be to look at the underlying type
734+
// to determine whether or not the opaque type itself should
735+
// be considered local. However, this could make it a breaking change
736+
// to switch the underlying ('defining') type from a local type
737+
// to a remote type. This would violate the rule that opaque
738+
// types should be completely opaque apart from the traits
739+
// that they implement, so we don't use this behavior.
740+
self.found_non_local_ty(ty)
741+
}
713742
};
714743
// A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
715744
// the first type we visit is always the self type.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
struct Outer<T: ?Sized> {
6+
i: InnerSend<T>,
7+
}
8+
9+
type InnerSend<T: ?Sized> = impl Send;
10+
11+
fn constrain<T: ?Sized>() -> InnerSend<T> {
12+
()
13+
}
14+
15+
trait SendMustNotImplDrop {}
16+
17+
#[allow(drop_bounds)]
18+
impl<T: ?Sized + Send + Drop> SendMustNotImplDrop for T {}
19+
20+
impl<T: ?Sized> SendMustNotImplDrop for Outer<T> {}
21+
22+
fn main() {}

src/test/ui/coherence/issue-99663.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
struct Send<T> {
6+
i: InnerSend<T>,
7+
}
8+
9+
type InnerSend<T> = impl Sized;
10+
11+
fn constrain<T>() -> InnerSend<T> {
12+
()
13+
}
14+
15+
trait SendMustNotImplDrop {}
16+
17+
#[allow(drop_bounds)]
18+
impl<T: Drop> SendMustNotImplDrop for T {}
19+
20+
impl<T> SendMustNotImplDrop for Send<T> {}
21+
22+
fn main() {}

src/test/ui/impl-trait/negative-reasoning.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
77
LL | impl AnotherTrait for D<OpaqueType> {
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
99
|
10-
= note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
10+
= note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
1111

1212
error: cannot implement trait on type alias impl trait
1313
--> $DIR/negative-reasoning.rs:19:25

0 commit comments

Comments
 (0)