From 5363f350887b1e5b5dd21a86f88c8af9d7fea6da Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:25 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_middle/src/ty/mod.rs | 668 +++++++++++++----------------------- 1 file changed, 231 insertions(+), 437 deletions(-) (limited to 'compiler/rustc_middle/src/ty/mod.rs') diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a42d05706..3f99efd25 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -9,6 +9,8 @@ //! //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html +#![allow(rustc::usage_of_ty_tykind)] + pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; pub use self::AssocItemContainer::*; @@ -26,13 +28,12 @@ use crate::ty::util::Discr; pub use adt::*; pub use assoc::*; pub use generics::*; -use hir::OpaqueTyOrigin; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; @@ -48,7 +49,9 @@ use rustc_session::cstore::CrateStoreDyn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; -use rustc_target::abi::{Align, VariantIdx}; +use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx}; +pub use rustc_target::abi::{ReprFlags, ReprOptions}; +use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -76,15 +79,15 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, ConstS, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, - CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, - GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, - UserTypeAnnotationIndex, + CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData, + GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults, + UserType, UserTypeAnnotationIndex, }; -pub use self::instance::{Instance, InstanceDef}; +pub use self::instance::{Instance, InstanceDef, ShortInstance}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::rvalue_scopes::RvalueScopes; @@ -94,9 +97,10 @@ pub use self::sty::{ BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, - InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, - PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, - RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, + InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, + ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; @@ -206,6 +210,8 @@ pub struct ResolverAstLowering { /// A small map keeping true kinds of built-in macros that appear to be fn-like on /// the surface (`macro` items in libcore), but are actually attributes or derives. pub builtin_macro_kinds: FxHashMap, + /// List functions and methods for which lifetime elision was successful. + pub lifetime_elision_allowed: FxHashSet, } #[derive(Clone, Copy, Debug)] @@ -410,7 +416,7 @@ impl Visibility { self.map_id(|id| id.expect_local()) } - // Returns `true` if this item is visible anywhere in the local crate. + /// Returns `true` if this item is visible anywhere in the local crate. pub fn is_visible_locally(self) -> bool { match self { Visibility::Public => true, @@ -441,118 +447,44 @@ pub struct CReaderCacheKey { pub pos: usize, } -/// Represents a type. -/// -/// IMPORTANT: -/// - This is a very "dumb" struct (with no derives and no `impls`). -/// - Values of this type are always interned and thus unique, and are stored -/// as an `Interned`. -/// - `Ty` (which contains a reference to a `Interned`) or `Interned` -/// should be used everywhere instead of `TyS`. In particular, `Ty` has most -/// of the relevant methods. -#[derive(PartialEq, Eq, PartialOrd, Ord)] -#[allow(rustc::usage_of_ty_tykind)] -pub(crate) struct TyS<'tcx> { - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::kind()` instead. - kind: TyKind<'tcx>, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::flags()` instead. - flags: TypeFlags, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This is a kind of confusing thing: it stores the smallest - /// binder such that - /// - /// (a) the binder itself captures nothing but - /// (b) all the late-bound things within the type are captured - /// by some sub-binder. - /// - /// So, for a type without any late-bound things, like `u32`, this - /// will be *innermost*, because that is the innermost binder that - /// captures nothing. But for a type `&'D u32`, where `'D` is a - /// late-bound region with De Bruijn index `D`, this would be `D + 1` - /// -- the binder itself does not capture `D`, but `D` is captured - /// by an inner binder. - /// - /// We call this concept an "exclusive" binder `D` because all - /// De Bruijn indices within the type are contained within `0..D` - /// (exclusive). - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `TyS`, whenever possible. +/// Use this rather than `TyKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] -pub struct Ty<'tcx>(Interned<'tcx, WithStableHash>>); +pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo>>); impl<'tcx> TyCtxt<'tcx> { /// A "bool" type used in rustc_mir_transform unit tests when we /// have not spun up a TyCtxt. - pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash { - internee: TyS { - kind: ty::Bool, + pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = + Ty(Interned::new_unchecked(&WithCachedTypeInfo { + internee: ty::Bool, + stable_hash: Fingerprint::ZERO, flags: TypeFlags::empty(), outer_exclusive_binder: DebruijnIndex::from_usize(0), - }, - stable_hash: Fingerprint::ZERO, - })); -} - -impl<'a, 'tcx> HashStable> for TyS<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TyS { - kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - - outer_exclusive_binder: _, - } = self; - - kind.hash_stable(hcx, hasher) - } + })); } impl ty::EarlyBoundRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn has_name(&self) -> bool { - self.name != kw::UnderscoreLifetime + self.name != kw::UnderscoreLifetime && self.name != kw::Empty } } -/// Represents a predicate. -/// -/// See comments on `TyS`, which apply here too (albeit for -/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). -#[derive(Debug)] -pub(crate) struct PredicateS<'tcx> { - kind: Binder<'tcx, PredicateKind<'tcx>>, - flags: TypeFlags, - /// See the comment for the corresponding field of [TyS]. - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `PredicateS`, whenever possible. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +/// Use this rather than `PredicateKind`, whenever possible. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>); +pub struct Predicate<'tcx>( + Interned<'tcx, WithCachedTypeInfo>>>, +); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.0.kind + self.0.internee } #[inline(always)] @@ -572,13 +504,15 @@ impl<'tcx> Predicate<'tcx> { let kind = self .kind() .map_bound(|kind| match kind { - PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => { - Some(PredicateKind::Trait(TraitPredicate { - trait_ref, - constness, - polarity: polarity.flip()?, - })) - } + PredicateKind::Clause(Clause::Trait(TraitPredicate { + trait_ref, + constness, + polarity, + })) => Some(PredicateKind::Clause(Clause::Trait(TraitPredicate { + trait_ref, + constness, + polarity: polarity.flip()?, + }))), _ => None, }) @@ -588,14 +522,14 @@ impl<'tcx> Predicate<'tcx> { } pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self { - if let PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) = self.kind().skip_binder() + if let PredicateKind::Clause(Clause::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() && constness != BoundConstness::NotConst { - self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate { + self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(Clause::Trait(TraitPredicate { trait_ref, constness: BoundConstness::NotConst, polarity, - }))); + })))); } self } @@ -609,36 +543,22 @@ impl<'tcx> Predicate<'tcx> { pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { PredicateKind::WellFormed(_) => false, - PredicateKind::Trait(_) - | PredicateKind::RegionOutlives(_) - | PredicateKind::TypeOutlives(_) - | PredicateKind::Projection(_) + PredicateKind::Clause(Clause::Trait(_)) + | PredicateKind::Clause(Clause::RegionOutlives(_)) + | PredicateKind::Clause(Clause::TypeOutlives(_)) + | PredicateKind::Clause(Clause::Projection(_)) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) | PredicateKind::ConstEvaluatable(_) | PredicateKind::ConstEquate(_, _) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(_) => true, } } } -impl<'a, 'tcx> HashStable> for Predicate<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let PredicateS { - ref kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - outer_exclusive_binder: _, - } = self.0.0; - - kind.hash_stable(hcx, hasher); - } -} - impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) @@ -647,7 +567,9 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum PredicateKind<'tcx> { +/// A clause is something that can appear in where bounds or be inferred +/// by implied bounds. +pub enum Clause<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. @@ -662,6 +584,13 @@ pub enum PredicateKind<'tcx> { /// `where ::Name == X`, approximately. /// See the `ProjectionPredicate` struct for details. Projection(ProjectionPredicate<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub enum PredicateKind<'tcx> { + /// Prove a clause + Clause(Clause<'tcx>), /// No syntax: `T` well-formed. WellFormed(GenericArg<'tcx>), @@ -701,6 +630,10 @@ pub enum PredicateKind<'tcx> { /// /// Only used for Chalk. TypeWellFormedFromEnv(Ty<'tcx>), + + /// A marker predicate that is always ambiguous. + /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. + Ambiguous, } /// The crate outlives map is computed during typeck and contains the @@ -714,7 +647,7 @@ pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. - pub predicates: FxHashMap, Span)]>, + pub predicates: FxHashMap, Span)]>, } impl<'tcx> Predicate<'tcx> { @@ -851,6 +784,10 @@ impl<'tcx> TraitPredicate<'tcx> { } } + pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + Self { trait_ref: self.trait_ref.with_self_type(tcx, self_ty), ..self } + } + pub fn def_id(self) -> DefId { self.trait_ref.def_id } @@ -902,9 +839,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } } +/// `A: B` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct OutlivesPredicate(pub A, pub B); // `A: B` +pub struct OutlivesPredicate(pub A, pub B); pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; @@ -1003,7 +941,7 @@ impl<'tcx> Term<'tcx> { unsafe { match ptr & TAG_MASK { TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithStableHash>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), @@ -1047,7 +985,7 @@ impl<'tcx> TermKind<'tcx> { TermKind::Ty(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); - (TYPE_TAG, ty.0.0 as *const WithStableHash> as usize) + (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo> as usize) } TermKind::Const(ct) => { // Ensure we can use the tag bits. @@ -1125,12 +1063,12 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { } } -pub trait ToPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; +pub trait ToPredicate<'tcx, P = Predicate<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P; } -impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { - fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { +impl<'tcx, T> ToPredicate<'tcx, T> for T { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T { self } } @@ -1142,27 +1080,53 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) + } +} + +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); + pred.to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { + self.map_bound(|trait_ref| TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }) + } +} + impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(PredicateKind::Trait).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(PredicateKind::RegionOutlives).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(PredicateKind::TypeOutlives).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(PredicateKind::Projection).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) } } @@ -1170,17 +1134,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_pred(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Trait(t) => Some(predicate.rebind(t)), - PredicateKind::Projection(..) + PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::RegionOutlives(..) + | PredicateKind::Clause(Clause::RegionOutlives(..)) | PredicateKind::WellFormed(..) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::TypeOutlives(..) + | PredicateKind::Clause(Clause::TypeOutlives(..)) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1188,17 +1153,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_projection_pred(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Projection(t) => Some(predicate.rebind(t)), - PredicateKind::Trait(..) + PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::RegionOutlives(..) + | PredicateKind::Clause(Clause::RegionOutlives(..)) | PredicateKind::WellFormed(..) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::TypeOutlives(..) + | PredicateKind::Clause(Clause::TypeOutlives(..)) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1206,17 +1172,18 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_type_outlives(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::TypeOutlives(data) => Some(predicate.rebind(data)), - PredicateKind::Trait(..) - | PredicateKind::Projection(..) + PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)), + PredicateKind::Clause(Clause::Trait(..)) + | PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::RegionOutlives(..) + | PredicateKind::Clause(Clause::RegionOutlives(..)) | PredicateKind::WellFormed(..) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1257,7 +1224,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { pub def_id: LocalDefId, @@ -1319,7 +1286,6 @@ impl<'tcx> OpaqueHiddenType<'tcx> { tcx: TyCtxt<'tcx>, // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck. ignore_errors: bool, - origin: OpaqueTyOrigin, ) -> Self { let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -1332,78 +1298,10 @@ impl<'tcx> OpaqueHiddenType<'tcx> { let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); debug!(?id_substs); - let map = substs.iter().zip(id_substs); - - let map: FxHashMap, GenericArg<'tcx>> = match origin { - // HACK: The HIR lowering for async fn does not generate - // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes - // would now fail to compile. We should probably just make hir lowering fill this in properly. - OpaqueTyOrigin::AsyncFn(_) => map.collect(), - OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => { - // Opaque types may only use regions that are bound. So for - // ```rust - // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; - // ``` - // we may not use `'c` in the hidden type. - struct OpaqueTypeLifetimeCollector<'tcx> { - lifetimes: FxHashSet>, - } - - impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - self.lifetimes.insert(r); - r.super_visit_with(self) - } - } - - let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() }; - - for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() { - let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); - - trace!(pred=?pred.kind()); - - // We only ignore opaque type substs if the opaque type is the outermost type. - // The opaque type may be nested within itself via recursion in e.g. - // type Foo<'a> = impl PartialEq>; - // which thus mentions `'a` and should thus accept hidden types that borrow 'a - // instead of requiring an additional `+ 'a`. - match pred.kind().skip_binder() { - ty::PredicateKind::Trait(TraitPredicate { - trait_ref: ty::TraitRef { def_id: _, substs }, - constness: _, - polarity: _, - }) => { - trace!(?substs); - for subst in &substs[1..] { - subst.visit_with(&mut collector); - } - } - ty::PredicateKind::Projection(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { substs, item_def_id: _ }, - term, - }) => { - for subst in &substs[1..] { - subst.visit_with(&mut collector); - } - term.visit_with(&mut collector); - } - _ => { - pred.visit_with(&mut collector); - } - } - } - let lifetimes = collector.lifetimes; - trace!(?lifetimes); - map.filter(|(_, v)| { - let ty::GenericArgKind::Lifetime(lt) = v.unpack() else { - return true; - }; - lifetimes.contains(<) - }) - .collect() - } - }; + // This zip may have several times the same lifetime in `substs` paired with a different + // lifetime from `id_substs`. Simply `collect`ing the iterator is the correct behaviour: + // it will pick the last one, which is the one we introduced in the impl-trait desugaring. + let map = substs.iter().zip(id_substs).collect(); debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside @@ -1748,7 +1646,7 @@ impl<'tcx> ParamEnv<'tcx> { } ParamEnv::new( - tcx.normalize_opaque_types(self.caller_bounds()), + tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All, self.constness(), ) @@ -1852,15 +1750,13 @@ pub struct VariantDef { pub def_id: DefId, /// `DefId` that identifies the variant's constructor. /// If this variant is a struct variant, then this is `None`. - pub ctor_def_id: Option, + pub ctor: Option<(CtorKind, DefId)>, /// Variant or struct name. pub name: Symbol, /// Discriminant of this variant. pub discr: VariantDiscr, /// Fields of this variant. pub fields: Vec, - /// Type of constructor of variant. - pub ctor_kind: CtorKind, /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, } @@ -1885,19 +1781,18 @@ impl VariantDef { pub fn new( name: Symbol, variant_did: Option, - ctor_def_id: Option, + ctor: Option<(CtorKind, DefId)>, discr: VariantDiscr, fields: Vec, - ctor_kind: CtorKind, adt_kind: AdtKind, parent_did: DefId, recovered: bool, is_field_list_non_exhaustive: bool, ) -> Self { debug!( - "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?}, - fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})", - name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did, + "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?}, + fields = {:?}, adt_kind = {:?}, parent_did = {:?})", + name, variant_did, ctor, discr, fields, adt_kind, parent_did, ); let mut flags = VariantFlags::NO_VARIANT_FLAGS; @@ -1909,15 +1804,7 @@ impl VariantDef { flags |= VariantFlags::IS_RECOVERED; } - VariantDef { - def_id: variant_did.unwrap_or(parent_did), - ctor_def_id, - name, - discr, - fields, - ctor_kind, - flags, - } + VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags } } /// Is this field list non-exhaustive? @@ -1936,6 +1823,16 @@ impl VariantDef { pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) } + + #[inline] + pub fn ctor_kind(&self) -> Option { + self.ctor.map(|(kind, _)| kind) + } + + #[inline] + pub fn ctor_def_id(&self) -> Option { + self.ctor.map(|(_, def_id)| def_id) + } } impl PartialEq for VariantDef { @@ -1948,26 +1845,8 @@ impl PartialEq for VariantDef { // definition of `VariantDef` changes, a compile-error will be produced, // reminding us to revisit this assumption. - let Self { - def_id: lhs_def_id, - ctor_def_id: _, - name: _, - discr: _, - fields: _, - ctor_kind: _, - flags: _, - } = &self; - - let Self { - def_id: rhs_def_id, - ctor_def_id: _, - name: _, - discr: _, - fields: _, - ctor_kind: _, - flags: _, - } = other; - + 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 } } @@ -1984,9 +1863,7 @@ impl Hash for VariantDef { // of `VariantDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } = - &self; - + let Self { def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self; def_id.hash(s) } } @@ -2047,163 +1924,6 @@ impl Hash for FieldDef { } } -bitflags! { - #[derive(TyEncodable, TyDecodable, Default, HashStable)] - pub struct ReprFlags: u8 { - const IS_C = 1 << 0; - const IS_SIMD = 1 << 1; - const IS_TRANSPARENT = 1 << 2; - // Internal only for now. If true, don't reorder fields. - const IS_LINEAR = 1 << 3; - // If true, the type's layout can be randomized using - // the seed stored in `ReprOptions.layout_seed` - const RANDOMIZE_LAYOUT = 1 << 4; - // Any of these flags being set prevent field reordering optimisation. - const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits - | ReprFlags::IS_SIMD.bits - | ReprFlags::IS_LINEAR.bits; - } -} - -/// Represents the repr options provided by the user, -#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Default, HashStable)] -pub struct ReprOptions { - pub int: Option, - pub align: Option, - pub pack: Option, - pub flags: ReprFlags, - /// The seed to be used for randomizing a type's layout - /// - /// Note: This could technically be a `[u8; 16]` (a `u128`) which would - /// be the "most accurate" hash as it'd encompass the item and crate - /// hash without loss, but it does pay the price of being larger. - /// Everything's a tradeoff, a `u64` seed should be sufficient for our - /// purposes (primarily `-Z randomize-layout`) - pub field_shuffle_seed: u64, -} - -impl ReprOptions { - pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { - let mut flags = ReprFlags::empty(); - let mut size = None; - let mut max_align: Option = None; - let mut min_pack: Option = None; - - // Generate a deterministically-derived seed from the item's path hash - // to allow for cross-crate compilation to actually work - let mut field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash(); - - // If the user defined a custom seed for layout randomization, xor the item's - // path hash with the user defined seed, this will allowing determinism while - // still allowing users to further randomize layout generation for e.g. fuzzing - if let Some(user_seed) = tcx.sess.opts.unstable_opts.layout_seed { - field_shuffle_seed ^= user_seed; - } - - for attr in tcx.get_attrs(did, sym::repr) { - for r in attr::parse_repr_attr(&tcx.sess, attr) { - flags.insert(match r { - attr::ReprC => ReprFlags::IS_C, - attr::ReprPacked(pack) => { - let pack = Align::from_bytes(pack as u64).unwrap(); - min_pack = Some(if let Some(min_pack) = min_pack { - min_pack.min(pack) - } else { - pack - }); - ReprFlags::empty() - } - attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, - attr::ReprSimd => ReprFlags::IS_SIMD, - attr::ReprInt(i) => { - size = Some(i); - ReprFlags::empty() - } - attr::ReprAlign(align) => { - max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); - ReprFlags::empty() - } - }); - } - } - - // If `-Z randomize-layout` was enabled for the type definition then we can - // consider performing layout randomization - if tcx.sess.opts.unstable_opts.randomize_layout { - flags.insert(ReprFlags::RANDOMIZE_LAYOUT); - } - - // This is here instead of layout because the choice must make it into metadata. - if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) { - flags.insert(ReprFlags::IS_LINEAR); - } - - Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } - } - - #[inline] - pub fn simd(&self) -> bool { - self.flags.contains(ReprFlags::IS_SIMD) - } - - #[inline] - pub fn c(&self) -> bool { - self.flags.contains(ReprFlags::IS_C) - } - - #[inline] - pub fn packed(&self) -> bool { - self.pack.is_some() - } - - #[inline] - pub fn transparent(&self) -> bool { - self.flags.contains(ReprFlags::IS_TRANSPARENT) - } - - #[inline] - pub fn linear(&self) -> bool { - self.flags.contains(ReprFlags::IS_LINEAR) - } - - /// Returns the discriminant type, given these `repr` options. - /// This must only be called on enums! - pub fn discr_type(&self) -> attr::IntType { - self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize)) - } - - /// Returns `true` if this `#[repr()]` should inhabit "smart enum - /// layout" optimizations, such as representing `Foo<&T>` as a - /// single pointer. - pub fn inhibit_enum_layout_opt(&self) -> bool { - self.c() || self.int.is_some() - } - - /// Returns `true` if this `#[repr()]` should inhibit struct field reordering - /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr()`. - pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - if let Some(pack) = self.pack { - if pack.bytes() == 1 { - return true; - } - } - - self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() - } - - /// Returns `true` if this type is valid for reordering and `-Z randomize-layout` - /// was enabled for its declaration crate - pub fn can_randomize_type_layout(&self) -> bool { - !self.inhibit_struct_field_reordering_opt() - && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) - } - - /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. - pub fn inhibit_union_abi_opt(&self) -> bool { - self.c() - } -} - impl<'tcx> FieldDef { /// Returns the type of this field. The resulting type is not normalized. The `subst` is /// typically obtained via the second field of [`TyKind::Adt`]. @@ -2271,6 +1991,81 @@ impl<'tcx> TyCtxt<'tcx> { .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value()) } + pub fn repr_options_of_def(self, did: DefId) -> ReprOptions { + let mut flags = ReprFlags::empty(); + let mut size = None; + let mut max_align: Option = None; + let mut min_pack: Option = None; + + // Generate a deterministically-derived seed from the item's path hash + // to allow for cross-crate compilation to actually work + let mut field_shuffle_seed = self.def_path_hash(did).0.to_smaller_hash(); + + // If the user defined a custom seed for layout randomization, xor the item's + // path hash with the user defined seed, this will allowing determinism while + // still allowing users to further randomize layout generation for e.g. fuzzing + if let Some(user_seed) = self.sess.opts.unstable_opts.layout_seed { + field_shuffle_seed ^= user_seed; + } + + for attr in self.get_attrs(did, sym::repr) { + for r in attr::parse_repr_attr(&self.sess, attr) { + flags.insert(match r { + attr::ReprC => ReprFlags::IS_C, + attr::ReprPacked(pack) => { + let pack = Align::from_bytes(pack as u64).unwrap(); + min_pack = Some(if let Some(min_pack) = min_pack { + min_pack.min(pack) + } else { + pack + }); + ReprFlags::empty() + } + attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, + attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprInt(i) => { + size = Some(match i { + attr::IntType::SignedInt(x) => match x { + ast::IntTy::Isize => IntegerType::Pointer(true), + ast::IntTy::I8 => IntegerType::Fixed(Integer::I8, true), + ast::IntTy::I16 => IntegerType::Fixed(Integer::I16, true), + ast::IntTy::I32 => IntegerType::Fixed(Integer::I32, true), + ast::IntTy::I64 => IntegerType::Fixed(Integer::I64, true), + ast::IntTy::I128 => IntegerType::Fixed(Integer::I128, true), + }, + attr::IntType::UnsignedInt(x) => match x { + ast::UintTy::Usize => IntegerType::Pointer(false), + ast::UintTy::U8 => IntegerType::Fixed(Integer::I8, false), + ast::UintTy::U16 => IntegerType::Fixed(Integer::I16, false), + ast::UintTy::U32 => IntegerType::Fixed(Integer::I32, false), + ast::UintTy::U64 => IntegerType::Fixed(Integer::I64, false), + ast::UintTy::U128 => IntegerType::Fixed(Integer::I128, false), + }, + }); + ReprFlags::empty() + } + attr::ReprAlign(align) => { + max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); + ReprFlags::empty() + } + }); + } + } + + // If `-Z randomize-layout` was enabled for the type definition then we can + // consider performing layout randomization + if self.sess.opts.unstable_opts.randomize_layout { + flags.insert(ReprFlags::RANDOMIZE_LAYOUT); + } + + // This is here instead of layout because the choice must make it into metadata. + if !self.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) { + flags.insert(ReprFlags::IS_LINEAR); + } + + ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } + } + /// Look up the name of a definition across crates. This does not look at HIR. pub fn opt_item_name(self, def_id: DefId) -> Option { if let Some(cnum) = def_id.as_crate_root() { @@ -2322,10 +2117,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize { - typeck_results.field_indices().get(hir_id).cloned().expect("no index for a field") - } - pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { variant .fields @@ -2506,6 +2297,10 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } + pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { + self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id) + } + /// Returns layout of a generator. Layout might be unavailable if the /// generator is tainted by errors. pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> { @@ -2550,11 +2345,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. - pub fn span_of_impl(self, impl_did: DefId) -> Result { - if let Some(impl_did) = impl_did.as_local() { - Ok(self.def_span(impl_did)) + pub fn span_of_impl(self, impl_def_id: DefId) -> Result { + if let Some(impl_def_id) = impl_def_id.as_local() { + Ok(self.def_span(impl_def_id)) } else { - Err(self.crate_name(impl_did.krate)) + Err(self.crate_name(impl_def_id.krate)) } } @@ -2782,8 +2577,7 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(PredicateS<'_>, 48); - static_assert_size!(TyS<'_>, 40); - static_assert_size!(WithStableHash>, 56); + static_assert_size!(PredicateKind<'_>, 32); + static_assert_size!(WithCachedTypeInfo>, 56); // tidy-alphabetical-end } -- cgit v1.2.3