From dc0db358abe19481e475e10c32149b53370f1a1c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:57:31 +0200 Subject: Merging upstream version 1.72.1+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_hir_analysis/src/collect/generics_of.rs | 59 ++-- .../rustc_hir_analysis/src/collect/item_bounds.rs | 57 ++-- .../src/collect/predicates_of.rs | 328 ++++++++++++--------- .../src/collect/resolve_bound_vars.rs | 73 ++++- compiler/rustc_hir_analysis/src/collect/type_of.rs | 89 +++--- .../src/collect/type_of/opaque.rs | 131 +++++--- 6 files changed, 462 insertions(+), 275 deletions(-) (limited to 'compiler/rustc_hir_analysis/src/collect') diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ed60998ec..ccc9f8084 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -50,7 +50,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // We do not allow generic parameters in anon consts if we are inside // of a const parameter type, e.g. `struct Foo` is not allowed. None - } else if tcx.lazy_normalization() { + } else if tcx.features().generic_const_exprs { let parent_node = tcx.hir().get_parent(hir_id); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node && constant.hir_id == hir_id @@ -101,6 +101,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, + host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -123,9 +124,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { - Some(tcx.typeck_root_def_id(def_id.to_def_id())) - } // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { @@ -142,11 +140,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } } - Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { + Node::ConstBlock(_) + | 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 { + ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), in_trait, @@ -228,10 +227,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; + let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; + host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.params.len() }); @@ -253,11 +254,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; - let mut i = 0; + let mut i: u32 = 0; let mut next_index = || { let prev = i; i += 1; - prev as u32 + type_start + prev + type_start }; const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ @@ -297,7 +298,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }) } GenericParamKind::Const { default, .. } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { + let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host); + + if !matches!(allow_defaults, Defaults::Allowed) + && default.is_some() + // `rustc_host` effect params are allowed to have defaults. + && !is_host_param + { tcx.sess.span_err( param.span, "defaults for const parameters are only allowed in \ @@ -305,8 +312,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ); } + let index = next_index(); + + if is_host_param { + if let Some(idx) = host_effect_index { + bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + } + + host_effect_index = Some(parent_count + index as usize); + } + Some(ty::GenericParamDef { - index: next_index(), + index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, @@ -339,17 +356,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } // provide junk type parameter defs for const blocks. - if let Node::AnonConst(_) = node { - let parent_node = tcx.hir().get_parent(hir_id); - if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { - params.push(ty::GenericParamDef { - index: next_index(), - name: Symbol::intern(""), - def_id: def_id.to_def_id(), - pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, - }); - } + if let Node::ConstBlock(_) = node { + params.push(ty::GenericParamDef { + index: next_index(), + name: Symbol::intern(""), + def_id: def_id.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, + }); } let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); @@ -361,6 +375,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), + host_effect_index, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 948b903e5..57f74172e 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,5 +1,5 @@ use super::ItemCtxt; -use crate::astconv::{AstConv, OnlySelfBounds}; +use crate::astconv::{AstConv, PredicateFilter}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::subst::InternalSubsts; @@ -19,32 +19,34 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { - let item_ty = tcx.mk_projection( +) -> &'tcx [(ty::Clause<'tcx>, Span)] { + let item_ty = Ty::new_projection( + tcx, assoc_item_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, assoc_item_def_id), ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Associated types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty, - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { - proj.projection_ty.self_ty() == item_ty - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty, + let bounds_from_parent = trait_predicates + .predicates + .iter() + .copied() + .filter(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, + ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty, + ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, _ => false, - } - }); + }) + .map(|(clause, span)| (clause, span)); - let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -64,33 +66,34 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, -) -> &'tcx [(ty::Predicate<'tcx>, Span)] { +) -> &'tcx [(ty::Clause<'tcx>, Span)] { ty::print::with_no_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false)); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Opaque types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.predicates()) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // 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().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder(opaque_type_bounds( + return ty::EarlyBinder::bind(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - tcx.mk_projection( + Ty::new_projection( + tcx, def_id.to_def_id(), ty::InternalSubsts::identity_for_item(tcx, def_id), ), @@ -116,25 +119,23 @@ pub(super) fn explicit_item_bounds( }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { - tcx.mk_projection(def_id.to_def_id(), substs) + Ty::new_projection(tcx, def_id.to_def_id(), substs) } else { - tcx.mk_opaque(def_id.to_def_id(), substs) + Ty::new_opaque(tcx, def_id.to_def_id(), substs) }; opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } + hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder(bounds) + ty::EarlyBinder::bind(bounds) } pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List>> { +) -> ty::EarlyBinder<&'_ ty::List>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { - tcx.mk_predicates_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))) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e5b5dae55..129366641 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,8 +1,8 @@ -use crate::astconv::{AstConv, OnlySelfBounds}; +use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter}; use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use hir::{HirId, Node}; +use hir::{HirId, Lifetime, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{GenericPredicates, ToPredicate}; +use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -62,6 +62,67 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + match tcx.opt_rpitit_info(def_id.to_def_id()) { + Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => { + let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local()); + let opaque_ty_node = tcx.hir().get(opaque_ty_id); + let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else { + bug!("unexpected {opaque_ty_node:?}") + }; + + let mut predicates = Vec::new(); + + // RPITITs should inherit the predicates of their parent. This is + // both to ensure that the RPITITs are only instantiated when the + // parent predicates would hold, and also so that the param-env + // inherits these predicates as assumptions. + let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + predicates.extend( + tcx.explicit_predicates_of(fn_def_id).instantiate_own(tcx, identity_substs), + ); + + // We also install bidirectional outlives predicates for the RPITIT + // to keep the duplicates lifetimes from opaque lowering in sync. + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping.iter().map(|(lifetime, def_id)| { + (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + }), + tcx.generics_of(def_id.to_def_id()), + &mut predicates, + ); + + return ty::GenericPredicates { + parent: Some(tcx.parent(def_id.to_def_id())), + predicates: tcx.arena.alloc_from_iter(predicates), + }; + } + + Some(ImplTraitInTraitData::Impl { fn_def_id }) => { + let assoc_item = tcx.associated_item(def_id); + let trait_assoc_predicates = + tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap()); + + let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + let impl_def_id = tcx.parent(fn_def_id); + let impl_trait_ref_substs = + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs; + + let impl_assoc_substs = + impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs); + + let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs); + + return ty::GenericPredicates { + parent: Some(impl_def_id), + predicates: tcx.arena.alloc_from_iter(impl_predicates), + }; + } + + None => {} + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); @@ -75,7 +136,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. - let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); + let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => item.generics, @@ -125,8 +186,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen if let Some(self_bounds) = is_trait { predicates.extend( icx.astconv() - .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false)) - .predicates(), + .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) + .clauses(), ); } @@ -175,22 +236,24 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.predicates()); + predicates.extend(bounds.clauses()); trace!(?predicates); } GenericParamKind::Const { .. } => { let name = param.name.ident().name; let param_const = ty::ParamConst::new(index, name); - let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity(); + let ct_ty = tcx + .type_of(param.def_id.to_def_id()) + .no_bound_vars() + .expect("const parameters cannot be generic"); - let ct = tcx.mk_const(param_const, ct_ty); + let ct = ty::Const::new_param(tcx, param_const, ct_ty); - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::ConstArgHasType(ct, ct_ty), - )) - .to_predicate(tcx); - predicates.insert((predicate, param.span)); + predicates.insert(( + ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), + param.span, + )); index += 1; } @@ -219,7 +282,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } else { let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( - ty::PredicateKind::WellFormed(ty.into()), + ty::ClauseKind::WellFormed(ty.into()), bound_vars, ); predicates.insert((predicate.to_predicate(tcx), span)); @@ -234,7 +297,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend(bounds.predicates()); + predicates.extend(bounds.clauses()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -246,11 +309,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } _ => bug!(), }; - let pred = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)), - )) - .to_predicate(icx.tcx); - + let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) + .to_predicate(icx.tcx); (pred, span) })) } @@ -293,39 +353,22 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen 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 = icx.astconv().ast_region_to_region(&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 = duplicate.def_id.to_def_id(); - - let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; - - let dup_region = tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: dup_def, - index: dup_index, - name: duplicate.name.ident().name, - }); - predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(orig_region, dup_region), - ))) - .to_predicate(icx.tcx), - duplicate.span, - )); - predicates.push(( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives( - ty::OutlivesPredicate(dup_region, orig_region), - ))) - .to_predicate(icx.tcx), - duplicate.span, - )); - } + let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params) + .map(|(arg, dup)| { + let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; + (**arg, dup) + }) + .filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span))); + + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping, + generics, + &mut predicates, + ); debug!(?predicates); } @@ -335,13 +378,53 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } +/// Opaques have duplicated lifetimes and we need to compute bidirectional outlives predicates to +/// enforce that these lifetimes stay in sync. +fn compute_bidirectional_outlives_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, + lifetime_mapping: impl Iterator, + generics: &Generics, + predicates: &mut Vec<(ty::Clause<'tcx>, Span)>, +) { + let icx = ItemCtxt::new(tcx, item_def_id); + + for (arg, (dup_def, name, span)) in lifetime_mapping { + let orig_region = icx.astconv().ast_region_to_region(&arg, None); + if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { + // There is no late-bound lifetime to actually match up here, since the lifetime doesn't + // show up in the opaque's parent's substs. + continue; + } + + let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else { bug!() }; + + let dup_region = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name }, + ); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region)) + .to_predicate(tcx), + span, + )); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region)) + .to_predicate(tcx), + span, + )); + } +} + fn const_evaluatable_predicates_of( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> FxIndexSet<(ty::Predicate<'_>, Span)> { +) -> FxIndexSet<(ty::Clause<'_>, Span)> { struct ConstCollector<'tcx> { tcx: TyCtxt<'tcx>, - preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + preds: FxIndexSet<(ty::Clause<'tcx>, Span)>, } impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { @@ -349,11 +432,8 @@ fn const_evaluatable_predicates_of( let ct = ty::Const::from_anon_const(self.tcx, c.def_id); if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); - self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) - .to_predicate(self.tcx), - span, - )); + self.preds + .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span)); } } @@ -441,13 +521,9 @@ pub(super) fn explicit_predicates_of<'tcx>( .iter() .copied() .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()), - ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => { - !is_assoc_item_ty(proj.projection_ty.self_ty()) - } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { - !is_assoc_item_ty(outlives.0) - } + ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()), + ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()), + ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0), _ => true, }) .collect(); @@ -460,7 +536,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } } else { - if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { + if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); @@ -488,9 +564,7 @@ pub(super) fn explicit_predicates_of<'tcx>( .predicates .into_iter() .filter(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) = - pred.kind().skip_binder() - { + if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() { match ct.kind() { ty::ConstKind::Param(param_const) => { let defaulted_param_idx = tcx @@ -544,19 +618,6 @@ pub(super) fn explicit_predicates_of<'tcx>( } } -#[derive(Copy, Clone, Debug)] -pub enum PredicateFilter { - /// All predicates may be implied by the trait - All, - - /// Only traits that reference `Self: ..` are implied by the trait - SelfOnly, - - /// Only traits that reference `Self: ..` and define an associated type - /// with the given ident are implied by the trait - SelfThatDefines(Ident), -} - /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are converted and stored. This also ensures that /// the transitive super-predicates are converted. @@ -578,11 +639,15 @@ pub(super) fn implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { - if tcx.is_trait_alias(trait_def_id.to_def_id()) { - implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All) - } else { - tcx.super_predicates_of(trait_def_id) - } + implied_predicates_with_filter( + tcx, + trait_def_id.to_def_id(), + if tcx.is_trait_alias(trait_def_id.to_def_id()) { + PredicateFilter::All + } else { + PredicateFilter::SelfAndAssociatedTypeBounds + }, + ) } /// Ensures that the super-predicates of the trait with a `DefId` @@ -615,48 +680,18 @@ pub(super) fn implied_predicates_with_filter( let icx = ItemCtxt::new(tcx, trait_def_id); let self_param_ty = tcx.types.self_param; - let (superbounds, where_bounds_that_match) = match filter { - PredicateFilter::All => ( - // Convert the bounds that follow the colon (or equal in trait aliases) - icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)), - // Also include all where clause bounds - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(false), - None, - ), - ), - PredicateFilter::SelfOnly => ( - // Convert the bounds that follow the colon (or equal in trait aliases) - icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)), - // Include where clause bounds for `Self` - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(true), - None, - ), - ), - PredicateFilter::SelfThatDefines(assoc_name) => ( - // Convert the bounds that follow the colon (or equal) that reference the associated name - icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name), - // Include where clause bounds for `Self` that reference the associated name - icx.type_parameter_bounds_in_generics( - generics, - item.owner_id.def_id, - self_param_ty, - OnlySelfBounds(true), - Some(assoc_name), - ), - ), - }; + let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter); + + let where_bounds_that_match = icx.type_parameter_bounds_in_generics( + generics, + item.owner_id.def_id, + self_param_ty, + filter, + ); // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are converted, which will, in @@ -665,7 +700,7 @@ pub(super) fn implied_predicates_with_filter( if matches!(filter, PredicateFilter::SelfOnly) { for &(pred, span) in implied_bounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() + if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::ImplPolarity::Positive { tcx.at(span).super_predicates_of(bound.def_id()); @@ -684,6 +719,7 @@ pub(super) fn type_param_predicates( (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; // In the AST, bounds can derive from two places. Either // written inline like `` or in a where-clause like @@ -693,7 +729,7 @@ pub(super) fn type_param_predicates( let param_owner = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(param_owner); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); + let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner { @@ -721,7 +757,7 @@ pub(super) fn type_param_predicates( ItemKind::Fn(.., generics, _) | ItemKind::Impl(&hir::Impl { generics, .. }) | ItemKind::TyAlias(_, generics) - | ItemKind::OpaqueTy(OpaqueTy { + | ItemKind::OpaqueTy(&OpaqueTy { generics, origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. @@ -757,12 +793,11 @@ pub(super) fn type_param_predicates( ast_generics, def_id, ty, - OnlySelfBounds(true), - Some(assoc_name), + PredicateFilter::SelfThatDefines(assoc_name), ) .into_iter() .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index), + ty::ClauseKind::Trait(data) => data.self_ty().is_param(index), _ => false, }), ); @@ -782,9 +817,8 @@ impl<'tcx> ItemCtxt<'tcx> { ast_generics: &'tcx hir::Generics<'tcx>, param_def_id: LocalDefId, ty: Ty<'tcx>, - only_self_bounds: OnlySelfBounds, - assoc_name: Option, - ) -> Vec<(ty::Predicate<'tcx>, Span)> { + filter: PredicateFilter, + ) -> Vec<(ty::Clause<'tcx>, Span)> { let mut bounds = Bounds::default(); for predicate in ast_generics.predicates { @@ -792,9 +826,23 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; + let (only_self_bounds, assoc_name) = match filter { + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + (OnlySelfBounds(false), None) + } + PredicateFilter::SelfOnly => (OnlySelfBounds(true), None), + PredicateFilter::SelfThatDefines(assoc_name) => { + (OnlySelfBounds(true), Some(assoc_name)) + } + }; + + // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we + // want to only consider predicates with `Self: ...`, but we don't want + // `OnlySelfBounds(true)` since we want to collect the nested associated + // type bound as well. let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty - } else if !only_self_bounds.0 { + } else if matches!(filter, PredicateFilter::All) { self.to_ty(predicate.bounded_ty) } else { continue; @@ -813,7 +861,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.predicates().collect() + bounds.clauses().collect() } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 794812a5c..acd0bcd8e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::fmt; use crate::errors; @@ -338,7 +338,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::TraitRefBoundary { .. } => { // We should only see super trait lifetimes if there is a `Binder` above - assert!(supertrait_bound_vars.is_empty()); + // though this may happen when we call `poly_trait_ref_binder_info` with + // an (erroneous, #113423) associated return type bound in an impl header. + if !supertrait_bound_vars.is_empty() { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!( + "found supertrait lifetimes without a binder to append \ + them to: {supertrait_bound_vars:?}" + ), + ); + } break (vec![], BinderScopeType::Normal); } @@ -556,7 +566,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent), generics, .. @@ -1344,12 +1354,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. } => { - let mut err = self.tcx.sess.struct_span_err( - lifetime_ref.ident.span, - "`impl Trait` can only mention lifetimes bound at the fn or impl level", - ); - err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here"); - err.emit(); + self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime { + span: lifetime_ref.ident.span, + param_span: self.tcx.def_span(region_def_id), + }); return; } Scope::Root { .. } => break, @@ -1379,6 +1387,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; let mut crossed_anon_const = false; + let result = loop { match *scope { Scope::Body { s, .. } => { @@ -1446,6 +1455,50 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { return; } + // We may fail to resolve higher-ranked ty/const vars that are mentioned by APIT. + // AST-based resolution does not care for impl-trait desugaring, which are the + // responsibility of lowering. This may create a mismatch between the resolution + // AST found (`param_def_id`) which points to HRTB, and what HIR allows. + // ``` + // fn foo(x: impl for Trait>) {} + // ``` + // + // In such case, walk back the binders to diagnose it properly. + let mut scope = self.scope; + loop { + match *scope { + Scope::Binder { + where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. + } => { + let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) { + DefKind::TyParam => errors::LateBoundInApit::Type { + span: self.tcx.hir().span(hir_id), + param_span: self.tcx.def_span(param_def_id), + }, + DefKind::ConstParam => errors::LateBoundInApit::Const { + span: self.tcx.hir().span(hir_id), + param_span: self.tcx.def_span(param_def_id), + }, + kind => { + bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id())) + } + }); + self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + return; + } + Scope::Root { .. } => break, + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { + scope = s; + } + } + } + self.tcx.sess.delay_span_bug( self.tcx.hir().span(hir_id), format!("could not resolve {param_def_id:?}"), @@ -1761,7 +1814,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::ClauseKind::Trait(data) => { // The order here needs to match what we would get from `subst_supertrait` let pred_bound_vars = bound_predicate.bound_vars(); let mut all_bound_vars = bound_vars.clone(); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8e082d3c5..3755342ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -16,6 +16,7 @@ mod opaque; fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; + use rustc_middle::ty::Ty; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() }; @@ -25,21 +26,15 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let (generics, arg_idx) = match parent_node { // Easy case: arrays repeat expressions. - Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id() == hir_id => { return tcx.types.usize } - Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { + Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { return tcx.typeck(def_id).node_type(e.hir_id) } - Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) - if anon_const.hir_id == hir_id => - { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - return substs.as_inline_const().ty() - } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { @@ -73,7 +68,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { ) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { - return tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find trait"); + return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait"); }; let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( @@ -85,7 +80,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find associated const on trait") + Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait") } } @@ -105,7 +100,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // arm would handle this. // // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU - Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { + Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Find the Item containing the associated type so we can create an ItemCtxt. // Using the ItemCtxt convert the HIR for the unresolved assoc type into a // ty which is a fully resolved projection. @@ -143,7 +138,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } else { // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); @@ -160,7 +155,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // As there is no relevant param for `def_id`, we simply return // `None` here. let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find type-dependent def for {:?}", parent_node_id), ); @@ -180,12 +175,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (tcx.generics_of(type_dependent_def), idx) } - Node::Ty(&Ty { kind: TyKind::Path(_), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. }) | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. }) | Node::TraitRef(..) | Node::Pat(_) => { let path = match parent_node { - Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) + Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. }) | Node::TraitRef(&TraitRef { path, .. }) => &*path, Node::Expr(&Expr { kind: @@ -201,14 +196,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { path } else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); } } _ => { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent path {:?}", parent_node), ); @@ -230,7 +225,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .position(|ct| ct.hir_id == hir_id) .map(|idx| (idx, seg))) }) else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), "no arg matching AnonConst in path", ); @@ -239,7 +234,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { - return tcx.ty_error_with_message( + return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); @@ -249,7 +244,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } - _ => return tcx.ty_error_with_message( + _ => return Ty::new_error_with_message(tcx, tcx.def_span(def_id), format!("unexpected const parent in type_of(): {parent_node:?}"), ), @@ -275,7 +270,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { { tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic") } else { - return tcx.ty_error_with_message( + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), ); @@ -311,6 +307,9 @@ fn get_path_containing_arg_in_pat<'hir>( } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder> { + use rustc_hir::*; + use rustc_middle::ty::Ty; + // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. @@ -323,7 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - return ty::EarlyBinder(tcx.ty_error_with_message( + return ty::EarlyBinder::bind(Ty::new_error_with_message( + tcx, DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -331,8 +331,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { TraitItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { is_suggestable_infer_ty(ty).then(|| { infer_placeholder_type( - tcx, def_id, body_id, ty.span, item.ident, "constant", + tcx, + def_id, + body_id, + ty.span, + item.ident, + "associated constant", ) }) }) @@ -361,11 +364,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { ImplItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ImplItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") + infer_placeholder_type( + tcx, + def_id, + body_id, + ty.span, + item.ident, + "associated constant", + ) } else { icx.to_ty(ty) } @@ -411,31 +421,31 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder icx.to_ty(*self_ty), }, ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { let def = tcx.adt_def(def_id); let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) + Ty::new_adt(tcx, def, substs) } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { + ItemKind::OpaqueTy(&OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => { - if in_trait && !tcx.impl_defaultness(owner).has_value() { + if in_trait && !tcx.defaultness(owner).has_value() { span_bug!( tcx.def_span(def_id), "tried to get type of this RPITIT with no definition" @@ -463,10 +473,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match foreign_item.kind { ForeignItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } ForeignItemKind::Static(t, _) => icx.to_ty(t), - ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), + ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def { @@ -475,7 +485,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id.to_def_id(), substs) + Ty::new_fn_def(tcx, def_id.to_def_id(), substs) } }, @@ -487,6 +497,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder anon_const_type_of(tcx, def_id), + Node::ConstBlock(_) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + substs.as_inline_const().ty() + } + Node::GenericParam(param) => match ¶m.kind { GenericParamKind::Type { default: Some(ty), .. } | GenericParamKind::Const { ty, .. } => icx.to_ty(ty), @@ -497,7 +512,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index f7c5b4467..957a6bb34 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,3 +1,4 @@ +use rustc_errors::StashKey; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem}; @@ -5,7 +6,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; -use crate::errors::UnconstrainedOpaqueType; +use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". @@ -59,7 +60,20 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local } } - let Some(hidden) = locator.found else { + if let Some(hidden) = locator.found { + // Only check against typeck if we didn't already error + if !hidden.ty.references_error() { + for concrete_type in locator.typeck_types { + if concrete_type.ty != tcx.erase_regions(hidden.ty) + && !(concrete_type, hidden).references_error() + { + hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); + } + } + } + + hidden.ty + } else { let reported = tcx.sess.emit_err(UnconstrainedOpaqueType { span: tcx.def_span(def_id), name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), @@ -70,21 +84,8 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local _ => "item", }, }); - return tcx.ty_error(reported); - }; - - // Only check against typeck if we didn't already error - if !hidden.ty.references_error() { - for concrete_type in locator.typeck_types { - if concrete_type.ty != tcx.erase_regions(hidden.ty) - && !(concrete_type, hidden).references_error() - { - hidden.report_mismatch(&concrete_type, def_id, tcx).emit(); - } - } + Ty::new_error(tcx, reported) } - - hidden.ty } struct TaitConstraintLocator<'tcx> { @@ -127,16 +128,41 @@ impl TaitConstraintLocator<'_> { // ``` let tables = self.tcx.typeck(item_def_id); if let Some(guar) = tables.tainted_by_errors { - self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) }); + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); return; } - let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else { + + let mut constrained = false; + for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { + if opaque_type_key.def_id != self.def_id { + continue; + } + constrained = true; + if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) { + self.tcx.sess.emit_err(TaitForwardCompat { + span: hidden_type.span, + item_span: self + .tcx + .def_ident_span(item_def_id) + .unwrap_or_else(|| self.tcx.def_span(item_def_id)), + }); + } + let concrete_type = + self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params( + opaque_type_key, + self.tcx, + true, + )); + if self.typeck_types.iter().all(|prev| prev.ty != concrete_type.ty) { + self.typeck_types.push(concrete_type); + } + } + + if !constrained { debug!("no constraints in typeck results"); return; }; - if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) { - self.typeck_types.push(typeck_hidden_ty); - } // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types; @@ -146,7 +172,7 @@ impl TaitConstraintLocator<'_> { if let Some(prev) = &mut self.found { if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit(); - prev.ty = self.tcx.ty_error(guar); + prev.ty = Ty::new_error(self.tcx, guar); } } else { self.found = Some(concrete_type); @@ -190,17 +216,45 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { } } -pub(super) fn find_opaque_ty_constraints_for_rpit( - tcx: TyCtxt<'_>, +pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( + tcx: TyCtxt<'tcx>, def_id: LocalDefId, owner_def_id: LocalDefId, ) -> Ty<'_> { - let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); + let tables = tcx.typeck(owner_def_id); - if let Some(concrete) = concrete { + // Check that all of the opaques we inferred during HIR are compatible. + // FIXME: We explicitly don't check that the types inferred during HIR + // typeck are compatible with the one that we infer during borrowck, + // because that one actually sometimes has consts evaluated eagerly so + // using strict type equality will fail. + let mut hir_opaque_ty: Option> = None; + if tables.tainted_by_errors.is_none() { + for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { + if opaque_type_key.def_id != def_id { + continue; + } + let concrete_type = tcx.erase_regions( + hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true), + ); + if let Some(prev) = &mut hir_opaque_ty { + if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() { + prev.report_mismatch(&concrete_type, def_id, tcx).stash( + tcx.def_span(opaque_type_key.def_id), + StashKey::OpaqueHiddenTypeMismatch, + ); + } + } else { + hir_opaque_ty = Some(concrete_type); + } + } + } + + let mir_opaque_ty = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); + if let Some(mir_opaque_ty) = mir_opaque_ty { let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id); debug!(?scope); - let mut locator = RpitConstraintChecker { def_id, tcx, found: concrete }; + let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty }; match tcx.hir().get(scope) { Node::Item(it) => intravisit::walk_item(&mut locator, it), @@ -208,27 +262,28 @@ pub(super) fn find_opaque_ty_constraints_for_rpit( Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } - } - concrete.map(|concrete| concrete.ty).unwrap_or_else(|| { - let table = tcx.typeck(owner_def_id); - if let Some(guar) = table.tainted_by_errors { - // Some error in the - // owner fn prevented us from populating + mir_opaque_ty.ty + } else { + if let Some(guar) = tables.tainted_by_errors { + // Some error in the owner fn prevented us from populating // the `concrete_opaque_types` table. - tcx.ty_error(guar) + Ty::new_error(tcx, guar) } else { - table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| { + // Fall back to the RPIT we inferred during HIR typeck + if let Some(hir_opaque_ty) = hir_opaque_ty { + hir_opaque_ty.ty + } else { // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, // so we can just make the hidden type be `!`. // For backwards compatibility reasons, we fall back to // `()` until we the diverging default is changed. - tcx.mk_diverging_default() - }) + Ty::new_diverging_default(tcx) + } } - }) + } } struct RpitConstraintChecker<'tcx> { -- cgit v1.2.3