Skip to content

Support using Self or projections inside an RPIT/async fn #103491

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Create bidirectional bounds between original and duplicated parameters.
  • Loading branch information
cjgillot committed Nov 13, 2022
commit c5949c8beedc290b2638e1ad9bd7c665edc9496a
18 changes: 6 additions & 12 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::DefPathData;
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::DesugaringKind;
Expand Down Expand Up @@ -1457,17 +1457,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);

let opaque_ty_def_id = match origin {
hir::OpaqueTyOrigin::TyAlias => self.create_def(
self.current_hir_id_owner.def_id,
opaque_ty_node_id,
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"),
};
let opaque_ty_def_id = self.create_def(
self.current_hir_id_owner.def_id,
opaque_ty_node_id,
DefPathData::ImplTrait,
);
debug!(?opaque_ty_def_id);

// Contains the new lifetime definitions created for the TAIT (if any).
Expand Down
29 changes: 16 additions & 13 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,6 @@ fn check_fn_or_method<'tcx>(

check_return_position_impl_trait_in_trait_bounds(
tcx,
wfcx,
def_id,
sig.output(),
hir_decl.output.span(),
Expand Down Expand Up @@ -1574,9 +1573,9 @@ fn check_fn_or_method<'tcx>(

/// Basically `check_associated_type_bounds`, but separated for now and should be
/// 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>(
tcx: TyCtxt<'tcx>,
wfcx: &WfCheckingCtxt<'_, 'tcx>,
fn_def_id: LocalDefId,
fn_output: Ty<'tcx>,
span: Span,
Expand All @@ -1590,18 +1589,22 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
&& 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()
{
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_id,
normalized_bound,
bound_span,
)
// 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 wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_id,
normalized_bound,
bound_span,
)
});
wfcx.register_obligations(wf_obligations);
});
wfcx.register_obligations(wf_obligations);
}
}
}
Expand Down
103 changes: 71 additions & 32 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,40 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP

Node::ImplItem(item) => item.generics,

Node::Item(item) => {
match item.kind {
ItemKind::Impl(ref impl_) => {
if impl_.defaultness.is_default() {
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
}
&impl_.generics
}
ItemKind::Fn(.., ref generics, _)
| ItemKind::TyAlias(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => *generics,

ItemKind::Trait(_, _, ref generics, ..) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
ItemKind::TraitAlias(ref generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
Node::Item(item) => match item.kind {
ItemKind::Impl(ref impl_) => {
if impl_.defaultness.is_default() {
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
}
ItemKind::OpaqueTy(OpaqueTy {
ref generics,
origin: hir::OpaqueTyOrigin::TyAlias,
..
}) => {
// type-alias impl trait
generics
}

_ => NO_GENERICS,
&impl_.generics
}
}
ItemKind::Fn(.., ref generics, _)
| ItemKind::TyAlias(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => *generics,

ItemKind::Trait(_, _, ref generics, ..) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
ItemKind::TraitAlias(ref generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
_ => NO_GENERICS,
},

Node::ForeignItem(item) => match item.kind {
ForeignItemKind::Static(..) => NO_GENERICS,
Expand Down Expand Up @@ -161,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP

trace!(?predicates);
trace!(?ast_generics);
trace!(?generics);

// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
Expand Down Expand Up @@ -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 {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {

/// See `ParamEnv` struct definition for details.
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.

let ty::InstantiatedPredicates { mut predicates, .. } =
tcx.predicates_of(def_id).instantiate_identity(tcx);

Expand Down
5 changes: 1 addition & 4 deletions src/test/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ error[E0720]: cannot resolve opaque type
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
|
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
| ^^^^^^^^^^^^^^^ recursive opaque type
...
LL | |x| x
| ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]`
| ^^^^^^^^^^^^^^^ cannot resolve opaque type

error: aborting due to 2 previous errors

Expand Down