Skip to content

Commit 58781ed

Browse files
committed
update coherence docs, fix opaque type + generator ice
1 parent 1491e5c commit 58781ed

File tree

7 files changed

+120
-22
lines changed

7 files changed

+120
-22
lines changed

compiler/rustc_middle/src/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pub enum Reveal {
6060
/// let <() as Assoc>::Output = true;
6161
/// }
6262
/// ```
63+
///
64+
/// We also do not reveal the hidden type of opaque types during
65+
/// type-checking.
6366
UserFacing,
6467

6568
/// At codegen time, all monomorphic projections will succeed.

compiler/rustc_trait_selection/src/traits/coherence.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ fn orphan_check_trait_ref<'tcx>(
645645
.substs
646646
.types()
647647
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
648-
.find(|ty| ty_is_local_constructor(*ty, in_crate));
648+
.find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
649649

650650
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
651651

@@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
677677
ty: Ty<'tcx>,
678678
in_crate: InCrate,
679679
) -> Vec<Ty<'tcx>> {
680-
if ty_is_local_constructor(ty, in_crate) {
680+
if ty_is_local_constructor(tcx, ty, in_crate) {
681681
Vec::new()
682682
} else {
683683
match fundamental_ty_inner_tys(tcx, ty) {
@@ -730,7 +730,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
730730
}
731731
}
732732

733-
fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
733+
fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
734734
debug!("ty_is_local_constructor({:?})", ty);
735735

736736
match *ty.kind() {
@@ -789,11 +789,6 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
789789
false
790790
}
791791

792-
ty::Closure(..) => {
793-
// Similar to the `Opaque` case (#83613).
794-
false
795-
}
796-
797792
ty::Dynamic(ref tt, ..) => {
798793
if let Some(principal) = tt.principal() {
799794
def_id_is_local(principal.def_id(), in_crate)
@@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
804799

805800
ty::Error(_) => true,
806801

807-
ty::Generator(..) | ty::GeneratorWitness(..) => {
808-
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
802+
// These variants should never appear during coherence checking because they
803+
// cannot be named directly.
804+
//
805+
// They could be indirectly used through an opaque type. While using opaque types
806+
// in impls causes an error, this path can still be hit afterwards.
807+
//
808+
// See `test/ui/coherence/coherence-with-closure.rs` for an example where this
809+
// could happens.
810+
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
811+
tcx.sess.delay_span_bug(
812+
DUMMY_SP,
813+
format!("ty_is_local invoked on closure or generator: {:?}", ty),
814+
);
815+
true
809816
}
810817
}
811818
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
103103
/// require themselves.
104104
freshener: TypeFreshener<'cx, 'tcx>,
105105

106-
/// If `true`, indicates that the evaluation should be conservative
107-
/// and consider the possibility of types outside this crate.
106+
/// During coherence we have to assume that other crates may add
107+
/// additional impls which we currently don't know about.
108+
///
109+
/// To deal with this evaluation should be conservative
110+
/// and consider the possibility of impls from outside this crate.
108111
/// This comes up primarily when resolving ambiguity. Imagine
109112
/// there is some trait reference `$0: Bar` where `$0` is an
110113
/// inference variable. If `intercrate` is true, then we can never
111114
/// say for sure that this reference is not implemented, even if
112115
/// there are *no impls at all for `Bar`*, because `$0` could be
113116
/// bound to some type that in a downstream crate that implements
114-
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
115-
/// though, we set this to false, because we are only interested
116-
/// in types that the user could actually have written --- in
117-
/// other words, we consider `$0: Bar` to be unimplemented if
117+
/// `Bar`.
118+
///
119+
/// Outside of coherence we set this to false because we are only
120+
/// interested in types that the user could actually have written.
121+
/// In other words, we consider `$0: Bar` to be unimplemented if
118122
/// there is no type that the user could *actually name* that
119123
/// would satisfy it. This avoids crippling inference, basically.
120124
intercrate: bool,
121-
125+
/// If `intercrate` is set, we remember predicates which were
126+
/// considered ambiguous because of impls potentially added in other crates.
127+
/// This is used in coherence to give improved diagnostics.
128+
/// We don't do his until we detect a coherence error because it can
129+
/// lead to false overflow results (#47139) and because always
130+
/// computing it may negatively impact performance.
122131
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
123132

124133
/// The mode that trait queries run in, which informs our error handling
@@ -240,11 +249,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
240249
}
241250
}
242251

243-
/// Enables tracking of intercrate ambiguity causes. These are
244-
/// used in coherence to give improved diagnostics. We don't do
245-
/// this until we detect a coherence error because it can lead to
246-
/// false overflow results (#47139) and because it costs
247-
/// computation time.
252+
/// Enables tracking of intercrate ambiguity causes. See
253+
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
248254
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
249255
assert!(self.intercrate);
250256
assert!(self.intercrate_ambiguity_causes.is_none());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Test that encountering closures during coherence does not cause issues.
2+
#![feature(type_alias_impl_trait)]
3+
type OpaqueClosure = impl Sized;
4+
fn defining_use() -> OpaqueClosure {
5+
|| ()
6+
}
7+
8+
struct Wrapper<T>(T);
9+
trait Trait {}
10+
impl Trait for Wrapper<OpaqueClosure> {}
11+
//~^ ERROR cannot implement trait on type alias impl trait
12+
impl<T: Sync> Trait for Wrapper<T> {}
13+
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/coherence-with-closure.rs:10:24
3+
|
4+
LL | impl Trait for Wrapper<OpaqueClosure> {}
5+
| ^^^^^^^^^^^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/coherence-with-closure.rs:3:22
9+
|
10+
LL | type OpaqueClosure = impl Sized;
11+
| ^^^^^^^^^^
12+
13+
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
14+
--> $DIR/coherence-with-closure.rs:12:1
15+
|
16+
LL | impl Trait for Wrapper<OpaqueClosure> {}
17+
| ------------------------------------- first implementation here
18+
LL |
19+
LL | impl<T: Sync> Trait for Wrapper<T> {}
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
21+
22+
error: aborting due to 2 previous errors
23+
24+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test that encountering closures during coherence does not cause issues.
2+
#![feature(type_alias_impl_trait, generators)]
3+
type OpaqueGenerator = impl Sized;
4+
fn defining_use() -> OpaqueGenerator {
5+
|| {
6+
for i in 0..10 {
7+
yield i;
8+
}
9+
}
10+
}
11+
12+
struct Wrapper<T>(T);
13+
trait Trait {}
14+
impl Trait for Wrapper<OpaqueGenerator> {}
15+
//~^ ERROR cannot implement trait on type alias impl trait
16+
impl<T: Sync> Trait for Wrapper<T> {}
17+
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/coherence-with-generator.rs:14:24
3+
|
4+
LL | impl Trait for Wrapper<OpaqueGenerator> {}
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/coherence-with-generator.rs:3:24
9+
|
10+
LL | type OpaqueGenerator = impl Sized;
11+
| ^^^^^^^^^^
12+
13+
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
14+
--> $DIR/coherence-with-generator.rs:16:1
15+
|
16+
LL | impl Trait for Wrapper<OpaqueGenerator> {}
17+
| --------------------------------------- first implementation here
18+
LL |
19+
LL | impl<T: Sync> Trait for Wrapper<T> {}
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
21+
22+
error: aborting due to 2 previous errors
23+
24+
For more information about this error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)