diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty/mod.rs')
-rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 328 |
1 files changed, 130 insertions, 198 deletions
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2e516f291..a8d0dca37 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -21,6 +21,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, GeneratorLayout}; +use crate::query::Providers; use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::fast_reject::SimplifiedType; @@ -36,12 +37,12 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_hir::Node; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; @@ -84,8 +85,7 @@ pub use self::consts::{ Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt, - TyCtxtFeed, + tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; @@ -122,7 +122,6 @@ pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; pub mod print; -pub mod query; pub mod relate; pub mod subst; pub mod trait_def; @@ -166,8 +165,7 @@ pub struct ResolverGlobalCtxt { pub effective_visibilities: EffectiveVisibilities, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, - pub module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>, - pub module_children_reexports: LocalDefIdMap<Vec<ModChild>>, + pub module_children: LocalDefIdMap<Vec<ModChild>>, pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, pub main_def: Option<MainDefinition>, pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>, @@ -861,6 +859,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub fn is_const_if_const(self) -> bool { self.skip_binder().is_const_if_const() } + + #[inline] + pub fn polarity(self) -> ImplPolarity { + self.skip_binder().polarity + } } /// `A: B` @@ -993,21 +996,15 @@ impl<'tcx> Term<'tcx> { } } - /// This function returns the inner `AliasTy` if this term is a projection. - /// - /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly - /// deal with constants. - pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { + /// This function returns the inner `AliasTy` for a `ty::Alias` or `ConstKind::Unevaluated`. + pub fn to_alias_ty(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { match self.unpack() { - TermKind::Ty(ty) => match ty.kind() { - ty::Alias(kind, alias_ty) => match kind { - AliasKind::Projection => Some(*alias_ty), - AliasKind::Opaque => None, - }, + TermKind::Ty(ty) => match *ty.kind() { + ty::Alias(_kind, alias_ty) => Some(alias_ty), _ => None, }, TermKind::Const(ct) => match ct.kind() { - ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def.did, uv.substs)), + ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def, uv.substs)), _ => None, }, } @@ -1067,6 +1064,24 @@ impl ParamTerm { } } +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum TermVid<'tcx> { + Ty(ty::TyVid), + Const(ty::ConstVid<'tcx>), +} + +impl From<ty::TyVid> for TermVid<'_> { + fn from(value: ty::TyVid) -> Self { + TermVid::Ty(value) + } +} + +impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> { + fn from(value: ty::ConstVid<'tcx>) -> Self { + TermVid::Const(value) + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1207,6 +1222,18 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef } } +impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitRef<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { + ty::Binder::dummy(self) + } +} + impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) @@ -1231,6 +1258,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } +impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx) + } +} + impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> { let predicate = self.kind(); @@ -1400,14 +1433,26 @@ pub struct OpaqueHiddenType<'tcx> { } impl<'tcx> OpaqueHiddenType<'tcx> { - pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed { + pub fn report_mismatch( + &self, + other: &Self, + opaque_def_id: LocalDefId, + tcx: TyCtxt<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + if let Some(diag) = tcx + .sess + .diagnostic() + .steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch) + { + diag.cancel(); + } // Found different concrete types for the opaque type. let sub_diag = if self.span == other.span { TypeMismatchReason::ConflictType { span: self.span } } else { TypeMismatchReason::PreviousUse { span: self.span } }; - tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + tcx.sess.create_err(OpaqueHiddenTypeMismatch { self_ty: self.ty, other_ty: other.ty, other_span: other.span, @@ -1471,135 +1516,6 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>; -/// A `DefId` which, in case it is a const argument, is potentially bundled with -/// the `DefId` of the generic parameter it instantiates. -/// -/// This is used to avoid calls to `type_of` for const arguments during typeck -/// which cause cycle errors. -/// -/// ```rust -/// struct A; -/// impl A { -/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] } -/// // ^ const parameter -/// } -/// struct B; -/// impl B { -/// fn foo<const M: u8>(&self) -> usize { 42 } -/// // ^ const parameter -/// } -/// -/// fn main() { -/// let a = A; -/// let _b = a.foo::<{ 3 + 7 }>(); -/// // ^^^^^^^^^ const argument -/// } -/// ``` -/// -/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know -/// which `foo` is used until we know the type of `a`. -/// -/// We only know the type of `a` once we are inside of `typeck(main)`. -/// We also end up normalizing the type of `_b` during `typeck(main)` which -/// requires us to evaluate the const argument. -/// -/// To evaluate that const argument we need to know its type, -/// which we would get using `type_of(const_arg)`. This requires us to -/// resolve `foo` as it can be either `usize` or `u8` in this example. -/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`, -/// which results in a cycle. -/// -/// In short we must not call `type_of(const_arg)` during `typeck(main)`. -/// -/// When first creating the `ty::Const` of the const argument inside of `typeck` we have -/// already resolved `foo` so we know which const parameter this argument instantiates. -/// This means that we also know the expected result of `type_of(const_arg)` even if we -/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is -/// trivial to compute. -/// -/// If we now want to use that constant in a place which potentially needs its type -/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`, -/// except that instead of a `Ty` we bundle the `DefId` of the const parameter. -/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some` -/// to get the type of `did`. -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)] -#[derive(PartialEq, Eq, PartialOrd, Ord)] -#[derive(Hash, HashStable)] -pub struct WithOptConstParam<T> { - pub did: T, - /// The `DefId` of the corresponding generic parameter in case `did` is - /// a const argument. - /// - /// Note that even if `did` is a const argument, this may still be `None`. - /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)` - /// to potentially update `param_did` in the case it is `None`. - pub const_param_did: Option<DefId>, -} - -impl<T> WithOptConstParam<T> { - /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`. - #[inline(always)] - pub fn unknown(did: T) -> WithOptConstParam<T> { - WithOptConstParam { did, const_param_did: None } - } -} - -impl WithOptConstParam<LocalDefId> { - /// Returns `Some((did, param_did))` if `def_id` is a const argument, - /// `None` otherwise. - #[inline(always)] - pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> { - tcx.opt_const_param_of(did).map(|param_did| (did, param_did)) - } - - /// In case `self` is unknown but `self.did` is a const argument, this returns - /// a `WithOptConstParam` with the correct `const_param_did`. - #[inline(always)] - pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> { - if self.const_param_did.is_none() { - if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) { - return Some(WithOptConstParam { did: self.did, const_param_did }); - } - } - - None - } - - pub fn to_global(self) -> WithOptConstParam<DefId> { - WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did } - } - - pub fn def_id_for_type_of(self) -> DefId { - if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() } - } -} - -impl WithOptConstParam<DefId> { - pub fn as_local(self) -> Option<WithOptConstParam<LocalDefId>> { - self.did - .as_local() - .map(|did| WithOptConstParam { did, const_param_did: self.const_param_did }) - } - - pub fn as_const_arg(self) -> Option<(LocalDefId, DefId)> { - if let Some(param_did) = self.const_param_did { - if let Some(did) = self.did.as_local() { - return Some((did, param_did)); - } - } - - None - } - - pub fn is_local(self) -> bool { - self.did.is_local() - } - - pub fn def_id_for_type_of(self) -> DefId { - self.const_param_did.unwrap_or(self.did) - } -} - /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this /// particular point. @@ -1626,27 +1542,12 @@ struct ParamTag { constness: hir::Constness, } -unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { - const BITS: usize = 2; - #[inline] - fn into_usize(self) -> usize { - match self { - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0, - Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1, - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2, - Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3, - } - } - #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - match ptr { - 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, - 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, - 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, - 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const }, - _ => std::hint::unreachable_unchecked(), - } - } +impl_tag! { + impl Tag for ParamTag; + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const }, } impl<'tcx> fmt::Debug for ParamEnv<'tcx> { @@ -1850,12 +1751,6 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { (self.param_env, self.value) } - - #[inline] - pub fn without_const(mut self) -> Self { - self.param_env = self.param_env.without_const(); - self - } } #[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] @@ -1868,7 +1763,7 @@ pub struct Destructor { bitflags! { #[derive(HashStable, TyEncodable, TyDecodable)] - pub struct VariantFlags: u32 { + pub struct VariantFlags: u8 { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; @@ -1969,6 +1864,16 @@ impl VariantDef { pub fn ctor_def_id(&self) -> Option<DefId> { self.ctor.map(|(_, def_id)| def_id) } + + /// Returns the one field in this variant. + /// + /// `panic!`s if there are no fields or multiple fields. + #[inline] + pub fn single_field(&self) -> &FieldDef { + assert!(self.fields.len() == 1); + + &self.fields[FieldIdx::from_u32(0)] + } } impl PartialEq for VariantDef { @@ -1983,7 +1888,20 @@ impl PartialEq for VariantDef { let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self; let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other; - lhs_def_id == rhs_def_id + + let res = lhs_def_id == rhs_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.ctor == other.ctor + && self.name == other.name + && self.discr == other.discr + && self.fields == other.fields + && self.flags == other.flags; + assert!(deep, "VariantDef for the same def-id has differing data"); + } + + res } } @@ -2038,7 +1956,15 @@ impl PartialEq for FieldDef { let Self { did: rhs_did, name: _, vis: _ } = other; - lhs_did == rhs_did + let res = lhs_did == rhs_did; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.name == other.name && self.vis == other.vis; + assert!(deep, "FieldDef for the same def-id has differing data"); + } + + res } } @@ -2245,10 +2171,9 @@ impl<'tcx> TyCtxt<'tcx> { /// See [`item_name`][Self::item_name] for more information. pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> { let def = self.opt_item_name(def_id)?; - let span = def_id - .as_local() - .and_then(|id| self.def_ident_span(id)) - .unwrap_or(rustc_span::DUMMY_SP); + let span = self + .def_ident_span(def_id) + .unwrap_or_else(|| bug!("missing ident span for {def_id:?}")); Some(Ident::new(def, span)) } @@ -2289,8 +2214,8 @@ impl<'tcx> TyCtxt<'tcx> { let impl_trait_ref2 = self.impl_trait_ref(def_id2); // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if impl_trait_ref1.map_or(false, |tr| tr.subst_identity().references_error()) - || impl_trait_ref2.map_or(false, |tr| tr.subst_identity().references_error()) + if impl_trait_ref1.is_some_and(|tr| tr.subst_identity().references_error()) + || impl_trait_ref2.is_some_and(|tr| tr.subst_identity().references_error()) { return Some(ImplOverlapKind::Permitted { marker: false }); } @@ -2311,7 +2236,7 @@ impl<'tcx> TyCtxt<'tcx> { let is_marker_overlap = { let is_marker_impl = |trait_ref: Option<EarlyBinder<TraitRef<'_>>>| -> bool { - trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker) + trait_ref.is_some_and(|tr| self.trait_def(tr.skip_binder().def_id).is_marker) }; is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) }; @@ -2361,7 +2286,7 @@ impl<'tcx> TyCtxt<'tcx> { match instance { ty::InstanceDef::Item(def) => { debug!("calling def_kind on def: {:?}", def); - let def_kind = self.def_kind(def.did); + let def_kind = self.def_kind(def); debug!("returned from def_kind: {:?}", def_kind); match def_kind { DefKind::Const @@ -2369,13 +2294,10 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::AssocConst | DefKind::Ctor(..) | DefKind::AnonConst - | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), + | DefKind::InlineConst => self.mir_for_ctfe(def), // If the caller wants `mir_for_ctfe` of a function they should not be using // `instance_mir`, so we'll assume const fn also wants the optimized version. - _ => { - assert_eq!(def.const_param_did, None); - self.optimized_mir(def.did) - } + _ => self.optimized_mir(def), } } ty::InstanceDef::VTableShim(..) @@ -2566,9 +2488,7 @@ impl<'tcx> TyCtxt<'tcx> { && if self.features().collapse_debuginfo { span.in_macro_expansion_with_collapse_debuginfo() } else { - // Inlined spans should not be collapsed as that leads to all of the - // inlined code being attributed to the inline callsite. - span.from_expansion() && !span.is_inlined() + span.from_expansion() } } @@ -2599,6 +2519,18 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Returns the `DefId` of the item within which the `impl Trait` is declared. + /// For type-alias-impl-trait this is the `type` alias. + /// For impl-trait-in-assoc-type this is the assoc type. + /// For return-position-impl-trait this is the function. + pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId { + // Find the surrounding item (type alias or assoc type) + while let DefKind::OpaqueTy = self.def_kind(def_id) { + def_id = self.local_parent(def_id); + } + def_id + } + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { if self.def_kind(def_id) != DefKind::AssocFn { return false; @@ -2643,7 +2575,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { Some(parent) } - hir::OpaqueTyOrigin::TyAlias => None, + hir::OpaqueTyOrigin::TyAlias { .. } => None, }; } } @@ -2701,7 +2633,7 @@ pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { closure::provide(providers); context::provide(providers); erase_regions::provide(providers); @@ -2710,7 +2642,7 @@ pub fn provide(providers: &mut ty::query::Providers) { print::provide(providers); super::util::bug::provide(providers); super::middle::provide(providers); - *providers = ty::query::Providers { + *providers = Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, const_param_default: consts::const_param_default, |