Skip to content

Commit 4f8ebac

Browse files
committed
Limit impl trait in assoc type defining scope
1 parent ffe4329 commit 4f8ebac

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

compiler/rustc_ty_utils/src/opaque_types.rs

+79-1
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,89 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
275275
}
276276
}
277277

278+
struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>);
279+
280+
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
281+
#[instrument(skip(self), ret, level = "trace")]
282+
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
283+
let old = self.0.span;
284+
self.0.span = Some(span);
285+
value.visit_with(self);
286+
self.0.span = old;
287+
288+
ControlFlow::Continue(())
289+
}
290+
}
291+
292+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInAssocTypeCollector<'tcx> {
293+
#[instrument(skip(self), ret, level = "trace")]
294+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
295+
t.super_visit_with(self)?;
296+
match t.kind() {
297+
ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
298+
self.0.visit_opaque_ty(alias_ty);
299+
}
300+
ty::Alias(ty::Projection, alias_ty) => {
301+
// This avoids having to do normalization of `Self::AssocTy` by only
302+
// supporting the case of a method defining opaque types from assoc types
303+
// in the same impl block.
304+
let parent_trait_ref = self
305+
.0
306+
.parent_trait_ref()
307+
.expect("impl trait in assoc type collector used on non-assoc item");
308+
// If the trait ref of the associated item and the impl differs,
309+
// then we can't use the impl's identity substitutions below, so
310+
// just skip.
311+
if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref {
312+
let parent = self.0.parent().expect("we should have a parent here");
313+
314+
for &assoc in self.0.tcx.associated_items(parent).in_definition_order() {
315+
trace!(?assoc);
316+
if assoc.trait_item_def_id != Some(alias_ty.def_id) {
317+
continue;
318+
}
319+
320+
// If the type is further specializable, then the type_of
321+
// is not actually correct below.
322+
if !assoc.defaultness(self.0.tcx).is_final() {
323+
continue;
324+
}
325+
326+
let impl_args = alias_ty.args.rebase_onto(
327+
self.0.tcx,
328+
parent_trait_ref.def_id,
329+
ty::GenericArgs::identity_for_item(self.0.tcx, parent),
330+
);
331+
332+
if check_args_compatible(self.0.tcx, assoc, impl_args) {
333+
return self
334+
.0
335+
.tcx
336+
.type_of(assoc.def_id)
337+
.instantiate(self.0.tcx, impl_args)
338+
.visit_with(self);
339+
} else {
340+
self.0.tcx.dcx().span_delayed_bug(
341+
self.0.tcx.def_span(assoc.def_id),
342+
"item had incorrect args",
343+
);
344+
}
345+
}
346+
}
347+
}
348+
_ => trace!(kind=?t.kind()),
349+
}
350+
ControlFlow::Continue(())
351+
}
352+
}
353+
278354
fn impl_trait_in_assoc_types_defined_by<'tcx>(
279355
tcx: TyCtxt<'tcx>,
280356
item: LocalDefId,
281357
) -> &'tcx ty::List<LocalDefId> {
282-
opaque_types_defined_by(tcx, item)
358+
let mut collector = ImplTraitInAssocTypeCollector(OpaqueTypeCollector::new(tcx, item));
359+
super::sig_types::walk_types(tcx, item, &mut collector);
360+
tcx.mk_local_def_ids(&collector.0.opaques)
283361
}
284362

285363
fn opaque_types_defined_by<'tcx>(

tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
//! This test shows that we can even follow projections
2-
//! into associated types of the same impl if they are
3-
//! indirectly mentioned in a struct field.
1+
//! This test shows that we do not treat opaque types
2+
//! as defined by a method if the opaque type is
3+
//! only indirectly mentioned in a struct field.
44
55
#![feature(impl_trait_in_assoc_type)]
6-
// check-pass
76

87
struct Bar;
98

@@ -16,6 +15,7 @@ impl Trait for Bar {
1615
type Assoc = impl std::fmt::Debug;
1716
fn foo() -> Foo {
1817
Foo { field: () }
18+
//~^ ERROR: item constrains opaque type that is not in its signature
1919
}
2020
}
2121

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: item constrains opaque type that is not in its signature
2+
--> $DIR/hidden_behind_struct_field2.rs:17:22
3+
|
4+
LL | Foo { field: () }
5+
| ^^
6+
|
7+
= note: this item must mention the opaque type in its signature in order to be able to register hidden types
8+
note: this item must mention the opaque type in its signature in order to be able to register hidden types
9+
--> $DIR/hidden_behind_struct_field2.rs:16:8
10+
|
11+
LL | fn foo() -> Foo {
12+
| ^^^
13+
14+
error: aborting due to 1 previous error
15+

0 commit comments

Comments
 (0)