Rollup merge of #121838 - oli-obk:impl_trait_in_assoc_tys_fix, r=compiler-errors
Use the correct logic for nested impl trait in assoc types Previously we accidentally continued with the TAIT visitor, which allowed more than we wanted to. r? ```@compiler-errors```
This commit is contained in:
commit
20dde1ea62
@ -22,11 +22,20 @@ struct OpaqueTypeCollector<'tcx> {
|
|||||||
seen: FxHashSet<LocalDefId>,
|
seen: FxHashSet<LocalDefId>,
|
||||||
|
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
|
|
||||||
|
mode: CollectionMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CollectionMode {
|
||||||
|
/// For impl trait in assoc types we only permit collecting them from
|
||||||
|
/// associated types of the same impl block.
|
||||||
|
ImplTraitInAssocTypes,
|
||||||
|
TypeAliasImplTraitTransition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> OpaqueTypeCollector<'tcx> {
|
impl<'tcx> OpaqueTypeCollector<'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
|
fn new(tcx: TyCtxt<'tcx>, item: LocalDefId, mode: CollectionMode) -> Self {
|
||||||
Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None }
|
Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
@ -251,6 +260,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Adt(def, _) if def.did().is_local() => {
|
ty::Adt(def, _) if def.did().is_local() => {
|
||||||
|
if let CollectionMode::ImplTraitInAssocTypes = self.mode {
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
if !self.seen.insert(def.did().expect_local()) {
|
if !self.seen.insert(def.did().expect_local()) {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
@ -275,89 +287,13 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ImplTraitInAssocTypeCollector<'tcx>(OpaqueTypeCollector<'tcx>);
|
|
||||||
|
|
||||||
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for ImplTraitInAssocTypeCollector<'tcx> {
|
|
||||||
#[instrument(skip(self), ret, level = "trace")]
|
|
||||||
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
|
|
||||||
let old = self.0.span;
|
|
||||||
self.0.span = Some(span);
|
|
||||||
value.visit_with(self);
|
|
||||||
self.0.span = old;
|
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInAssocTypeCollector<'tcx> {
|
|
||||||
#[instrument(skip(self), ret, level = "trace")]
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
ty::Alias(ty::Projection, alias_ty) => {
|
|
||||||
// This avoids having to do normalization of `Self::AssocTy` by only
|
|
||||||
// supporting the case of a method defining opaque types from assoc types
|
|
||||||
// in the same impl block.
|
|
||||||
let parent_trait_ref = self
|
|
||||||
.0
|
|
||||||
.parent_trait_ref()
|
|
||||||
.expect("impl trait in assoc type collector used on non-assoc item");
|
|
||||||
// If the trait ref of the associated item and the impl differs,
|
|
||||||
// then we can't use the impl's identity args below, so
|
|
||||||
// just skip.
|
|
||||||
if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref {
|
|
||||||
let parent = self.0.parent().expect("we should have a parent here");
|
|
||||||
|
|
||||||
for &assoc in self.0.tcx.associated_items(parent).in_definition_order() {
|
|
||||||
trace!(?assoc);
|
|
||||||
if assoc.trait_item_def_id != Some(alias_ty.def_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the type is further specializable, then the type_of
|
|
||||||
// is not actually correct below.
|
|
||||||
if !assoc.defaultness(self.0.tcx).is_final() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let impl_args = alias_ty.args.rebase_onto(
|
|
||||||
self.0.tcx,
|
|
||||||
parent_trait_ref.def_id,
|
|
||||||
ty::GenericArgs::identity_for_item(self.0.tcx, parent),
|
|
||||||
);
|
|
||||||
|
|
||||||
if check_args_compatible(self.0.tcx, assoc, impl_args) {
|
|
||||||
return self
|
|
||||||
.0
|
|
||||||
.tcx
|
|
||||||
.type_of(assoc.def_id)
|
|
||||||
.instantiate(self.0.tcx, impl_args)
|
|
||||||
.visit_with(self);
|
|
||||||
} else {
|
|
||||||
self.0.tcx.dcx().span_bug(
|
|
||||||
self.0.tcx.def_span(assoc.def_id),
|
|
||||||
"item had incorrect args",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => trace!(kind=?t.kind()),
|
|
||||||
}
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn impl_trait_in_assoc_types_defined_by<'tcx>(
|
fn impl_trait_in_assoc_types_defined_by<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
item: LocalDefId,
|
item: LocalDefId,
|
||||||
) -> &'tcx ty::List<LocalDefId> {
|
) -> &'tcx ty::List<LocalDefId> {
|
||||||
let mut collector = ImplTraitInAssocTypeCollector(OpaqueTypeCollector::new(tcx, item));
|
let mut collector = OpaqueTypeCollector::new(tcx, item, CollectionMode::ImplTraitInAssocTypes);
|
||||||
super::sig_types::walk_types(tcx, item, &mut collector);
|
super::sig_types::walk_types(tcx, item, &mut collector);
|
||||||
tcx.mk_local_def_ids(&collector.0.opaques)
|
tcx.mk_local_def_ids(&collector.opaques)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opaque_types_defined_by<'tcx>(
|
fn opaque_types_defined_by<'tcx>(
|
||||||
@ -366,7 +302,8 @@ fn opaque_types_defined_by<'tcx>(
|
|||||||
) -> &'tcx ty::List<LocalDefId> {
|
) -> &'tcx ty::List<LocalDefId> {
|
||||||
let kind = tcx.def_kind(item);
|
let kind = tcx.def_kind(item);
|
||||||
trace!(?kind);
|
trace!(?kind);
|
||||||
let mut collector = OpaqueTypeCollector::new(tcx, item);
|
let mut collector =
|
||||||
|
OpaqueTypeCollector::new(tcx, item, CollectionMode::TypeAliasImplTraitTransition);
|
||||||
super::sig_types::walk_types(tcx, item, &mut collector);
|
super::sig_types::walk_types(tcx, item, &mut collector);
|
||||||
match kind {
|
match kind {
|
||||||
DefKind::AssocFn
|
DefKind::AssocFn
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
//! This test demonstrates a bug where we accidentally
|
||||||
|
//! detected opaque types in struct fields, but only if nested
|
||||||
|
//! in projections of another opaque type.
|
||||||
|
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
struct Bar;
|
||||||
|
|
||||||
|
trait Trait: Sized {
|
||||||
|
type Assoc2;
|
||||||
|
type Assoc;
|
||||||
|
fn foo() -> Self::Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Bar {
|
||||||
|
type Assoc2 = impl std::fmt::Debug;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
field: <Bar as Trait>::Assoc2,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -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
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user