Skip to content

Commit efc6a6f

Browse files
committed
Report that opaque types are not allowed in impls even in the presence of other errors
1 parent 468492c commit efc6a6f

File tree

4 files changed

+64
-58
lines changed

4 files changed

+64
-58
lines changed

compiler/rustc_typeck/src/coherence/orphan.rs

+53-52
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,59 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
4444
};
4545
let sp = tcx.sess.source_map().guess_head_span(item.span);
4646
let tr = impl_.of_trait.as_ref().unwrap();
47+
48+
// Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
49+
// and #84660 where it would otherwise allow unsoundness.
50+
if trait_ref.has_opaque_types() {
51+
trace!("{:#?}", item);
52+
// First we find the opaque type in question.
53+
for ty in trait_ref.substs {
54+
for ty in ty.walk() {
55+
let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
56+
let ty::Opaque(def_id, _) = *ty.kind() else { continue };
57+
trace!(?def_id);
58+
59+
// Then we search for mentions of the opaque type's type alias in the HIR
60+
struct SpanFinder<'tcx> {
61+
sp: Span,
62+
def_id: DefId,
63+
tcx: TyCtxt<'tcx>,
64+
}
65+
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
66+
#[instrument(level = "trace", skip(self, _id))]
67+
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
68+
// You can't mention an opaque type directly, so we look for type aliases
69+
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
70+
// And check if that type alias's type contains the opaque type we're looking for
71+
for arg in self.tcx.type_of(def_id).walk() {
72+
if let GenericArgKind::Type(ty) = arg.unpack() {
73+
if let ty::Opaque(def_id, _) = *ty.kind() {
74+
if def_id == self.def_id {
75+
// Finally we update the span to the mention of the type alias
76+
self.sp = path.span;
77+
return;
78+
}
79+
}
80+
}
81+
}
82+
}
83+
hir::intravisit::walk_path(self, path)
84+
}
85+
}
86+
87+
let mut visitor = SpanFinder { sp, def_id, tcx };
88+
hir::intravisit::walk_item(&mut visitor, item);
89+
let reported = tcx
90+
.sess
91+
.struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
92+
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
93+
.emit();
94+
return Err(reported);
95+
}
96+
}
97+
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
98+
}
99+
47100
match traits::orphan_check(tcx, item.def_id.to_def_id()) {
48101
Ok(()) => {}
49102
Err(err) => emit_orphan_check_error(
@@ -143,58 +196,6 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
143196
}
144197
}
145198

146-
// Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
147-
// and #84660 where it would otherwise allow unsoundness.
148-
if trait_ref.has_opaque_types() {
149-
trace!("{:#?}", item);
150-
// First we find the opaque type in question.
151-
for ty in trait_ref.substs {
152-
for ty in ty.walk() {
153-
let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
154-
let ty::Opaque(def_id, _) = *ty.kind() else { continue };
155-
trace!(?def_id);
156-
157-
// Then we search for mentions of the opaque type's type alias in the HIR
158-
struct SpanFinder<'tcx> {
159-
sp: Span,
160-
def_id: DefId,
161-
tcx: TyCtxt<'tcx>,
162-
}
163-
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
164-
#[instrument(level = "trace", skip(self, _id))]
165-
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
166-
// You can't mention an opaque type directly, so we look for type aliases
167-
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
168-
// And check if that type alias's type contains the opaque type we're looking for
169-
for arg in self.tcx.type_of(def_id).walk() {
170-
if let GenericArgKind::Type(ty) = arg.unpack() {
171-
if let ty::Opaque(def_id, _) = *ty.kind() {
172-
if def_id == self.def_id {
173-
// Finally we update the span to the mention of the type alias
174-
self.sp = path.span;
175-
return;
176-
}
177-
}
178-
}
179-
}
180-
}
181-
hir::intravisit::walk_path(self, path)
182-
}
183-
}
184-
185-
let mut visitor = SpanFinder { sp, def_id, tcx };
186-
hir::intravisit::walk_item(&mut visitor, item);
187-
let reported = tcx
188-
.sess
189-
.struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
190-
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
191-
.emit();
192-
return Err(reported);
193-
}
194-
}
195-
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
196-
}
197-
198199
Ok(())
199200
}
200201

compiler/rustc_typeck/src/constrained_generic_params.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct ParameterCollector {
5959
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
6060
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
6161
match *t.kind() {
62-
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
62+
ty::Projection(..) if !self.include_nonconstraining => {
6363
// projections are not injective
6464
return ControlFlow::CONTINUE;
6565
}

src/test/ui/type-alias-impl-trait/coherence.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
1212
}
1313

1414
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
15+
//~^ ERROR cannot implement trait on type alias impl trait
1616

1717
fn main() {}

src/test/ui/type-alias-impl-trait/coherence.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
2-
--> $DIR/coherence.rs:14:6
1+
error: cannot implement trait on type alias impl trait
2+
--> $DIR/coherence.rs:14:41
33
|
44
LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
5-
| ^ unconstrained type parameter
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: type alias impl trait defined here
8+
--> $DIR/coherence.rs:9:30
9+
|
10+
LL | type AliasOfForeignType<T> = impl LocalTrait;
11+
| ^^^^^^^^^^^^^^^
612

713
error: aborting due to previous error
814

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

0 commit comments

Comments
 (0)