diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index b6f0addd77107..ee318b127ae66 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -432,7 +432,7 @@ fn orphan_check_trait_ref<'tcx>( } fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec> { - if ty_is_local_constructor(ty, in_crate) { + if ty_is_local_constructor(tcx, ty, in_crate) { vec![] } else if fundamental_ty(ty) { ty.walk_shallow() @@ -451,7 +451,7 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool { } fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool { - ty_is_local_constructor(ty, in_crate) || + ty_is_local_constructor(tcx, ty, in_crate) || fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate)) } @@ -472,7 +472,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.sty { @@ -504,6 +504,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::Adt(def, _) => def_id_is_local(def.did, in_crate), ty::Foreign(did) => def_id_is_local(did, in_crate), + ty::Opaque(did, _) => { + // Check the underlying type that this opaque + // type resolves to. + // This recursion will eventually terminate, + // since we've already managed to successfully + // resolve all opaque types by this point + let real_ty = tcx.type_of(did); + ty_is_local_constructor(tcx, real_ty, in_crate) + } ty::Dynamic(ref tt, ..) => { if let Some(principal) = tt.principal() { @@ -518,8 +527,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { ty::UnnormalizedProjection(..) | ty::Closure(..) | ty::Generator(..) | - ty::GeneratorWitness(..) | - ty::Opaque(..) => { + ty::GeneratorWitness(..) => { bug!("ty_is_local invoked on unexpected type: {:?}", ty) } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index b43881defdb85..c9a40db41dfde 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -395,7 +395,7 @@ impl<'tcx> Graph { /// The parent of a given impl, which is the `DefId` of the trait when the /// impl is a "specialization root". pub fn parent(&self, child: DefId) -> DefId { - *self.parent.get(&child).unwrap() + *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child)) } } diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs new file mode 100644 index 0000000000000..c767578120883 --- /dev/null +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -0,0 +1,23 @@ +// Tests that type alias impls traits do not leak auto-traits for +// the purposes of coherence checking +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait { } +impl OpaqueTrait for T { } +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { () } + +#[derive(Debug)] +struct D(T); + +trait AnotherTrait { } +impl AnotherTrait for T { } + +// This is in error, because we cannot assume that `OpaqueType: !Send`. +// (We treat opaque types as "foreign types" that could grow more impls +// in the future.) +impl AnotherTrait for D { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` +} + +fn main() {} diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr new file mode 100644 index 0000000000000..5e72ca7a47ba1 --- /dev/null +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D`: + --> $DIR/auto-trait.rs:19:1 + | +LL | impl AnotherTrait for T { } + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs new file mode 100644 index 0000000000000..4977f9bdbacd9 --- /dev/null +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -0,0 +1,22 @@ +// Tests that we cannot assume that an opaque type does *not* implement some +// other trait +#![feature(type_alias_impl_trait)] + +trait OpaqueTrait { } +impl OpaqueTrait for T { } +type OpaqueType = impl OpaqueTrait; +fn mk_opaque() -> OpaqueType { () } + +#[derive(Debug)] +struct D(T); + +trait AnotherTrait { } +impl AnotherTrait for T { } + + +// This is in error, because we cannot assume that `OpaqueType: !Debug` +impl AnotherTrait for D { + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` +} + +fn main() {} diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr new file mode 100644 index 0000000000000..526a664726ac2 --- /dev/null +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D`: + --> $DIR/negative-reasoning.rs:18:1 + | +LL | impl AnotherTrait for T { } + | ------------------------------------------- first implementation here +... +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` + | + = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs new file mode 100644 index 0000000000000..52802dd8fbb47 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/auxiliary/foreign-crate.rs @@ -0,0 +1,2 @@ +pub trait ForeignTrait {} +pub struct ForeignType(pub T); diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs new file mode 100644 index 0000000000000..1c0f83d6c12da --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/coherence.rs @@ -0,0 +1,17 @@ +// aux-build:foreign-crate.rs +#![feature(type_alias_impl_trait)] + +extern crate foreign_crate; + +trait LocalTrait {} +impl LocalTrait for foreign_crate::ForeignType {} + +type AliasOfForeignType = impl LocalTrait; +fn use_alias(val: T) -> AliasOfForeignType { + foreign_crate::ForeignType(val) +} + +impl foreign_crate::ForeignTrait for AliasOfForeignType {} +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr new file mode 100644 index 0000000000000..6ede0fa14ba70 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/coherence.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/coherence.rs:14:6 + | +LL | impl foreign_crate::ForeignTrait for AliasOfForeignType {} + | ^ unconstrained type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs new file mode 100644 index 0000000000000..28f4a85c9f290 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs @@ -0,0 +1,21 @@ +// check-pass +// Regression test for issue #63677 - ensure that +// coherence checking can properly handle 'impl trait' +// in type aliases +#![feature(type_alias_impl_trait)] + +pub trait Trait {} +pub struct S1(T); +pub struct S2(T); + +pub type T1 = impl Trait; +pub type T2 = S1; +pub type T3 = S2; + +impl Trait for S1 {} +impl S2 {} +impl T3 {} + +pub fn use_t1() -> T1 { S1(()) } + +fn main() {}