Add bidirectional where clauses on RPITIT synthesized GATs
This commit is contained in:
parent
d70deac161
commit
4925b57782
@ -1568,14 +1568,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
|
|
||||||
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
|
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
|
||||||
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
|
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
|
||||||
let lifetimes: Vec<_> = collected_lifetimes
|
let lifetime_mapping: Vec<_> = collected_lifetimes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, lifetime)| {
|
.map(|(node_id, lifetime)| {
|
||||||
let id = self.next_node_id();
|
let id = self.next_node_id();
|
||||||
self.new_named_lifetime(lifetime.id, id, lifetime.ident)
|
let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
|
||||||
|
let def_id = self.local_def_id(*node_id);
|
||||||
|
(lifetime, def_id)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
debug!(?lifetimes);
|
debug!(?lifetime_mapping);
|
||||||
|
|
||||||
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
|
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
|
||||||
// Install the remapping from old to new (if any):
|
// Install the remapping from old to new (if any):
|
||||||
@ -1626,6 +1628,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
}),
|
}),
|
||||||
bounds: hir_bounds,
|
bounds: hir_bounds,
|
||||||
origin,
|
origin,
|
||||||
|
lifetime_mapping: self.arena.alloc_from_iter(
|
||||||
|
lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)),
|
||||||
|
),
|
||||||
in_trait,
|
in_trait,
|
||||||
};
|
};
|
||||||
debug!(?opaque_ty_item);
|
debug!(?opaque_ty_item);
|
||||||
@ -1634,17 +1639,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
|
|
||||||
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
|
|
||||||
let lifetimes = self.arena.alloc_from_iter(
|
|
||||||
lifetimes.into_iter().map(|lifetime| hir::GenericArg::Lifetime(lifetime)),
|
|
||||||
);
|
|
||||||
debug!(?lifetimes);
|
|
||||||
|
|
||||||
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
|
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
|
||||||
hir::TyKind::OpaqueDef(
|
hir::TyKind::OpaqueDef(
|
||||||
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
||||||
lifetimes,
|
self.arena.alloc_from_iter(
|
||||||
|
lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
|
||||||
|
),
|
||||||
in_trait,
|
in_trait,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1986,7 +1986,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
let lifetime = Lifetime { id: outer_node_id, ident };
|
let lifetime = Lifetime { id: outer_node_id, ident };
|
||||||
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
|
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?collected_lifetimes);
|
debug!(?collected_lifetimes);
|
||||||
|
|
||||||
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
|
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
|
||||||
@ -2007,19 +2006,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
debug!(?collected_lifetimes);
|
debug!(?collected_lifetimes);
|
||||||
debug!(?new_remapping);
|
debug!(?new_remapping);
|
||||||
|
|
||||||
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
|
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
|
||||||
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
|
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
|
||||||
let lifetimes: Vec<_> = collected_lifetimes
|
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
|
||||||
|
// `TestReturn`.
|
||||||
|
let lifetime_mapping: Vec<_> = collected_lifetimes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, lifetime, res)| {
|
.map(|(node_id, lifetime, res)| {
|
||||||
let id = self.next_node_id();
|
let id = self.next_node_id();
|
||||||
let res = res.unwrap_or(
|
let res = res.unwrap_or(
|
||||||
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
|
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
|
||||||
);
|
);
|
||||||
self.new_named_lifetime_with_res(id, lifetime.ident, res)
|
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
|
||||||
|
let def_id = self.local_def_id(*node_id);
|
||||||
|
(lifetime, def_id)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
debug!(?lifetimes);
|
debug!(?lifetime_mapping);
|
||||||
|
|
||||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||||
// Install the remapping from old to new (if any):
|
// Install the remapping from old to new (if any):
|
||||||
@ -2086,6 +2089,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
}),
|
}),
|
||||||
bounds: arena_vec![this; future_bound],
|
bounds: arena_vec![this; future_bound],
|
||||||
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
|
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
|
||||||
|
lifetime_mapping: self.arena.alloc_from_iter(
|
||||||
|
lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)),
|
||||||
|
),
|
||||||
in_trait,
|
in_trait,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2109,9 +2115,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
//
|
//
|
||||||
// For the "output" lifetime parameters, we just want to
|
// For the "output" lifetime parameters, we just want to
|
||||||
// generate `'_`.
|
// generate `'_`.
|
||||||
let generic_args = self
|
let generic_args = self.arena.alloc_from_iter(
|
||||||
.arena
|
lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
|
||||||
.alloc_from_iter(lifetimes.iter().map(|lifetime| hir::GenericArg::Lifetime(*lifetime)));
|
);
|
||||||
|
|
||||||
// Create the `Foo<...>` reference itself. Note that the `type
|
// Create the `Foo<...>` reference itself. Note that the `type
|
||||||
// Foo = impl Trait` is, internally, created as a child of the
|
// Foo = impl Trait` is, internally, created as a child of the
|
||||||
|
@ -2664,6 +2664,10 @@ pub struct OpaqueTy<'hir> {
|
|||||||
pub generics: &'hir Generics<'hir>,
|
pub generics: &'hir Generics<'hir>,
|
||||||
pub bounds: GenericBounds<'hir>,
|
pub bounds: GenericBounds<'hir>,
|
||||||
pub origin: OpaqueTyOrigin,
|
pub origin: OpaqueTyOrigin,
|
||||||
|
// Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy
|
||||||
|
// so we can later generate bidirectional outlives predicates to enforce that these lifetimes
|
||||||
|
// stay in sync.
|
||||||
|
pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)],
|
||||||
pub in_trait: bool,
|
pub in_trait: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_middle::ty::subst::InternalSubsts;
|
use rustc_middle::ty::subst::InternalSubsts;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{GenericPredicates, Generics, ToPredicate};
|
use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||||
|
|
||||||
@ -62,6 +62,54 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
|
|||||||
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
|
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
|
||||||
use rustc_hir::*;
|
use rustc_hir::*;
|
||||||
|
|
||||||
|
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||||
|
Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
|
||||||
|
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
|
||||||
|
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
|
||||||
|
let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else {
|
||||||
|
bug!("unexpected {opaque_ty_node:?}")
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut predicates = Vec::new();
|
||||||
|
compute_bidirectional_outlives_predicates(
|
||||||
|
tcx,
|
||||||
|
def_id,
|
||||||
|
lifetime_mapping.iter().map(|(lifetime, def_id)| {
|
||||||
|
(*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
|
||||||
|
}),
|
||||||
|
tcx.generics_of(def_id.to_def_id()),
|
||||||
|
&mut predicates,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ty::GenericPredicates {
|
||||||
|
parent: Some(tcx.parent(def_id.to_def_id())),
|
||||||
|
predicates: tcx.arena.alloc_from_iter(predicates),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
|
||||||
|
let assoc_item = tcx.associated_item(def_id);
|
||||||
|
let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap());
|
||||||
|
|
||||||
|
let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||||
|
let impl_def_id = tcx.parent(fn_def_id);
|
||||||
|
let impl_trait_ref_substs =
|
||||||
|
tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs;
|
||||||
|
|
||||||
|
let impl_assoc_substs =
|
||||||
|
impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs);
|
||||||
|
|
||||||
|
let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs);
|
||||||
|
|
||||||
|
return ty::GenericPredicates {
|
||||||
|
parent: Some(impl_def_id),
|
||||||
|
predicates: tcx.arena.alloc_from_iter(impl_predicates),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let node = tcx.hir().get(hir_id);
|
let node = tcx.hir().get(hir_id);
|
||||||
|
|
||||||
@ -298,7 +346,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||||||
.filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
|
.filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
|
||||||
.map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
|
.map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
|
||||||
|
|
||||||
bidirectional_lifetime_predicates(tcx, def_id, lifetime_mapping, generics, &mut predicates);
|
compute_bidirectional_outlives_predicates(
|
||||||
|
tcx,
|
||||||
|
def_id,
|
||||||
|
lifetime_mapping,
|
||||||
|
generics,
|
||||||
|
&mut predicates,
|
||||||
|
);
|
||||||
debug!(?predicates);
|
debug!(?predicates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,12 +340,6 @@ fn associated_type_for_impl_trait_in_trait(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// There are no predicates for the synthesized associated type.
|
|
||||||
trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
|
|
||||||
parent: Some(trait_def_id.to_def_id()),
|
|
||||||
predicates: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
// There are no inferred outlives for the synthesized associated type.
|
// There are no inferred outlives for the synthesized associated type.
|
||||||
trait_assoc_ty.inferred_outlives_of(&[]);
|
trait_assoc_ty.inferred_outlives_of(&[]);
|
||||||
|
|
||||||
@ -424,12 +418,6 @@ fn associated_type_for_impl_trait_in_impl(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// There are no predicates for the synthesized associated type.
|
|
||||||
impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
|
|
||||||
parent: Some(impl_local_def_id.to_def_id()),
|
|
||||||
predicates: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
// There are no inferred outlives for the synthesized associated type.
|
// There are no inferred outlives for the synthesized associated type.
|
||||||
impl_assoc_ty.inferred_outlives_of(&[]);
|
impl_assoc_ty.inferred_outlives_of(&[]);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// check-pass
|
// check-pass
|
||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
|
||||||
|
// revisions: current next
|
||||||
|
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// check-pass
|
// check-pass
|
||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
|
||||||
|
// revisions: current next
|
||||||
|
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user