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:
@@ -576,7 +576,6 @@ fn find_and_apply_rpit_args<'tcx>(
|
|||||||
struct Visitor<'tcx> {
|
struct Visitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
opaque: DefId,
|
opaque: DefId,
|
||||||
function: DefId,
|
|
||||||
seen: FxHashSet<DefId>,
|
seen: FxHashSet<DefId>,
|
||||||
}
|
}
|
||||||
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
|
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) => {
|
ty::Alias(ty::Weak, alias) => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.type_of(alias.def_id)
|
.type_of(alias.def_id)
|
||||||
@@ -627,7 +613,7 @@ fn find_and_apply_rpit_args<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let ControlFlow::Break(args) =
|
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!(?args);
|
||||||
trace!("expected: {hidden_ty:#?}");
|
trace!("expected: {hidden_ty:#?}");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::astconv::{AstConv, PredicateFilter};
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::util;
|
use rustc_infer::traits::util;
|
||||||
use rustc_middle::ty::GenericArgs;
|
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::def_id::{DefId, LocalDefId};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ pub(super) fn explicit_item_bounds(
|
|||||||
..
|
..
|
||||||
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
||||||
hir::Node::Item(hir::Item {
|
hir::Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
|
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
|
||||||
span,
|
span,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
@@ -121,6 +121,27 @@ pub(super) fn explicit_item_bounds(
|
|||||||
let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
||||||
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
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(..), .. }) => &[],
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
|
||||||
_ => bug!("item_bounds called on {:?}", def_id),
|
_ => 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)))
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -558,10 +558,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
let pred = clause.kind().rebind(match clause.kind().skip_binder() {
|
let pred = clause.kind().rebind(match clause.kind().skip_binder() {
|
||||||
ty::ClauseKind::Trait(trait_pred) => {
|
ty::ClauseKind::Trait(trait_pred) => {
|
||||||
// FIXME(rpitit): This will need to be fixed when we move to associated types
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*trait_pred.trait_ref.self_ty().kind(),
|
*trait_pred.trait_ref.self_ty().kind(),
|
||||||
ty::Alias(_, ty::AliasTy { def_id, args: alias_args, .. })
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
|
||||||
if def_id == rpit_def_id && args == alias_args
|
if def_id == rpit_def_id && args == alias_args
|
||||||
));
|
));
|
||||||
ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
|
ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty))
|
||||||
@@ -569,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::ClauseKind::Projection(mut proj_pred) => {
|
ty::ClauseKind::Projection(mut proj_pred) => {
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*proj_pred.projection_ty.self_ty().kind(),
|
*proj_pred.projection_ty.self_ty().kind(),
|
||||||
ty::Alias(_, ty::AliasTy { def_id, args: alias_args, .. })
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. })
|
||||||
if def_id == rpit_def_id && args == alias_args
|
if def_id == rpit_def_id && args == alias_args
|
||||||
));
|
));
|
||||||
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
|
proj_pred = proj_pred.with_self_ty(self.tcx, ty);
|
||||||
|
|||||||
@@ -723,11 +723,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.iter_instantiated_copied(self.tcx, args)
|
.iter_instantiated_copied(self.tcx, args)
|
||||||
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
||||||
ty::Error(_) => return None,
|
ty::Error(_) => return None,
|
||||||
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
|
|
||||||
.tcx
|
|
||||||
.explicit_item_bounds(proj.def_id)
|
|
||||||
.iter_instantiated_copied(self.tcx, proj.args)
|
|
||||||
.find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
|
|
||||||
_ => span_bug!(
|
_ => span_bug!(
|
||||||
self.tcx.def_span(expr_def_id),
|
self.tcx.def_span(expr_def_id),
|
||||||
"async fn generator return type not an inference variable: {ret_ty}"
|
"async fn generator return type not an inference variable: {ret_ty}"
|
||||||
|
|||||||
@@ -619,13 +619,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
{
|
{
|
||||||
hidden_ty
|
hidden_ty
|
||||||
}
|
}
|
||||||
// FIXME(RPITIT): This can go away when we move to associated types
|
|
||||||
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
|
|
||||||
ty::Alias(ty::Projection, ty::AliasTy { def_id: def_id2, args: args2, .. })
|
|
||||||
if def_id == def_id2 && args == args2 =>
|
|
||||||
{
|
|
||||||
hidden_ty
|
|
||||||
}
|
|
||||||
_ => ty,
|
_ => ty,
|
||||||
},
|
},
|
||||||
lt_op: |lt| lt,
|
lt_op: |lt| lt,
|
||||||
|
|||||||
@@ -2625,19 +2625,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
|
matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId {
|
|
||||||
match self.opt_rpitit_info(def_id) {
|
|
||||||
Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
|
|
||||||
| Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
|
|
||||||
None => {
|
|
||||||
while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
|
|
||||||
def_id = self.parent(def_id);
|
|
||||||
}
|
|
||||||
def_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the `DefId` of the item within which the `impl Trait` is declared.
|
/// Returns the `DefId` of the item within which the `impl Trait` is declared.
|
||||||
/// For type-alias-impl-trait this is the `type` alias.
|
/// For type-alias-impl-trait this is the `type` alias.
|
||||||
/// For impl-trait-in-assoc-type this is the assoc type.
|
/// For impl-trait-in-assoc-type this is the assoc type.
|
||||||
|
|||||||
@@ -181,8 +181,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|||||||
|
|
||||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
||||||
if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind()
|
if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind()
|
||||||
&& self.tcx.is_impl_trait_in_trait(unshifted_alias_ty.def_id)
|
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }
|
||||||
&& self.tcx.impl_trait_in_trait_parent_fn(unshifted_alias_ty.def_id) == self.fn_def_id
|
| ty::ImplTraitInTraitData::Impl { fn_def_id, .. })
|
||||||
|
= self.tcx.opt_rpitit_info(unshifted_alias_ty.def_id)
|
||||||
|
&& fn_def_id == self.fn_def_id
|
||||||
&& self.seen.insert(unshifted_alias_ty.def_id)
|
&& self.seen.insert(unshifted_alias_ty.def_id)
|
||||||
{
|
{
|
||||||
// We have entered some binders as we've walked into the
|
// We have entered some binders as we've walked into the
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// edition:2021
|
// edition:2021
|
||||||
// known-bug: #108304
|
// check-pass
|
||||||
|
|
||||||
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
|
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
error: concrete type differs from previous defining opaque type use
|
|
||||||
--> $DIR/default-body-with-rpit.rs:11:9
|
|
||||||
|
|
|
||||||
LL | ""
|
|
||||||
| ^^ expected `impl Debug`, got `&'static str`
|
|
||||||
|
|
|
||||||
note: previous use here
|
|
||||||
--> $DIR/default-body-with-rpit.rs:10:39
|
|
||||||
|
|
|
||||||
LL | async fn baz(&self) -> impl Debug {
|
|
||||||
| _______________________________________^
|
|
||||||
LL | | ""
|
|
||||||
LL | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error[E0720]: cannot resolve opaque type
|
|
||||||
--> $DIR/default-body-with-rpit.rs:10:28
|
|
||||||
|
|
|
||||||
LL | async fn baz(&self) -> impl Debug {
|
|
||||||
| ^^^^^^^^^^ cannot resolve opaque type
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0720`.
|
|
||||||
Reference in New Issue
Block a user