Auto merge of #129244 - cjgillot:opaque-hir, r=compiler-errors

Make opaque types regular HIR nodes

Having opaque types as HIR owner introduces all sorts of complications. This PR proposes to make them regular HIR nodes instead.

I haven't gone through all the test changes yet, so there may be a few surprises.

Many thanks to `@camelid` for the first draft.
Fixes https://github.com/rust-lang/rust/issues/129023

Fixes #129099
Fixes #125843
Fixes #119716
Fixes #121422
This commit is contained in:
bors 2024-10-05 06:19:35 +00:00
commit 5a4ee43c38
105 changed files with 1056 additions and 1112 deletions

View file

@ -252,10 +252,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
tcx.dcx().span_bug(item.span, "expected opaque item");
};
let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id);
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
// `async-std` (and `pub async fn` in general).
@ -265,16 +262,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
return;
}
let span = tcx.def_span(item.owner_id.def_id);
let span = tcx.def_span(def_id);
if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
if tcx.type_of(def_id).instantiate_identity().references_error() {
return;
}
if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() {
if check_opaque_for_cycles(tcx, def_id, span).is_err() {
return;
}
let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, origin);
let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
}
/// Checks that an opaque type does not contain cycles.
@ -481,8 +478,7 @@ fn sanity_check_found_hidden_type<'tcx>(
/// 2. Checking that all lifetimes that are implicitly captured are mentioned.
/// 3. Asserting that all parameters mentioned in the captures list are invariant.
fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
let hir::OpaqueTy { bounds, .. } =
*tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
hir::GenericBound::Use(bounds, ..) => Some(bounds),
_ => None,

View file

@ -93,7 +93,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
// it's a refinement to a TAIT.
if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| {
matches!(
node.expect_item().expect_opaque_ty().origin,
node.expect_opaque_ty().origin,
hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::FnReturn { parent, .. }
if parent == impl_m.def_id.expect_local()
)

View file

@ -185,15 +185,16 @@ where
}
}
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
let node = tcx.hir_owner_node(def_id);
fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let node = tcx.hir_node_by_def_id(def_id);
let mut res = match node {
hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
hir::OwnerNode::Item(item) => check_item(tcx, item),
hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
hir::OwnerNode::Synthetic => unreachable!(),
hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
hir::Node::Item(item) => check_item(tcx, item),
hir::Node::TraitItem(item) => check_trait_item(tcx, item),
hir::Node::ImplItem(item) => check_impl_item(tcx, item),
hir::Node::ForeignItem(item) => check_foreign_item(tcx, item),
hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)),
_ => unreachable!(),
};
if let Some(generics) = node.generics() {
@ -201,6 +202,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG
res = res.and(check_param_wf(tcx, param));
}
}
res
}
@ -2172,10 +2174,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_module_items(module);
let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id));
res =
res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
res =
res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
res = res
.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
if module == LocalModDefId::CRATE_DEF_ID {
super::entry::check_for_entry_fn(tcx);
}

View file

@ -260,8 +260,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
| hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Struct(_, generics) => (generics, true),
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
hir::ItemKind::TyAlias(_, generics) => (generics, false),
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
_ => return,
};
@ -328,6 +327,19 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
intravisit::walk_expr(self, expr);
}
/// Don't call `type_of` on opaque types, since that depends on type checking function bodies.
/// `check_item_type` ensures that it's called instead.
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
let def_id = opaque.def_id;
self.tcx.ensure().generics_of(def_id);
self.tcx.ensure().predicates_of(def_id);
self.tcx.ensure().explicit_item_bounds(def_id);
self.tcx.ensure().explicit_item_super_predicates(def_id);
self.tcx.ensure().item_bounds(def_id);
self.tcx.ensure().item_super_predicates(def_id);
intravisit::walk_opaque_ty(self, opaque);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
lower_trait_item(self.tcx, trait_item.trait_item_id());
intravisit::walk_trait_item(self, trait_item);
@ -731,18 +743,6 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
}
// Don't call `type_of` on opaque types, since that depends on type
// checking function bodies. `check_item_type` ensures that it's called
// instead.
hir::ItemKind::OpaqueTy(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().predicates_of(def_id);
tcx.ensure().explicit_item_bounds(def_id);
tcx.ensure().explicit_item_super_predicates(def_id);
tcx.ensure().item_bounds(def_id);
tcx.ensure().item_super_predicates(def_id);
}
hir::ItemKind::TyAlias(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
@ -1852,12 +1852,8 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
}
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
match tcx.hir_node_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
}
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
}
let opaque = tcx.hir().expect_opaque_ty(def_id);
matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
}
fn rendered_precise_capturing_args<'tcx>(
@ -1870,12 +1866,10 @@ fn rendered_precise_capturing_args<'tcx>(
return tcx.rendered_precise_capturing_args(opaque_def_id);
}
tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map(
|bound| match bound {
hir::GenericBound::Use(args, ..) => {
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
}
_ => None,
},
)
tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound {
hir::GenericBound::Use(args, ..) => {
Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
}
_ => None,
})
}

View file

@ -1,4 +1,3 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::intravisit;
use rustc_middle::hir::nested_filter::OnlyBodies;
@ -10,12 +9,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
return;
}
for id in tcx.hir().items() {
let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
let ty = tcx.type_of(id.owner_id).instantiate_identity();
tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty });
for id in tcx.hir_crate_items(()).opaques() {
let ty = tcx.type_of(id).instantiate_identity();
let span = tcx.def_span(id);
tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
}
}

View file

@ -24,6 +24,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
tcx.opt_rpitit_info(def_id.to_def_id())
{
debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}");
let trait_def_id = tcx.parent(fn_def_id);
let opaque_ty_generics = tcx.generics_of(opaque_def_id);
let opaque_ty_parent_count = opaque_ty_generics.parent_count;
@ -207,36 +208,33 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
| Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(&hir::OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl }
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
..
}) => {
if in_trait_or_impl.is_some() {
assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
} else {
assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
}
Some(fn_def_id.to_def_id())
Node::OpaqueTy(&hir::OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl }
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
..
}) => {
if in_trait_or_impl.is_some() {
assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
} else {
assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
}
ItemKind::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
..
}) => {
if in_assoc_ty {
assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
} else {
assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
}
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
// Opaque types are always nested within another item, and
// inherit the generics of the item.
Some(parent.to_def_id())
Some(fn_def_id.to_def_id())
}
Node::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
..
}) => {
if in_assoc_ty {
assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
} else {
assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
}
_ => None,
},
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
// Opaque types are always nested within another item, and
// inherit the generics of the item.
Some(parent.to_def_id())
}
_ => None,
};
@ -272,13 +270,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
ItemKind::TyAlias(..)
| ItemKind::Enum(..)
| ItemKind::Struct(..)
| ItemKind::OpaqueTy(..)
| ItemKind::Union(..) => (None, Defaults::Allowed),
ItemKind::Const(..) => (None, Defaults::Deny),
_ => (None, Defaults::FutureCompatDisallowed),
}
}
Node::OpaqueTy(..) => (None, Defaults::Allowed),
// GATs
Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
(None, Defaults::Deny)

View file

@ -335,8 +335,7 @@ pub(super) fn explicit_item_bounds_with_filter(
// RPITIT's bounds are the same as opaque type bounds, but with
// a projection self type.
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item();
let opaque_ty = item.expect_opaque_ty();
let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
let item_ty = Ty::new_projection_from_args(
tcx,
def_id.to_def_id(),
@ -347,7 +346,7 @@ pub(super) fn explicit_item_bounds_with_filter(
opaque_def_id.expect_local(),
opaque_ty.bounds,
item_ty,
item.span,
opaque_ty.span,
filter,
);
assert_only_contains_predicates_from(filter, bounds, item_ty);
@ -369,11 +368,7 @@ pub(super) fn explicit_item_bounds_with_filter(
span,
..
}) => associated_type_bounds(tcx, def_id, bounds, *span, filter),
hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, origin, .. }),
span,
..
}) => match origin {
hir::Node::OpaqueTy(hir::OpaqueTy { bounds, origin, span, .. }) => match origin {
// Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_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.
@ -412,7 +407,7 @@ pub(super) fn explicit_item_bounds_with_filter(
}
},
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
_ => bug!("item_bounds called on {:?}", def_id),
node => bug!("item_bounds called on {def_id:?} => {node:?}"),
};
ty::EarlyBinder::bind(bounds)

View file

@ -330,7 +330,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// 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 {
if let Node::OpaqueTy(..) = node {
let opaque_ty_node = tcx.parent_hir_node(hir_id);
let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node
else {

View file

@ -11,10 +11,13 @@ use std::fmt;
use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
use rustc_hir::{
GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
};
use rustc_macros::extension;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::*;
@ -74,7 +77,7 @@ impl ResolvedArg {
struct NamedVarMap {
// maps from every use of a named (not anonymous) bound var to a
// `ResolvedArg` describing how that variable is bound
defs: HirIdMap<ResolvedArg>,
defs: ItemLocalMap<ResolvedArg>,
// Maps relevant hir items to the bound vars on them. These include:
// - function defs
@ -82,7 +85,7 @@ struct NamedVarMap {
// - closures
// - trait refs
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
}
struct BoundVarContext<'a, 'tcx> {
@ -225,10 +228,10 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
resolve_bound_vars,
named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
named_variable_map: |tcx, id| &tcx.resolve_bound_vars(id).defs,
is_late_bound_map,
object_lifetime_default,
late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id),
late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars,
..*providers
};
@ -265,16 +268,12 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
hir::OwnerNode::Synthetic => unreachable!(),
}
let mut rl = ResolveBoundVars::default();
for (hir_id, v) in named_variable_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
for (hir_id, v) in named_variable_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
let defs = named_variable_map.defs.into_sorted_stable_ord();
let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
let rl = ResolveBoundVars {
defs: SortedMap::from_presorted_elements(defs),
late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
};
debug!(?rl.defs);
debug!(?rl.late_bound_vars);
@ -340,7 +339,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Binder { hir_id, .. } => {
// Nested poly trait refs have the binders concatenated
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
full_binders.extend(supertrait_bound_vars);
break (full_binders, BinderScopeType::Concatenating);
}
@ -486,6 +485,31 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self))]
fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
// We want to start our early-bound indices at the end of the parent scope,
// not including any parent `impl Trait`s.
let mut bound_vars = FxIndexMap::default();
debug!(?opaque.generics.params);
for param in opaque.generics.params {
let (def_id, reg) = ResolvedArg::early(param);
bound_vars.insert(def_id, reg);
}
let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
let scope = Scope::Binder {
hir_id,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
};
self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
})
}
#[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match &item.kind {
@ -513,38 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// These sorts of items have no lifetime parameters at all.
intravisit::walk_item(self, item);
}
hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn { parent, .. }
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
| hir::OpaqueTyOrigin::TyAlias { parent, .. },
generics,
..
}) => {
// We want to start our early-bound indices at the end of the parent scope,
// not including any parent `impl Trait`s.
let mut bound_vars = FxIndexMap::default();
debug!(?generics.params);
for param in generics.params {
let (def_id, reg) = ResolvedArg::early(param);
bound_vars.insert(def_id, reg);
}
let scope = Scope::Root { opt_parent_item: Some(parent) };
self.with(scope, |this| {
let scope = Scope::Binder {
hir_id: item.hir_id(),
bound_vars,
s: this.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
};
this.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |this| intravisit::walk_item(this, item))
});
})
}
hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Const(_, generics, _)
| hir::ItemKind::Enum(_, generics)
@ -684,22 +676,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
hir::TyKind::Ref(lifetime_ref, ref mt) => {
self.visit_lifetime(lifetime_ref);
let scope = Scope::ObjectLifetimeDefault {
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
s: self.scope,
};
self.with(scope, |this| this.visit_ty(mt.ty));
}
hir::TyKind::OpaqueDef(item_id, lifetimes) => {
hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
self.visit_opaque_ty(opaque_ty);
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
// `type MyAnonTy<'b> = impl MyTrait<'b>;`
// ^ ^ this gets resolved in the scope of
// the opaque_ty generics
let opaque_ty = self.tcx.hir().item(item_id);
match &opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {}
i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
};
// Resolve the lifetimes that are applied to the opaque type.
// These are resolved in the current scope.
@ -714,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// and ban them. Type variables instantiated inside binders aren't
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).copied();
let def = self.map.defs.get(&lifetime.hir_id.local_id).copied();
let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
@ -722,9 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
{
// Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
// it must be a reified late-bound lifetime from a trait goal.
hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy { .. }, ..
}) => "higher-ranked lifetime from outer `impl Trait`",
hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`",
// Other items are fine.
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
continue;
@ -740,8 +727,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
{
let opaque_span = self.tcx.def_span(item_id.owner_id);
(opaque_span, Some(opaque_span))
(opaque_ty.span, Some(opaque_ty.span))
} else {
(lifetime.ident.span, None)
};
@ -854,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let bound_vars: Vec<_> =
self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
self.map.late_bound_vars.insert(hir_id, bound_vars);
self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
}
self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
intravisit::walk_fn_kind(self, fk);
@ -1032,10 +1018,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
}
fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
bug!(
"overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
self.map.late_bound_vars[&hir_id]
self.map.late_bound_vars[&hir_id.local_id]
)
}
}
@ -1394,9 +1380,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
kind.descr(param_def_id.to_def_id())
),
};
self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
} else {
self.map.defs.insert(hir_id, def);
self.map.defs.insert(hir_id.local_id, def);
}
return;
}
@ -1429,7 +1415,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
}
});
self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
return;
}
Scope::Root { .. } => break,
@ -1539,7 +1525,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// This index can be used with `generic_args` since `parent_count == 0`.
let index = generics.param_def_id_to_index[&param_def_id] as usize;
generic_args.args.get(index).and_then(|arg| match arg {
GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id).copied(),
GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id.local_id).copied(),
_ => None,
})
}
@ -1829,7 +1815,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
debug!(span = ?lifetime_ref.ident.span);
self.map.defs.insert(lifetime_ref.hir_id, def);
self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
}
/// Sometimes we resolve a lifetime, but later find that it is an
@ -1840,8 +1826,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
lifetime_ref: &'tcx hir::Lifetime,
bad_def: ResolvedArg,
) {
// FIXME(#120456) - is `swap_remove` correct?
let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id);
let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id);
assert_eq!(old_value, Some(bad_def));
}
@ -2011,7 +1996,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
// And this is exercised in:
// `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap();
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
let existing_bound_vars_saved = existing_bound_vars.clone();
existing_bound_vars.extend(bound_vars);
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);

View file

@ -529,10 +529,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
|CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
|ty| ty.instantiate_identity(),
),
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
@ -545,6 +541,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
}
},
Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
|CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
|ty| ty.instantiate_identity(),
),
Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
@ -603,42 +604,25 @@ pub(super) fn type_of_opaque(
def_id: DefId,
) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
if let Some(def_id) = def_id.as_local() {
use rustc_hir::*;
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
..
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
| hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl },
..
}) => {
if in_trait_or_impl == Some(hir::RpitContext::Trait)
&& !tcx.defaultness(owner).has_value()
{
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
opaque::find_opaque_ty_constraints_for_tait(tcx, def_id)
}
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id)
}
// Opaque types desugared from `impl Trait`.
hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
| hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
if in_trait_or_impl == Some(hir::RpitContext::Trait)
&& !tcx.defaultness(owner).has_value()
{
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
_ => {
span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
}
},
x => {
bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
}))
} else {

View file

@ -2087,43 +2087,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
}
&hir::TyKind::OpaqueDef(item_id, lifetimes) => {
let opaque_ty = tcx.hir().item(item_id);
&hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
let local_def_id = opaque_ty.def_id;
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => {
let local_def_id = item_id.owner_id.def_id;
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
// type a projection.
match origin {
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
} => self.lower_opaque_ty(
tcx.associated_type_for_impl_trait_in_trait(local_def_id)
.to_def_id(),
lifetimes,
true,
),
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::TyAlias { .. } => {
self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false)
}
}
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
// type a projection.
match opaque_ty.origin {
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
} => self.lower_opaque_ty(
tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(),
lifetimes,
true,
),
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::TyAlias { .. } => {
self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false)
}
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
// If we encounter a type relative path with RTN generics, then it must have
@ -2289,7 +2282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span_bug!(
tcx.def_span(param.def_id),
"only expected lifetime for opaque's own generics, got {:?}",
param.kind
param
);
};
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else {

View file

@ -1,6 +1,5 @@
use std::fmt::Write;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_middle::ty::{GenericArgs, TyCtxt};
use rustc_span::symbol::sym;
@ -24,18 +23,18 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
}
pub(crate) fn variances(tcx: TyCtxt<'_>) {
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
for id in tcx.hir().items() {
let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
let crate_items = tcx.hir_crate_items(());
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
for id in crate_items.opaques() {
tcx.dcx().emit_err(crate::errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances: format_variances(tcx, id.owner_id.def_id),
span: tcx.def_span(id),
variances: format_variances(tcx, id),
});
}
}
for id in tcx.hir().items() {
for id in crate_items.free_items() {
if !tcx.has_attr(id.owner_id, sym::rustc_variance) {
continue;
}