update coherence docs, fix opaque type + generator ice
This commit is contained in:
parent
1491e5cc14
commit
58781edc54
7 changed files with 120 additions and 22 deletions
|
@ -60,6 +60,9 @@ pub enum Reveal {
|
||||||
/// let <() as Assoc>::Output = true;
|
/// let <() as Assoc>::Output = true;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// We also do not reveal the hidden type of opaque types during
|
||||||
|
/// type-checking.
|
||||||
UserFacing,
|
UserFacing,
|
||||||
|
|
||||||
/// At codegen time, all monomorphic projections will succeed.
|
/// At codegen time, all monomorphic projections will succeed.
|
||||||
|
|
|
@ -645,7 +645,7 @@ fn orphan_check_trait_ref<'tcx>(
|
||||||
.substs
|
.substs
|
||||||
.types()
|
.types()
|
||||||
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
|
.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);
|
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
|
||||||
|
|
||||||
|
@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
in_crate: InCrate,
|
in_crate: InCrate,
|
||||||
) -> Vec<Ty<'tcx>> {
|
) -> Vec<Ty<'tcx>> {
|
||||||
if ty_is_local_constructor(ty, in_crate) {
|
if ty_is_local_constructor(tcx, ty, in_crate) {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
match fundamental_ty_inner_tys(tcx, ty) {
|
match fundamental_ty_inner_tys(tcx, ty) {
|
||||||
|
@ -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);
|
debug!("ty_is_local_constructor({:?})", ty);
|
||||||
|
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
|
@ -789,11 +789,6 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Closure(..) => {
|
|
||||||
// Similar to the `Opaque` case (#83613).
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Dynamic(ref tt, ..) => {
|
ty::Dynamic(ref tt, ..) => {
|
||||||
if let Some(principal) = tt.principal() {
|
if let Some(principal) = tt.principal() {
|
||||||
def_id_is_local(principal.def_id(), in_crate)
|
def_id_is_local(principal.def_id(), in_crate)
|
||||||
|
@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||||
|
|
||||||
ty::Error(_) => true,
|
ty::Error(_) => true,
|
||||||
|
|
||||||
ty::Generator(..) | ty::GeneratorWitness(..) => {
|
// These variants should never appear during coherence checking because they
|
||||||
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
|
||||||
/// require themselves.
|
/// require themselves.
|
||||||
freshener: TypeFreshener<'cx, 'tcx>,
|
freshener: TypeFreshener<'cx, 'tcx>,
|
||||||
|
|
||||||
/// If `true`, indicates that the evaluation should be conservative
|
/// During coherence we have to assume that other crates may add
|
||||||
/// and consider the possibility of types outside this crate.
|
/// 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
|
/// This comes up primarily when resolving ambiguity. Imagine
|
||||||
/// there is some trait reference `$0: Bar` where `$0` is an
|
/// there is some trait reference `$0: Bar` where `$0` is an
|
||||||
/// inference variable. If `intercrate` is true, then we can never
|
/// inference variable. If `intercrate` is true, then we can never
|
||||||
/// say for sure that this reference is not implemented, even if
|
/// say for sure that this reference is not implemented, even if
|
||||||
/// there are *no impls at all for `Bar`*, because `$0` could be
|
/// there are *no impls at all for `Bar`*, because `$0` could be
|
||||||
/// bound to some type that in a downstream crate that implements
|
/// bound to some type that in a downstream crate that implements
|
||||||
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
|
/// `Bar`.
|
||||||
/// though, we set this to false, because we are only interested
|
///
|
||||||
/// in types that the user could actually have written --- in
|
/// Outside of coherence we set this to false because we are only
|
||||||
/// other words, we consider `$0: Bar` to be unimplemented if
|
/// 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
|
/// there is no type that the user could *actually name* that
|
||||||
/// would satisfy it. This avoids crippling inference, basically.
|
/// would satisfy it. This avoids crippling inference, basically.
|
||||||
intercrate: bool,
|
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>>,
|
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
|
||||||
|
|
||||||
/// The mode that trait queries run in, which informs our error handling
|
/// The mode that trait queries run in, which informs our error handling
|
||||||
|
@ -240,11 +249,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables tracking of intercrate ambiguity causes. These are
|
/// Enables tracking of intercrate ambiguity causes. See
|
||||||
/// used in coherence to give improved diagnostics. We don't do
|
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
|
||||||
/// this until we detect a coherence error because it can lead to
|
|
||||||
/// false overflow results (#47139) and because it costs
|
|
||||||
/// computation time.
|
|
||||||
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
|
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
|
||||||
assert!(self.intercrate);
|
assert!(self.intercrate);
|
||||||
assert!(self.intercrate_ambiguity_causes.is_none());
|
assert!(self.intercrate_ambiguity_causes.is_none());
|
||||||
|
|
15
src/test/ui/coherence/coherence-with-closure.rs
Normal file
15
src/test/ui/coherence/coherence-with-closure.rs
Normal file
|
@ -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
src/test/ui/coherence/coherence-with-closure.stderr
Normal file
24
src/test/ui/coherence/coherence-with-closure.stderr
Normal file
|
@ -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
src/test/ui/coherence/coherence-with-generator.rs
Normal file
19
src/test/ui/coherence/coherence-with-generator.rs
Normal file
|
@ -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
src/test/ui/coherence/coherence-with-generator.stderr
Normal file
24
src/test/ui/coherence/coherence-with-generator.stderr
Normal file
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue