Skip to content

Report that opaque types are not allowed in impls even in the presence of other errors #96673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 53 additions & 52 deletions compiler/rustc_typeck/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,59 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
};
let sp = tcx.sess.source_map().guess_head_span(item.span);
let tr = impl_.of_trait.as_ref().unwrap();

// 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() {
trace!("{:#?}", item);
// First we find the opaque type in question.
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 };
trace!(?def_id);

// Then we search for mentions of the opaque type's type alias in the HIR
struct SpanFinder<'tcx> {
sp: Span,
def_id: DefId,
tcx: TyCtxt<'tcx>,
}
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
#[instrument(level = "trace", skip(self, _id))]
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
// You can't mention an opaque type directly, so we look for type aliases
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
// And check if that type alias's type contains the opaque type we're looking for
for arg in self.tcx.type_of(def_id).walk() {
if let GenericArgKind::Type(ty) = arg.unpack() {
if let ty::Opaque(def_id, _) = *ty.kind() {
if def_id == self.def_id {
// Finally we update the span to the mention of the type alias
self.sp = path.span;
return;
}
}
}
}
}
hir::intravisit::walk_path(self, path)
}
}

let mut visitor = SpanFinder { sp, def_id, tcx };
hir::intravisit::walk_item(&mut visitor, item);
let reported = tcx
.sess
.struct_span_err(visitor.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, "opaque type not found, but `has_opaque_types` is set")
}

match traits::orphan_check(tcx, item.def_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
Expand Down Expand Up @@ -143,58 +196,6 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
}
}

// 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() {
trace!("{:#?}", item);
// First we find the opaque type in question.
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 };
trace!(?def_id);

// Then we search for mentions of the opaque type's type alias in the HIR
struct SpanFinder<'tcx> {
sp: Span,
def_id: DefId,
tcx: TyCtxt<'tcx>,
}
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
#[instrument(level = "trace", skip(self, _id))]
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
// You can't mention an opaque type directly, so we look for type aliases
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
// And check if that type alias's type contains the opaque type we're looking for
for arg in self.tcx.type_of(def_id).walk() {
if let GenericArgKind::Type(ty) = arg.unpack() {
if let ty::Opaque(def_id, _) = *ty.kind() {
if def_id == self.def_id {
// Finally we update the span to the mention of the type alias
self.sp = path.span;
return;
}
}
}
}
}
hir::intravisit::walk_path(self, path)
}
}

let mut visitor = SpanFinder { sp, def_id, tcx };
hir::intravisit::walk_item(&mut visitor, item);
let reported = tcx
.sess
.struct_span_err(visitor.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, "opaque type not found, but `has_opaque_types` is set")
}

Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/constrained_generic_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct ParameterCollector {
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
ty::Projection(..) if !self.include_nonconstraining => {
// projections are not injective
return ControlFlow::CONTINUE;
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/type-alias-impl-trait/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
}

impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates
//~^ ERROR cannot implement trait on type alias impl trait

fn main() {}
13 changes: 9 additions & 4 deletions src/test/ui/type-alias-impl-trait/coherence.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> $DIR/coherence.rs:14:6
error: cannot implement trait on type alias impl trait
--> $DIR/coherence.rs:14:41
|
LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
| ^ unconstrained type parameter
| ^^^^^^^^^^^^^^^^^^^^^
|
note: type alias impl trait defined here
--> $DIR/coherence.rs:9:30
|
LL | type AliasOfForeignType<T> = impl LocalTrait;
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

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