Create bidirectional bounds between original and duplicated parameters.
This commit is contained in:
parent
49a5aa4f0c
commit
c5949c8bee
5 changed files with 94 additions and 66 deletions
|
@ -61,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::definitions::DefPathData;
|
use rustc_hir::definitions::DefPathData;
|
||||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::source_map::DesugaringKind;
|
use rustc_span::source_map::DesugaringKind;
|
||||||
|
@ -1457,17 +1457,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// frequently opened issues show.
|
// frequently opened issues show.
|
||||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||||
|
|
||||||
let opaque_ty_def_id = match origin {
|
let opaque_ty_def_id = self.create_def(
|
||||||
hir::OpaqueTyOrigin::TyAlias => self.create_def(
|
|
||||||
self.current_hir_id_owner.def_id,
|
self.current_hir_id_owner.def_id,
|
||||||
opaque_ty_node_id,
|
opaque_ty_node_id,
|
||||||
DefPathData::ImplTrait,
|
DefPathData::ImplTrait,
|
||||||
),
|
);
|
||||||
hir::OpaqueTyOrigin::FnReturn(fn_def_id) => {
|
|
||||||
self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait)
|
|
||||||
}
|
|
||||||
hir::OpaqueTyOrigin::AsyncFn(..) => bug!("unreachable"),
|
|
||||||
};
|
|
||||||
debug!(?opaque_ty_def_id);
|
debug!(?opaque_ty_def_id);
|
||||||
|
|
||||||
// Contains the new lifetime definitions created for the TAIT (if any).
|
// Contains the new lifetime definitions created for the TAIT (if any).
|
||||||
|
|
|
@ -1538,7 +1538,6 @@ fn check_fn_or_method<'tcx>(
|
||||||
|
|
||||||
check_return_position_impl_trait_in_trait_bounds(
|
check_return_position_impl_trait_in_trait_bounds(
|
||||||
tcx,
|
tcx,
|
||||||
wfcx,
|
|
||||||
def_id,
|
def_id,
|
||||||
sig.output(),
|
sig.output(),
|
||||||
hir_decl.output.span(),
|
hir_decl.output.span(),
|
||||||
|
@ -1574,9 +1573,9 @@ fn check_fn_or_method<'tcx>(
|
||||||
|
|
||||||
/// Basically `check_associated_type_bounds`, but separated for now and should be
|
/// Basically `check_associated_type_bounds`, but separated for now and should be
|
||||||
/// deduplicated when RPITITs get lowered into real associated items.
|
/// deduplicated when RPITITs get lowered into real associated items.
|
||||||
|
#[tracing::instrument(level = "trace", skip(tcx))]
|
||||||
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
wfcx: &WfCheckingCtxt<'_, 'tcx>,
|
|
||||||
fn_def_id: LocalDefId,
|
fn_def_id: LocalDefId,
|
||||||
fn_output: Ty<'tcx>,
|
fn_output: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -1590,6 +1589,9 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
||||||
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
|
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
|
||||||
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
|
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
|
||||||
{
|
{
|
||||||
|
// Create a new context, since we want the opaque's ParamEnv and not the parent's.
|
||||||
|
let span = tcx.def_span(proj.item_def_id);
|
||||||
|
enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| {
|
||||||
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
|
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
|
||||||
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
||||||
let normalized_bound = wfcx.normalize(span, None, bound);
|
let normalized_bound = wfcx.normalize(span, None, bound);
|
||||||
|
@ -1602,6 +1604,7 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
wfcx.register_obligations(wf_obligations);
|
wfcx.register_obligations(wf_obligations);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,8 +84,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
|
|
||||||
Node::ImplItem(item) => item.generics,
|
Node::ImplItem(item) => item.generics,
|
||||||
|
|
||||||
Node::Item(item) => {
|
Node::Item(item) => match item.kind {
|
||||||
match item.kind {
|
|
||||||
ItemKind::Impl(ref impl_) => {
|
ItemKind::Impl(ref impl_) => {
|
||||||
if impl_.defaultness.is_default() {
|
if impl_.defaultness.is_default() {
|
||||||
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
|
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
|
||||||
|
@ -106,18 +105,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||||
*generics
|
*generics
|
||||||
}
|
}
|
||||||
ItemKind::OpaqueTy(OpaqueTy {
|
ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
|
||||||
ref generics,
|
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// type-alias impl trait
|
|
||||||
generics
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => NO_GENERICS,
|
_ => NO_GENERICS,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
Node::ForeignItem(item) => match item.kind {
|
Node::ForeignItem(item) => match item.kind {
|
||||||
ForeignItemKind::Static(..) => NO_GENERICS,
|
ForeignItemKind::Static(..) => NO_GENERICS,
|
||||||
|
@ -161,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
|
|
||||||
trace!(?predicates);
|
trace!(?predicates);
|
||||||
trace!(?ast_generics);
|
trace!(?ast_generics);
|
||||||
|
trace!(?generics);
|
||||||
|
|
||||||
// Collect the predicates that were written inline by the user on each
|
// Collect the predicates that were written inline by the user on each
|
||||||
// type parameter (e.g., `<T: Foo>`).
|
// type parameter (e.g., `<T: Foo>`).
|
||||||
|
@ -279,6 +270,54 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opaque types duplicate some of their generic parameters.
|
||||||
|
// We create bi-directional Outlives predicates between the original
|
||||||
|
// and the duplicated parameter, to ensure that they do not get out of sync.
|
||||||
|
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
|
||||||
|
let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
|
||||||
|
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
|
||||||
|
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
|
||||||
|
bug!("unexpected {opaque_ty_node:?}")
|
||||||
|
};
|
||||||
|
debug!(?lifetimes);
|
||||||
|
for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
|
||||||
|
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
|
||||||
|
let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
|
||||||
|
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
|
||||||
|
// Only early-bound regions can point to the original generic parameter.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
|
||||||
|
let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
|
||||||
|
|
||||||
|
let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
|
||||||
|
|
||||||
|
let dup_region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||||
|
def_id: dup_def,
|
||||||
|
index: dup_index,
|
||||||
|
name: duplicate.name.ident().name,
|
||||||
|
}));
|
||||||
|
predicates.push((
|
||||||
|
ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
|
||||||
|
orig_region,
|
||||||
|
dup_region,
|
||||||
|
)))
|
||||||
|
.to_predicate(icx.tcx),
|
||||||
|
duplicate.span,
|
||||||
|
));
|
||||||
|
predicates.push((
|
||||||
|
ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
|
||||||
|
dup_region,
|
||||||
|
orig_region,
|
||||||
|
)))
|
||||||
|
.to_predicate(icx.tcx),
|
||||||
|
duplicate.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
debug!(?predicates);
|
||||||
|
}
|
||||||
|
|
||||||
ty::GenericPredicates {
|
ty::GenericPredicates {
|
||||||
parent: generics.parent,
|
parent: generics.parent,
|
||||||
predicates: tcx.arena.alloc_from_iter(predicates),
|
predicates: tcx.arena.alloc_from_iter(predicates),
|
||||||
|
|
|
@ -108,12 +108,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
|
||||||
|
|
||||||
/// See `ParamEnv` struct definition for details.
|
/// See `ParamEnv` struct definition for details.
|
||||||
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
||||||
// The param_env of an impl Trait type is its defining function's param_env
|
|
||||||
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
|
|
||||||
return param_env(tcx, parent.to_def_id());
|
|
||||||
}
|
|
||||||
// Compute the bounds on Self and the type parameters.
|
// Compute the bounds on Self and the type parameters.
|
||||||
|
|
||||||
let ty::InstantiatedPredicates { mut predicates, .. } =
|
let ty::InstantiatedPredicates { mut predicates, .. } =
|
||||||
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,7 @@ error[E0720]: cannot resolve opaque type
|
||||||
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
|
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
|
||||||
|
|
|
|
||||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||||
| ^^^^^^^^^^^^^^^ recursive opaque type
|
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
|
||||||
...
|
|
||||||
LL | |x| x
|
|
||||||
| ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue