Skip to content

Commit 94628af

Browse files
authored
Rollup merge of rust-lang#63934 - Aaron1011:fix/impl-trait-coherence, r=nikomatsakis
Fix coherence checking for impl trait in type aliases **UPDATE**: This PR now treats all opaque types as remote. The original description appears below, but is no longer accurate. Fixes rust-lang#63677 [RFC 2071](rust-lang/rfcs#2071) (impl-trait-existential-types) does not explicitly state how `type_alias_impl_trait` should interact with coherence. However, there's only one choice which makes sense - coherence should look at the underlying type (i.e. the *"defining"* type of the `impl Trait`) of the type alias, just like we do for non-`impl Trait` type aliases. Specifically, `impl Trait` type aliases that resolve to a local type should be treated like a local type with respect to coherence (e.g. `impl Trait` type aliases which resolve to a foreign type should be treated as a foreign type, and those that resolve to a local type should be treated as a local type). Since neither inherent impls nor direct trait impl (i.e. `impl MyType` or `impl MyTrait for MyType`) are allowed for type aliases, this usually does not come up. Before we ever attempt to do coherence checking, we will have errored out if an `impl Trait` type alias was used directly in an `impl` clause. However, during trait selection, we sometimes need to prove bounds like `T: Sized` for some type `T`. If `T` is an impl trait type alias, this requires to know the coherence behavior for `impl Trait` type aliases when we perform coherence checking. Note: Since determining the underlying type of an `impl Trait` type alias requires us to perform body type checking, this commit causes us to type check some bodies easier than we otherwise would have. However, since this is done through a query, this shouldn't cause any problems For completeness, I've added an additional test of the coherence-related behavior of `impl Trait` type aliases. cc rust-lang#63063
2 parents c623aa4 + 61cfe92 commit 94628af

File tree

10 files changed

+134
-6
lines changed

10 files changed

+134
-6
lines changed

src/librustc/traits/coherence.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ fn orphan_check_trait_ref<'tcx>(
432432
}
433433

434434
fn uncovered_tys<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
435-
if ty_is_local_constructor(ty, in_crate) {
435+
if ty_is_local_constructor(tcx, ty, in_crate) {
436436
vec![]
437437
} else if fundamental_ty(ty) {
438438
ty.walk_shallow()
@@ -451,7 +451,7 @@ fn is_possibly_remote_type(ty: Ty<'_>, _in_crate: InCrate) -> bool {
451451
}
452452

453453
fn ty_is_local(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
454-
ty_is_local_constructor(ty, in_crate) ||
454+
ty_is_local_constructor(tcx, ty, in_crate) ||
455455
fundamental_ty(ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
456456
}
457457

@@ -472,7 +472,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
472472
}
473473
}
474474

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

478478
match ty.sty {
@@ -504,6 +504,15 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
504504

505505
ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
506506
ty::Foreign(did) => def_id_is_local(did, in_crate),
507+
ty::Opaque(did, _) => {
508+
// Check the underlying type that this opaque
509+
// type resolves to.
510+
// This recursion will eventually terminate,
511+
// since we've already managed to successfully
512+
// resolve all opaque types by this point
513+
let real_ty = tcx.type_of(did);
514+
ty_is_local_constructor(tcx, real_ty, in_crate)
515+
}
507516

508517
ty::Dynamic(ref tt, ..) => {
509518
if let Some(principal) = tt.principal() {
@@ -518,8 +527,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
518527
ty::UnnormalizedProjection(..) |
519528
ty::Closure(..) |
520529
ty::Generator(..) |
521-
ty::GeneratorWitness(..) |
522-
ty::Opaque(..) => {
530+
ty::GeneratorWitness(..) => {
523531
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
524532
}
525533
}

src/librustc/traits/specialize/specialization_graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ impl<'tcx> Graph {
395395
/// The parent of a given impl, which is the `DefId` of the trait when the
396396
/// impl is a "specialization root".
397397
pub fn parent(&self, child: DefId) -> DefId {
398-
*self.parent.get(&child).unwrap()
398+
*self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
399399
}
400400
}
401401

src/test/ui/impl-trait/auto-trait.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Tests that type alias impls traits do not leak auto-traits for
2+
// the purposes of coherence checking
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait OpaqueTrait { }
6+
impl<T> OpaqueTrait for T { }
7+
type OpaqueType = impl OpaqueTrait;
8+
fn mk_opaque() -> OpaqueType { () }
9+
10+
#[derive(Debug)]
11+
struct D<T>(T);
12+
13+
trait AnotherTrait { }
14+
impl<T: Send> AnotherTrait for T { }
15+
16+
// This is in error, because we cannot assume that `OpaqueType: !Send`.
17+
// (We treat opaque types as "foreign types" that could grow more impls
18+
// in the future.)
19+
impl AnotherTrait for D<OpaqueType> {
20+
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
21+
}
22+
23+
fn main() {}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
2+
--> $DIR/auto-trait.rs:19:1
3+
|
4+
LL | impl<T: Send> AnotherTrait for T { }
5+
| -------------------------------- first implementation here
6+
...
7+
LL | impl AnotherTrait for D<OpaqueType> {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Tests that we cannot assume that an opaque type does *not* implement some
2+
// other trait
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait OpaqueTrait { }
6+
impl<T> OpaqueTrait for T { }
7+
type OpaqueType = impl OpaqueTrait;
8+
fn mk_opaque() -> OpaqueType { () }
9+
10+
#[derive(Debug)]
11+
struct D<T>(T);
12+
13+
trait AnotherTrait { }
14+
impl<T: std::fmt::Debug> AnotherTrait for T { }
15+
16+
17+
// This is in error, because we cannot assume that `OpaqueType: !Debug`
18+
impl AnotherTrait for D<OpaqueType> {
19+
//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`:
2+
--> $DIR/negative-reasoning.rs:18:1
3+
|
4+
LL | impl<T: std::fmt::Debug> AnotherTrait for T { }
5+
| ------------------------------------------- first implementation here
6+
...
7+
LL | impl AnotherTrait for D<OpaqueType> {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
9+
|
10+
= note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub trait ForeignTrait {}
2+
pub struct ForeignType<T>(pub T);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// aux-build:foreign-crate.rs
2+
#![feature(type_alias_impl_trait)]
3+
4+
extern crate foreign_crate;
5+
6+
trait LocalTrait {}
7+
impl<T> LocalTrait for foreign_crate::ForeignType<T> {}
8+
9+
type AliasOfForeignType<T> = impl LocalTrait;
10+
fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
11+
foreign_crate::ForeignType(val)
12+
}
13+
14+
impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
15+
//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
2+
--> $DIR/coherence.rs:14:6
3+
|
4+
LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
5+
| ^ unconstrained type parameter
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0207`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// check-pass
2+
// Regression test for issue #63677 - ensure that
3+
// coherence checking can properly handle 'impl trait'
4+
// in type aliases
5+
#![feature(type_alias_impl_trait)]
6+
7+
pub trait Trait {}
8+
pub struct S1<T>(T);
9+
pub struct S2<T>(T);
10+
11+
pub type T1 = impl Trait;
12+
pub type T2 = S1<T1>;
13+
pub type T3 = S2<T2>;
14+
15+
impl<T> Trait for S1<T> {}
16+
impl<T: Trait> S2<T> {}
17+
impl T3 {}
18+
19+
pub fn use_t1() -> T1 { S1(()) }
20+
21+
fn main() {}

0 commit comments

Comments
 (0)