Rollup merge of #114267 - compiler-errors:rpitit-opaque-bounds, r=spastorino
Map RPITIT's opaque type bounds back from projections to opaques An RPITIT in a program's AST is eventually translated into both a projection GAT and an opaque. The opaque is used for default trait methods, like: ``` trait Foo { fn bar() -> impl Sized { 0i32 } } ``` The item bounds for both the projection and opaque are identical, and both have a *projection* self ty. This is mostly okay, since we can normalize this projection within the default trait method body to the opaque, but it does two things: 1. it leads to bugs in places where we don't normalize item bounds, like `deduce_future_output_from_obligations` 2. it leads to extra match arms that are both suspicious looking and also easy to miss This PR maps the opaque type bounds of the RPITIT's *opaque* back to the opaque's self type to avoid this quirk. Then we can fix the UI test for #108304 (1.) and also remove a bunch of match arms (2.). Fixes #108304 r? `@spastorino`
This commit is contained in:
commit
692d764e53
9 changed files with 54 additions and 72 deletions
|
@ -576,7 +576,6 @@ fn find_and_apply_rpit_args<'tcx>(
|
|||
struct Visitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque: DefId,
|
||||
function: DefId,
|
||||
seen: FxHashSet<DefId>,
|
||||
}
|
||||
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
|
||||
|
@ -601,19 +600,6 @@ fn find_and_apply_rpit_args<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Projection, alias) => {
|
||||
if self.tcx.is_impl_trait_in_trait(alias.def_id)
|
||||
&& self.tcx.impl_trait_in_trait_parent_fn(alias.def_id) == self.function
|
||||
{
|
||||
// If we're lowering to associated item, install the opaque type which is just
|
||||
// the `type_of` of the trait's associated item. If we're using the old lowering
|
||||
// strategy, then just reinterpret the associated type like an opaque :^)
|
||||
self.tcx
|
||||
.type_of(alias.def_id)
|
||||
.instantiate(self.tcx, alias.args)
|
||||
.visit_with(self)?;
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
self.tcx
|
||||
.type_of(alias.def_id)
|
||||
|
@ -627,7 +613,7 @@ fn find_and_apply_rpit_args<'tcx>(
|
|||
}
|
||||
}
|
||||
if let ControlFlow::Break(args) =
|
||||
ret.visit_with(&mut Visitor { tcx, function, opaque, seen: Default::default() })
|
||||
ret.visit_with(&mut Visitor { tcx, opaque, seen: Default::default() })
|
||||
{
|
||||
trace!(?args);
|
||||
trace!("expected: {hidden_ty:#?}");
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::astconv::{AstConv, PredicateFilter};
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::GenericArgs;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
@ -113,7 +113,7 @@ pub(super) fn explicit_item_bounds(
|
|||
..
|
||||
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
|
||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
|
||||
span,
|
||||
..
|
||||
}) => {
|
||||
|
@ -121,6 +121,27 @@ pub(super) fn explicit_item_bounds(
|
|||
let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
||||
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
||||
}
|
||||
// Since RPITITs are astconv'd as projections in `ast_ty_to_ty`, when we're asking
|
||||
// for the item bounds of the *opaques* in a trait's default method signature, we
|
||||
// need to map these projections back to opaques.
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
|
||||
span,
|
||||
..
|
||||
}) => {
|
||||
let (hir::OpaqueTyOrigin::FnReturn(fn_def_id)
|
||||
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin
|
||||
else {
|
||||
bug!()
|
||||
};
|
||||
let args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
||||
tcx.arena.alloc_slice(
|
||||
&opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
||||
.to_vec()
|
||||
.fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
|
||||
)
|
||||
}
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
|
||||
_ => bug!("item_bounds called on {:?}", def_id),
|
||||
};
|
||||
|
@ -135,3 +156,26 @@ pub(super) fn item_bounds(
|
|||
tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
|
||||
})
|
||||
}
|
||||
|
||||
struct AssocTyToOpaque<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_def_id: DefId,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
|
||||
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. })
|
||||
= self.tcx.opt_rpitit_info(projection_ty.def_id)
|
||||
&& fn_def_id == self.fn_def_id
|
||||
{
|
||||
self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue