Lower RPITIT to ImplTraitPlaceholder item

This commit is contained in:
Michael Goulet 2022-08-31 04:03:24 +00:00
parent 78b962a4f3
commit d34cb98fb0
11 changed files with 99 additions and 8 deletions

View File

@ -255,6 +255,8 @@ enum ImplTraitContext {
},
/// Impl trait in type aliases.
TypeAliasesOpaqueTy,
/// Return-position `impl Trait` in trait definition
InTrait,
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
@ -323,9 +325,17 @@ enum FnDeclKind {
}
impl FnDeclKind {
fn impl_trait_return_allowed(&self) -> bool {
fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
_ => false,
}
}
fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
_ => false,
}
}
@ -1346,6 +1356,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut nested_itctx,
)
}
ImplTraitContext::InTrait => {
// FIXME(RPITIT): Should we use def_node_id here?
self.lower_impl_trait_in_trait(span, def_node_id, bounds)
}
ImplTraitContext::Universal => {
let span = t.span;
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@ -1532,6 +1546,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
}
#[tracing::instrument(level = "debug", skip(self))]
fn lower_impl_trait_in_trait(
&mut self,
span: Span,
opaque_ty_node_id: NodeId,
bounds: &GenericBounds,
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
// FIXME(RPITIT): This should be a more descriptive ImplTraitPosition, i.e. nested RPITIT
// FIXME(RPITIT): We _also_ should support this eventually
let hir_bounds = lctx
.lower_param_bounds(bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Trait));
let rpitit_placeholder = hir::ImplTraitPlaceholder { bounds: hir_bounds };
let rpitit_item = hir::Item {
def_id: opaque_ty_def_id,
ident: Ident::empty(),
kind: hir::ItemKind::ImplTraitPlaceholder(rpitit_placeholder),
span: lctx.lower_span(span),
vis_span: lctx.lower_span(span.shrink_to_lo()),
};
hir::OwnerNode::Item(lctx.arena.alloc(rpitit_item))
});
hir::TyKind::ImplTraitInTrait(hir::ItemId { def_id: opaque_ty_def_id })
}
/// Registers a new opaque type with the proper `NodeId`s and
/// returns the lowered node-ID for the opaque type.
fn generate_opaque_type(
@ -1690,12 +1730,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match decl.output {
FnRetTy::Ty(ref ty) => {
let mut context = match fn_node_id {
Some(fn_node_id) if kind.impl_trait_return_allowed() => {
Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
}
}
Some(_) if kind.impl_trait_in_trait_allowed(self.tcx) => {
ImplTraitContext::InTrait
}
_ => ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes")

View File

@ -487,6 +487,8 @@ declare_features! (
(incomplete, repr128, "1.16.0", Some(56071), None),
/// Allows `repr(simd)` and importing the various simd intrinsics.
(active, repr_simd, "1.4.0", Some(27731), None),
/// Allows return-position `impl Trait` in traits.
(incomplete, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
/// Allows `extern "rust-cold"`.
(active, rust_cold_cc, "1.63.0", Some(97544), None),
/// Allows the use of SIMD types in functions declared in `extern` blocks.

View File

@ -105,6 +105,7 @@ impl Target {
DefKind::GlobalAsm => Target::GlobalAsm,
DefKind::TyAlias => Target::TyAlias,
DefKind::OpaqueTy => Target::OpaqueTy,
DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder,
DefKind::Enum => Target::Enum,
DefKind::Struct => Target::Struct,
DefKind::Union => Target::Union,

View File

@ -2,6 +2,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
use crate::ty::diagnostics::suggest_constraining_type_param;
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
use hir::def::DefKind;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
use rustc_hir as hir;
@ -538,7 +539,7 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter");
}
}
(ty::Projection(proj_ty), _) => {
(ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
self.expected_projection(
diag,
proj_ty,
@ -547,7 +548,7 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
(_, ty::Projection(proj_ty)) => {
(_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,

View File

@ -11,6 +11,7 @@ use crate::ty::{
TypeVisitor,
};
use crate::ty::{List, ParamEnv};
use hir::def::DefKind;
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::intern::Interned;
@ -1196,7 +1197,9 @@ pub struct ProjectionTy<'tcx> {
impl<'tcx> ProjectionTy<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
tcx.parent(self.item_def_id)
let parent = tcx.parent(self.item_def_id);
assert_eq!(tcx.def_kind(parent), DefKind::Trait);
parent
}
/// Extracts the underlying trait reference and own substs from this projection.

View File

@ -597,7 +597,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
}
hir::ItemKind::ImplTraitPlaceholder(..) => {
// FIXME(RPITIT): We don't need to do anything here, right?
// FIXME(RPITIT): We don't need to do anything special here, right?
intravisit::walk_item(self, item);
}
hir::ItemKind::TyAlias(_, ref generics)
| hir::ItemKind::Enum(_, ref generics)

View File

@ -1183,6 +1183,7 @@ symbols! {
require,
residual,
result,
return_position_impl_trait_in_trait,
rhs,
rintf32,
rintf64,

View File

@ -1465,6 +1465,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
// Can't assemble candidate from impl for RPITIT
if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
return;
}
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));

View File

@ -2638,8 +2638,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
hir::TyKind::ImplTraitInTrait(..) => {
span_bug!(ast_ty.span, "not yet implemented")
hir::TyKind::ImplTraitInTrait(item_id) => {
let def_id = item_id.def_id.to_def_id();
tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id))
}
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!(?qself, ?segment);

View File

@ -1600,6 +1600,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// inherit the generics of the item.
Some(parent_id.to_def_id())
}
ItemKind::ImplTraitPlaceholder(_) => {
let parent_id = tcx.hir().get_parent_item(hir_id).to_def_id();
assert_eq!(tcx.def_kind(parent_id), DefKind::AssocFn);
Some(parent_id)
}
_ => None,
},
_ => None,

View File

@ -74,6 +74,29 @@ fn opaque_type_bounds<'tcx>(
})
}
/// Opaque types don't inherit bounds from their parent: for return position
/// impl trait it isn't possible to write a suitable predicate on the
/// containing function and for type-alias impl trait we don't have a backwards
/// compatibility issue.
fn impl_trait_in_trait_item_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
opaque_def_id: DefId,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
span: Span,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
ty::print::with_no_queries!({
// FIXME(RPITIT): DRY-er code please
let item_ty =
tcx.mk_projection(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// RPITITs are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
})
}
pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
@ -90,6 +113,11 @@ pub(super) fn explicit_item_bounds(
span,
..
}) => opaque_type_bounds(tcx, def_id, bounds, *span),
hir::Node::Item(hir::Item {
kind: hir::ItemKind::ImplTraitPlaceholder(hir::ImplTraitPlaceholder { bounds }),
span,
..
}) => impl_trait_in_trait_item_bounds(tcx, def_id, bounds, *span),
_ => bug!("item_bounds called on {:?}", def_id),
}
}