From 7d5bbf55f22c91f966a0feb130b5ff476da4f017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 22 Jul 2021 20:21:48 +0200 Subject: [PATCH] prevent opaque types from appearing in impl headers --- compiler/rustc_typeck/src/coherence/orphan.rs | 23 ++++++++++----- src/test/ui/impl-trait/auto-trait.rs | 1 + src/test/ui/impl-trait/auto-trait.stderr | 14 ++++++++- src/test/ui/impl-trait/negative-reasoning.rs | 1 + .../ui/impl-trait/negative-reasoning.stderr | 14 ++++++++- ...ias-impl-trait-declaration-too-subtle-2.rs | 3 +- ...impl-trait-declaration-too-subtle-2.stderr | 16 +++++----- ...alias-impl-trait-declaration-too-subtle.rs | 4 +-- ...s-impl-trait-declaration-too-subtle.stderr | 29 ++++++------------- .../nested-tait-inference3.rs | 2 +- .../nested-tait-inference3.stderr | 10 +++++-- 11 files changed, 73 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 4b23cc4db85..564c3d31368 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -141,13 +141,22 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua } } - if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { - let reported = tcx - .sess - .struct_span_err(sp, "cannot implement trait on type alias impl trait") - .span_note(tcx.def_span(def_id), "type alias impl trait defined here") - .emit(); - return Err(reported); + // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, + // and #84660 where it would otherwise allow unsoundness. + if trait_ref.has_opaque_types() { + for ty in trait_ref.substs { + for ty in ty.walk() { + let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue }; + let ty::Opaque(def_id, _) = ty.kind() else { continue }; + let reported = tcx + .sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note(tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + return Err(reported); + } + } + span_bug!(sp, "opque type not found, but `has_opaque_types` is set") } Ok(()) diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs index 35994e4a5ba..afa95645a27 100644 --- a/src/test/ui/impl-trait/auto-trait.rs +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -20,6 +20,7 @@ impl AnotherTrait for T {} // in the future.) impl AnotherTrait for D { //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D` + //~| ERROR cannot implement trait on type alias impl trait } fn main() {} diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr index 81009413c9a..9171cfca5b1 100644 --- a/src/test/ui/impl-trait/auto-trait.stderr +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -1,3 +1,15 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/auto-trait.rs:21:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/auto-trait.rs:7:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D` --> $DIR/auto-trait.rs:21:1 | @@ -7,6 +19,6 @@ LL | impl AnotherTrait for T {} LL | impl AnotherTrait for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D` -error: aborting due to previous error +error: aborting due to 2 previous errors 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 index 70e24a3a9d0..da69bb349ae 100644 --- a/src/test/ui/impl-trait/negative-reasoning.rs +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -18,6 +18,7 @@ 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` + //~| ERROR cannot implement trait on type alias impl trait } fn main() {} diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr index 6b8cc9e7374..1a7233bca5c 100644 --- a/src/test/ui/impl-trait/negative-reasoning.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -1,3 +1,15 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/negative-reasoning.rs:19:1 + | +LL | impl AnotherTrait for D { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/negative-reasoning.rs:7:19 + | +LL | type OpaqueType = impl OpaqueTrait; + | ^^^^^^^^^^^^^^^^ + error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D` --> $DIR/negative-reasoning.rs:19:1 | @@ -9,6 +21,6 @@ LL | impl AnotherTrait 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 +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs index 6b200d7e3a8..621c4ea6e0d 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -5,13 +5,14 @@ type Foo = impl PartialEq<(Foo, i32)>; struct Bar; impl PartialEq<(Foo, i32)> for Bar { +//~^ ERROR cannot implement trait on type alias impl trait fn eq(&self, _other: &(Foo, i32)) -> bool { true } } fn foo() -> Foo { - Bar //~ ERROR can't compare `Bar` with `(Bar, i32)` + Bar } fn main() {} diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr index 6cd63db44fa..4e8d4cce0a1 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr @@ -1,12 +1,14 @@ -error[E0277]: can't compare `Bar` with `(Bar, i32)` - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:14:5 +error: cannot implement trait on type alias impl trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:1 | -LL | Bar - | ^^^ no implementation for `Bar == (Bar, i32)` +LL | impl PartialEq<(Foo, i32)> for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar` - = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar` +note: type alias impl trait defined here + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs index 6aa832cde71..df7966f00e1 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs @@ -2,7 +2,6 @@ mod a { type Foo = impl PartialEq<(Foo, i32)>; - //~^ ERROR unconstrained opaque type struct Bar; @@ -15,13 +14,12 @@ mod a { mod b { type Foo = impl PartialEq<(Foo, i32)>; - //~^ ERROR unconstrained opaque type struct Bar; impl PartialEq<(Foo, i32)> for Bar { + //~^ ERROR cannot implement trait on type alias impl trait fn eq(&self, _other: &(Bar, i32)) -> bool { - //~^ ERROR impl has stricter requirements than trait true } } diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 19d5cdb9d0a..ccb0bc0a366 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -1,25 +1,14 @@ -error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 +error: cannot implement trait on type alias impl trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:5 + | +LL | impl PartialEq<(Foo, i32)> for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16 | LL | type Foo = impl PartialEq<(Foo, i32)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module -error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:17:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module +error: aborting due to previous error -error[E0276]: impl has stricter requirements than trait - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:23:9 - | -LL | fn eq(&self, _other: &(Bar, i32)) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `b::Bar: PartialEq<(b::Bar, i32)>` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs index fbab5470b4f..ebf3a99bbf9 100644 --- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs +++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs @@ -4,11 +4,11 @@ use std::fmt::Debug; type FooX = impl Debug; -//~^ unconstrained opaque type trait Foo { } impl Foo for () { } +//~^ cannot implement trait on type alias impl trait fn foo() -> impl Foo { () diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr index b1d947a9ccf..bf1582639a2 100644 --- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr +++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr @@ -1,10 +1,14 @@ -error: unconstrained opaque type +error: cannot implement trait on type alias impl trait + --> $DIR/nested-tait-inference3.rs:10:1 + | +LL | impl Foo for () { } + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here --> $DIR/nested-tait-inference3.rs:6:13 | LL | type FooX = impl Debug; | ^^^^^^^^^^ - | - = note: `FooX` must be used in combination with a concrete type within the same module error: aborting due to previous error