Skip to content

Commit

Permalink
Rollup merge of rust-lang#95979 - lcnr:coherence-docs, r=compiler-errors
Browse files Browse the repository at this point in the history
update coherence docs, fix generator + opaque type ICE

the world is confusing, this makes it slightly less so
  • Loading branch information
Dylan-DPC authored May 18, 2022
2 parents 64c58a1 + 58781ed commit 04f9038
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 22 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ pub enum Reveal {
/// let x: <() as Assoc>::Output = true;
/// }
/// ```
///
/// We also do not reveal the hidden type of opaque types during
/// type-checking.
UserFacing,

/// At codegen time, all monomorphic projections will succeed.
Expand Down
27 changes: 17 additions & 10 deletions compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ fn orphan_check_trait_ref<'tcx>(
.substs
.types()
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
.find(|ty| ty_is_local_constructor(*ty, in_crate));
.find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));

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

Expand Down Expand Up @@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
ty: Ty<'tcx>,
in_crate: InCrate,
) -> Vec<Ty<'tcx>> {
if ty_is_local_constructor(ty, in_crate) {
if ty_is_local_constructor(tcx, ty, in_crate) {
Vec::new()
} else {
match fundamental_ty_inner_tys(tcx, ty) {
Expand Down Expand Up @@ -730,7 +730,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
}
}

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

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

ty::Closure(..) => {
// Similar to the `Opaque` case (#83613).
false
}

ty::Dynamic(ref tt, ..) => {
if let Some(principal) = tt.principal() {
def_id_is_local(principal.def_id(), in_crate)
Expand All @@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {

ty::Error(_) => true,

ty::Generator(..) | ty::GeneratorWitness(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
// These variants should never appear during coherence checking because they
// cannot be named directly.
//
// They could be indirectly used through an opaque type. While using opaque types
// in impls causes an error, this path can still be hit afterwards.
//
// See `test/ui/coherence/coherence-with-closure.rs` for an example where this
// could happens.
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
tcx.sess.delay_span_bug(
DUMMY_SP,
format!("ty_is_local invoked on closure or generator: {:?}", ty),
);
true
}
}
}
30 changes: 18 additions & 12 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
/// require themselves.
freshener: TypeFreshener<'cx, 'tcx>,

/// If `true`, indicates that the evaluation should be conservative
/// and consider the possibility of types outside this crate.
/// During coherence we have to assume that other crates may add
/// additional impls which we currently don't know about.
///
/// To deal with this evaluation should be conservative
/// and consider the possibility of impls from outside this crate.
/// This comes up primarily when resolving ambiguity. Imagine
/// there is some trait reference `$0: Bar` where `$0` is an
/// inference variable. If `intercrate` is true, then we can never
/// say for sure that this reference is not implemented, even if
/// there are *no impls at all for `Bar`*, because `$0` could be
/// bound to some type that in a downstream crate that implements
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
/// though, we set this to false, because we are only interested
/// in types that the user could actually have written --- in
/// other words, we consider `$0: Bar` to be unimplemented if
/// `Bar`.
///
/// Outside of coherence we set this to false because we are only
/// interested in types that the user could actually have written.
/// In other words, we consider `$0: Bar` to be unimplemented if
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
intercrate: bool,

/// If `intercrate` is set, we remember predicates which were
/// considered ambiguous because of impls potentially added in other crates.
/// This is used in coherence to give improved diagnostics.
/// We don't do his until we detect a coherence error because it can
/// lead to false overflow results (#47139) and because always
/// computing it may negatively impact performance.
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,

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

/// Enables tracking of intercrate ambiguity causes. These are
/// used in coherence to give improved diagnostics. We don't do
/// this until we detect a coherence error because it can lead to
/// false overflow results (#47139) and because it costs
/// computation time.
/// Enables tracking of intercrate ambiguity causes. See
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
assert!(self.intercrate);
assert!(self.intercrate_ambiguity_causes.is_none());
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/coherence/coherence-with-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Test that encountering closures during coherence does not cause issues.
#![feature(type_alias_impl_trait)]
type OpaqueClosure = impl Sized;
fn defining_use() -> OpaqueClosure {
|| ()
}

struct Wrapper<T>(T);
trait Trait {}
impl Trait for Wrapper<OpaqueClosure> {}
//~^ ERROR cannot implement trait on type alias impl trait
impl<T: Sync> Trait for Wrapper<T> {}
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`

fn main() {}
24 changes: 24 additions & 0 deletions src/test/ui/coherence/coherence-with-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: cannot implement trait on type alias impl trait
--> $DIR/coherence-with-closure.rs:10:24
|
LL | impl Trait for Wrapper<OpaqueClosure> {}
| ^^^^^^^^^^^^^
|
note: type alias impl trait defined here
--> $DIR/coherence-with-closure.rs:3:22
|
LL | type OpaqueClosure = impl Sized;
| ^^^^^^^^^^

error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
--> $DIR/coherence-with-closure.rs:12:1
|
LL | impl Trait for Wrapper<OpaqueClosure> {}
| ------------------------------------- first implementation here
LL |
LL | impl<T: Sync> Trait for Wrapper<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0119`.
19 changes: 19 additions & 0 deletions src/test/ui/coherence/coherence-with-generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Test that encountering closures during coherence does not cause issues.
#![feature(type_alias_impl_trait, generators)]
type OpaqueGenerator = impl Sized;
fn defining_use() -> OpaqueGenerator {
|| {
for i in 0..10 {
yield i;
}
}
}

struct Wrapper<T>(T);
trait Trait {}
impl Trait for Wrapper<OpaqueGenerator> {}
//~^ ERROR cannot implement trait on type alias impl trait
impl<T: Sync> Trait for Wrapper<T> {}
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`

fn main() {}
24 changes: 24 additions & 0 deletions src/test/ui/coherence/coherence-with-generator.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: cannot implement trait on type alias impl trait
--> $DIR/coherence-with-generator.rs:14:24
|
LL | impl Trait for Wrapper<OpaqueGenerator> {}
| ^^^^^^^^^^^^^^^
|
note: type alias impl trait defined here
--> $DIR/coherence-with-generator.rs:3:24
|
LL | type OpaqueGenerator = impl Sized;
| ^^^^^^^^^^

error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
--> $DIR/coherence-with-generator.rs:16:1
|
LL | impl Trait for Wrapper<OpaqueGenerator> {}
| --------------------------------------- first implementation here
LL |
LL | impl<T: Sync> Trait for Wrapper<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0119`.

0 comments on commit 04f9038

Please sign in to comment.