Skip to content

Commit

Permalink
Walk into the right visitor when looking at projections of opaque types
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Mar 1, 2024
1 parent 802df56 commit 06ab841
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 9 deletions.
32 changes: 24 additions & 8 deletions compiler/rustc_ty_utils/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,17 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
}
TaitInBodyFinder { collector: self }.visit_expr(body);
}
}

/// A helper trait that ensures that we can recurse with the right TypeVisitor
/// when looking at projections on the opaque type's bounds.
trait OpaqueFinderVisitor<'tcx>: SpannedTypeVisitor<'tcx> {
fn collector(&mut self) -> &mut OpaqueTypeCollector<'tcx>;
fn visit_opaque_ty(&mut self, alias_ty: &ty::AliasTy<'tcx>) {
if !self.seen.insert(alias_ty.def_id.expect_local()) {
if !self.collector().seen.insert(alias_ty.def_id.expect_local()) {
return;
}

let tcx = self.tcx;
let tcx = self.collector().tcx;

// TAITs outside their defining scopes are ignored.
let origin = tcx.opaque_type_origin(alias_ty.def_id.expect_local());
Expand All @@ -127,14 +131,14 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
if !in_assoc_ty {
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
if !self.collector().check_tait_defining_scope(alias_ty.def_id.expect_local()) {
return;
}
}
}
}

self.opaques.push(alias_ty.def_id.expect_local());
self.collector().opaques.push(alias_ty.def_id.expect_local());

let parent_count = tcx.generics_of(alias_ty.def_id).parent_count;
// Only check that the parent generics of the TAIT/RPIT are unique.
Expand All @@ -161,21 +165,27 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
Err(NotUniqueParam::NotParam(arg)) => {
tcx.dcx().emit_err(NotParam {
arg,
span: self.span(),
span: self.collector().span(),
opaque_span: tcx.def_span(alias_ty.def_id),
});
}
Err(NotUniqueParam::DuplicateParam(arg)) => {
tcx.dcx().emit_err(DuplicateArg {
arg,
span: self.span(),
span: self.collector().span(),
opaque_span: tcx.def_span(alias_ty.def_id),
});
}
}
}
}

impl<'tcx> OpaqueFinderVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
fn collector(&mut self) -> &mut OpaqueTypeCollector<'tcx> {
self
}
}

impl<'tcx> SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
Expand Down Expand Up @@ -273,6 +283,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {

struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>);

impl<'tcx> OpaqueFinderVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
fn collector(&mut self) -> &mut OpaqueTypeCollector<'tcx> {
&mut self.0
}
}

impl<'tcx> SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
Expand All @@ -291,7 +307,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInAssocTypeCollector<'tcx> {
t.super_visit_with(self)?;
match t.kind() {
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
self.0.visit_opaque_ty(alias_ty);
self.visit_opaque_ty(alias_ty);
}
ty::Alias(ty::Projection, alias_ty) => {
// This avoids having to do normalization of `Self::AssocTy` by only
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! This test demonstrates a bug where we accidentally
//! detected opaque types in struct fields, but only if nested
//! in projections of another opaque type.
//@ check-pass

#![feature(impl_trait_in_assoc_type)]

Expand All @@ -18,6 +17,7 @@ impl Trait for Bar {
type Assoc = impl Iterator<Item = Foo>;
fn foo() -> Self::Assoc {
vec![Foo { field: () }].into_iter()
//~^ ERROR item constrains opaque type that is not in its signature
}
}

Expand Down
15 changes: 15 additions & 0 deletions tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: item constrains opaque type that is not in its signature
--> $DIR/hidden_behind_struct_field3.rs:19:27
|
LL | vec![Foo { field: () }].into_iter()
| ^^
|
= note: this item must mention the opaque type in its signature in order to be able to register hidden types
note: this item must mention the opaque type in its signature in order to be able to register hidden types
--> $DIR/hidden_behind_struct_field3.rs:18:8
|
LL | fn foo() -> Self::Assoc {
| ^^^

error: aborting due to 1 previous error

0 comments on commit 06ab841

Please sign in to comment.