diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
commit | 94a0819fe3a0d679c3042a77bfe6a2afc505daea (patch) | |
tree | 2b827afe6a05f3538db3f7803a88c4587fe85648 /compiler/rustc_middle/src/ty | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.tar.xz rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.zip |
Adding upstream version 1.66.0+dfsg1.upstream/1.66.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
42 files changed, 1966 insertions, 3966 deletions
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index bed809930..1aa4df778 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -1,7 +1,7 @@ //! A subset of a mir body used for const evaluatability checking. use crate::mir; use crate::ty::visit::TypeVisitable; -use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt}; +use crate::ty::{self, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use std::cmp; @@ -30,7 +30,7 @@ pub struct AbstractConst<'tcx> { impl<'tcx> AbstractConst<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - uv: ty::Unevaluated<'tcx, ()>, + uv: ty::UnevaluatedConst<'tcx>, ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; debug!("AbstractConst::new({:?}) = {:?}", uv, inner); @@ -42,7 +42,7 @@ impl<'tcx> AbstractConst<'tcx> { ct: ty::Const<'tcx>, ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { match ct.kind() { - ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()), + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported), _ => Ok(None), } @@ -71,16 +71,16 @@ impl<'tcx> AbstractConst<'tcx> { walk_abstract_const::<!, _>(tcx, self, |node| { match node.root(tcx) { Node::Leaf(leaf) => { - if leaf.has_infer_types_or_consts() { + if leaf.has_non_region_infer() { failure_kind = FailureKind::MentionsInfer; - } else if leaf.has_param_types_or_consts() { + } else if leaf.has_non_region_param() { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } } Node::Cast(_, _, ty) => { - if ty.has_infer_types_or_consts() { + if ty.has_non_region_infer() { failure_kind = FailureKind::MentionsInfer; - } else if ty.has_param_types_or_consts() { + } else if ty.has_non_region_param() { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index d36cf2fe3..4682ac96b 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -77,7 +77,7 @@ pub enum PointerCast { /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` -> /// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, pub target: Ty<'tcx>, @@ -89,7 +89,7 @@ impl<'tcx> Adjustment<'tcx> { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, @@ -101,6 +101,9 @@ pub enum Adjust<'tcx> { Borrow(AutoBorrow<'tcx>), Pointer(PointerCast), + + /// Cast into a dyn* object. + DynStar, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` @@ -108,7 +111,7 @@ pub enum Adjust<'tcx> { /// The target type is `U` in both cases, with the region and mutability /// being those shared by both the receiver and the returned reference. #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable, Lift)] pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, @@ -167,7 +170,7 @@ impl From<AutoBorrowMutability> for hir::Mutability { } #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable, Lift)] pub enum AutoBorrow<'tcx> { /// Converts from T to &T. Ref(ty::Region<'tcx>, AutoBorrowMutability), diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2e596b275..b0a2412ab 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -26,9 +26,6 @@ use super::{ Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr, }; -#[derive(Copy, Clone, HashStable, Debug)] -pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); - bitflags! { #[derive(HashStable, TyEncodable, TyDecodable)] pub struct AdtFlags: u32 { @@ -332,13 +329,13 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_PHANTOM_DATA) } - /// Returns `true` if this is Box<T>. + /// Returns `true` if this is `Box<T>`. #[inline] pub fn is_box(self) -> bool { self.flags().contains(AdtFlags::IS_BOX) } - /// Returns `true` if this is UnsafeCell<T>. + /// Returns `true` if this is `UnsafeCell<T>`. #[inline] pub fn is_unsafe_cell(self) -> bool { self.flags().contains(AdtFlags::IS_UNSAFE_CELL) @@ -438,7 +435,8 @@ impl<'tcx> AdtDef<'tcx> { | Res::Def(DefKind::Union, _) | Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy { .. } + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } | Res::SelfCtor(..) => self.non_enum_variant(), _ => bug!("unexpected res {:?} in variant_of_res", res), } @@ -457,11 +455,9 @@ impl<'tcx> AdtDef<'tcx> { Some(Discr { val: b, ty }) } else { info!("invalid enum discriminant: {:#?}", val); - crate::mir::interpret::struct_error( - tcx.at(tcx.def_span(expr_did)), - "constant evaluation of enum discriminant resulted in non-integer", - ) - .emit(); + tcx.sess.emit_err(crate::error::ConstEvalNonIntError { + span: tcx.def_span(expr_did), + }); None } } @@ -564,6 +560,13 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0) + ty::EarlyBinder(tcx.adt_sized_constraint(self.did())) } } + +#[derive(Clone, Copy, Debug)] +#[derive(HashStable)] +pub enum Representability { + Representable, + Infinite, +} diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index c97156ac1..55ee5bd2f 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -42,7 +42,7 @@ impl AssocItem { } #[inline] - pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility { + pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> { tcx.visibility(self.def_id) } diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 3d65429f2..a5b05a4f9 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -1,6 +1,4 @@ -use rustc_hir::BindingAnnotation; -use rustc_hir::BindingAnnotation::*; -use rustc_hir::Mutability; +use rustc_hir::{BindingAnnotation, ByRef, Mutability}; #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)] pub enum BindingMode { @@ -11,12 +9,10 @@ pub enum BindingMode { TrivialTypeTraversalAndLiftImpls! { BindingMode, } impl BindingMode { - pub fn convert(ba: BindingAnnotation) -> BindingMode { - match ba { - Unannotated => BindingMode::BindByValue(Mutability::Not), - Mutable => BindingMode::BindByValue(Mutability::Mut), - Ref => BindingMode::BindByReference(Mutability::Not), - RefMut => BindingMode::BindByReference(Mutability::Mut), + pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { + match by_ref { + ByRef::No => BindingMode::BindByValue(mutbl), + ByRef::Yes => BindingMode::BindByReference(mutbl), } } } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c4b743dd4..e65585955 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -2,6 +2,7 @@ // typeck and codegen. use crate::ty::{self, Ty}; +use rustc_middle::mir; use rustc_macros::HashStable; @@ -33,10 +34,12 @@ pub enum CastTy<'tcx> { FnPtr, /// Raw pointers. Ptr(ty::TypeAndMut<'tcx>), + /// Casting into a `dyn*` value. + DynStar, } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) -/// (or librustc_typeck/check/cast.rs). +/// (or rustc_hir_analysis/check/cast.rs). #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum CastKind { CoercionCast, @@ -50,6 +53,7 @@ pub enum CastKind { ArrayPtrCast, FnPtrPtrCast, FnPtrAddrCast, + DynStarCast, } impl<'tcx> CastTy<'tcx> { @@ -67,7 +71,33 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::FnPtr(..) => Some(CastTy::FnPtr), + ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar), _ => None, } } } + +/// Returns `mir::CastKind` from the given parameters. +pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKind { + let from = CastTy::from_ty(from_ty); + let cast = CastTy::from_ty(cast_ty); + let cast_kind = match (from, cast) { + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + mir::CastKind::PointerExposeAddress + } + (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress, + (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar, + (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt, + (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr, + + (Some(CastTy::Float), Some(CastTy::Int(_))) => mir::CastKind::FloatToInt, + (Some(CastTy::Int(_)), Some(CastTy::Float)) => mir::CastKind::IntToFloat, + (Some(CastTy::Float), Some(CastTy::Float)) => mir::CastKind::FloatToFloat, + (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PtrToPtr, + + (_, _) => { + bug!("Attempting to cast non-castable types {:?} and {:?}", from_ty, cast_ty) + } + }; + cast_kind +} diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 51137c526..14ec88b7e 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -455,6 +455,7 @@ impl_arena_copy_decoder! {<'tcx> rustc_span::def_id::DefId, rustc_span::def_id::LocalDefId, (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), + ty::DeducedParamAttrs, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f8792edc0..f998e6083 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,9 +1,6 @@ use crate::mir::interpret::LitToConstInput; use crate::mir::ConstantKind; -use crate::ty::{ - self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, - TyCtxt, TypeVisitable, -}; +use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -41,7 +38,7 @@ pub struct ConstS<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstS<'_>, 48); +static_assert_size!(ConstS<'_>, 40); impl<'tcx> Const<'tcx> { #[inline] @@ -65,8 +62,6 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>, ) -> Self { - debug!("Const::from_anon_const(def={:?})", def); - let body_id = match tcx.hir().get_by_def_id(def.did) { hir::Node::AnonConst(ac) => ac.body, _ => span_bug!( @@ -83,10 +78,9 @@ impl<'tcx> Const<'tcx> { match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, None => tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { + kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: def.to_global(), substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), - promoted: None, }), ty, }), @@ -153,46 +147,6 @@ impl<'tcx> Const<'tcx> { } } - pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - debug!("Const::from_inline_const(def_id={:?})", def_id); - - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - let body_id = match tcx.hir().get(hir_id) { - hir::Node::AnonConst(ac) => ac.body, - _ => span_bug!( - tcx.def_span(def_id.to_def_id()), - "from_inline_const can only process anonymous constants" - ), - }; - - let expr = &tcx.hir().body(body_id).value; - - let ty = tcx.typeck(def_id).node_type(hir_id); - - let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) { - Some(v) => v, - None => { - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); - let parent_substs = - tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); - let substs = - InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) - .substs; - tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: ty::WithOptConstParam::unknown(def_id).to_global(), - substs, - promoted: None, - }), - ty, - }) - } - }; - debug_assert!(!ret.has_free_regions()); - ret - } - /// Interns the given value as a constant. #[inline] pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self { @@ -309,6 +263,10 @@ impl<'tcx> Const<'tcx> { self.try_eval_usize(tcx, param_env) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } + + pub fn is_ct_infer(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(_)) + } } pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index cb0137d2e..4ab761e07 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,50 +1,52 @@ use std::convert::TryInto; +use crate::mir; use crate::mir::interpret::{AllocId, ConstValue, Scalar}; -use crate::mir::Promoted; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::ParamEnv; use crate::ty::{self, TyCtxt, TypeVisitable}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_target::abi::Size; use super::ScalarInt; -/// An unevaluated, potentially generic, constant. + +/// An unevaluated (potentially generic) constant used in the type-system. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] -#[derive(Hash, HashStable)] -pub struct Unevaluated<'tcx, P = Option<Promoted>> { +#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct UnevaluatedConst<'tcx> { pub def: ty::WithOptConstParam<DefId>, pub substs: SubstsRef<'tcx>, - pub promoted: P, } -impl<'tcx> Unevaluated<'tcx> { - #[inline] - pub fn shrink(self) -> Unevaluated<'tcx, ()> { - debug_assert_eq!(self.promoted, None); - Unevaluated { def: self.def, substs: self.substs, promoted: () } +impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{:?}", self).into_diagnostic_arg() } } -impl<'tcx> Unevaluated<'tcx, ()> { +impl<'tcx> UnevaluatedConst<'tcx> { #[inline] - pub fn expand(self) -> Unevaluated<'tcx> { - Unevaluated { def: self.def, substs: self.substs, promoted: None } + pub fn expand(self) -> mir::UnevaluatedConst<'tcx> { + mir::UnevaluatedConst { def: self.def, substs: self.substs, promoted: None } } } -impl<'tcx, P: Default> Unevaluated<'tcx, P> { +impl<'tcx> UnevaluatedConst<'tcx> { #[inline] - pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> { - Unevaluated { def, substs, promoted: Default::default() } + pub fn new( + def: ty::WithOptConstParam<DefId>, + substs: SubstsRef<'tcx>, + ) -> UnevaluatedConst<'tcx> { + UnevaluatedConst { def, substs } } } /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable)] +#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum ConstKind<'tcx> { /// A const generic parameter. Param(ty::ParamConst), @@ -60,7 +62,7 @@ pub enum ConstKind<'tcx> { /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other /// variants when the code is monomorphic enough for that. - Unevaluated(Unevaluated<'tcx>), + Unevaluated(UnevaluatedConst<'tcx>), /// Used to hold computed value. Value(ty::ValTree<'tcx>), @@ -71,7 +73,7 @@ pub enum ConstKind<'tcx> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstKind<'_>, 40); +static_assert_size!(ConstKind<'_>, 32); impl<'tcx> ConstKind<'tcx> { #[inline] @@ -107,7 +109,6 @@ impl<'tcx> ConstKind<'tcx> { /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] -#[derive(HashStable)] pub enum InferConst<'tcx> { /// Infer the value of the const. Var(ty::ConstVid<'tcx>), @@ -115,6 +116,15 @@ pub enum InferConst<'tcx> { Fresh(u32), } +impl<CTX> HashStable<CTX> for InferConst<'_> { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + match self { + InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"), + InferConst::Fresh(i) => i.hash_stable(hcx, hasher), + } + } +} + enum EvalMode { Typeck, Mir, @@ -174,6 +184,7 @@ impl<'tcx> ConstKind<'tcx> { param_env: ParamEnv<'tcx>, eval_mode: EvalMode, ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; @@ -194,10 +205,9 @@ impl<'tcx> ConstKind<'tcx> { // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // we can call `infcx.const_eval_resolve` which handles inference variables. let param_env_and = if param_env_and.needs_infer() { - tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { + tcx.param_env(unevaluated.def.did).and(ty::UnevaluatedConst { def: unevaluated.def, substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did), - promoted: unevaluated.promoted, }) } else { param_env_and @@ -221,7 +231,7 @@ impl<'tcx> ConstKind<'tcx> { } } EvalMode::Mir => { - match tcx.const_eval_resolve(param_env, unevaluated, None) { + match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { // NOTE(eddyb) `val` contains no lifetimes/types/consts, // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 93707bb18..a803fca0d 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. pub enum ValTree<'tcx> { - /// ZSTs, integers, `bool`, `char` are represented as scalars. + /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), @@ -27,8 +27,11 @@ pub enum ValTree<'tcx> { // dont use SliceOrStr for now /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by /// listing their fields' values in order. + /// /// Enums are represented by storing their discriminant as a field, followed by all /// the fields of the variant. + /// + /// ZST types are represented as an empty slice. Branch(&'tcx [ValTree<'tcx>]), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0a0f45ce1..3d7e2a083 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,10 +1,10 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::{DepGraph, DepKind, DepKindStruct}; +use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintLevelSource}; +use crate::lint::struct_lint_level; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; use crate::middle::stability; @@ -15,14 +15,15 @@ use crate::mir::{ use crate::thir::Thir; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; -use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, + Visibility, }; +use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts}; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -33,12 +34,16 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal}; +use rustc_data_structures::unord::UnordSet; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan}; +use rustc_errors::{ + DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; +use rustc_hir::hir_id::OwnerId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ @@ -52,7 +57,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{CrateType, OutputFilenames}; use rustc_session::cstore::CrateStoreDyn; -use rustc_session::lint::{Level, Lint}; +use rustc_session::lint::Lint; use rustc_session::Limit; use rustc_session::Session; use rustc_span::def_id::{DefPathHash, StableCrateId}; @@ -62,7 +67,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags}; +use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; use std::borrow::Borrow; @@ -75,7 +80,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::{ImplPolarity, RvalueScopes}; +use super::{ImplPolarity, ResolverOutputs, RvalueScopes}; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -194,9 +199,9 @@ impl<'tcx> CtxtInterners<'tcx> { .intern(kind, |kind| { let flags = super::flags::FlagComputation::for_kind(&kind); - // It's impossible to hash inference regions (and will ICE), so we don't need to try to cache them. + // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them. // Without incremental, we rarely stable-hash types, so let's not do it proactively. - let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER) + let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER) || sess.opts.incremental.is_none() { Fingerprint::ZERO @@ -275,9 +280,6 @@ pub struct CommonTypes<'tcx> { } pub struct CommonLifetimes<'tcx> { - /// `ReEmpty` in the root universe. - pub re_root_empty: Region<'tcx>, - /// `ReStatic` pub re_static: Region<'tcx>, @@ -290,7 +292,7 @@ pub struct CommonConsts<'tcx> { } pub struct LocalTableInContext<'a, V> { - hir_owner: LocalDefId, + hir_owner: OwnerId, data: &'a ItemLocalMap<V>, } @@ -302,7 +304,7 @@ pub struct LocalTableInContext<'a, V> { /// would result in lookup errors, or worse, in silently wrong data being /// stored/returned. #[inline] -fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) { +fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { if hir_id.owner != hir_owner { invalid_hir_id_for_typeck_results(hir_owner, hir_id); } @@ -310,7 +312,7 @@ fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) #[cold] #[inline(never)] -fn invalid_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) { +fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { ty::tls::with(|tcx| { bug!( "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}", @@ -346,7 +348,7 @@ impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> { } pub struct LocalTableInContextMut<'a, V> { - hir_owner: LocalDefId, + hir_owner: OwnerId, data: &'a mut ItemLocalMap<V>, } @@ -418,7 +420,7 @@ pub struct GeneratorDiagnosticData<'tcx> { #[derive(TyEncodable, TyDecodable, Debug, HashStable)] pub struct TypeckResults<'tcx> { /// The `HirId::owner` all `ItemLocalId`s in this table are relative to. - pub hir_owner: LocalDefId, + pub hir_owner: OwnerId, /// Resolved definitions for `<T>::X` associated paths and /// method calls, including those of overloaded operators. @@ -530,19 +532,17 @@ pub struct TypeckResults<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>, + pub used_trait_imports: Lrc<UnordSet<LocalDefId>>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorGuaranteed)`. pub tainted_by_errors: Option<ErrorGuaranteed>, /// All the opaque types that have hidden types set - /// by this function. For return-position-impl-trait we also store the - /// type here, so that mir-borrowck can figure out hidden types, + /// by this function. We also store the + /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - /// For type-alias-impl-trait, this map is only used to prevent query cycles, - /// so the hidden types are all `None`. - pub concrete_opaque_types: VecMap<LocalDefId, Option<Ty<'tcx>>>, + pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -574,7 +574,7 @@ pub struct TypeckResults<'tcx> { /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions /// by applying extended parameter rules. - /// Details may be find in `rustc_typeck::check::rvalue_scopes`. + /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. pub rvalue_scopes: RvalueScopes, /// Stores the type, expression, span and optional scope span of all types @@ -593,7 +593,7 @@ pub struct TypeckResults<'tcx> { } impl<'tcx> TypeckResults<'tcx> { - pub fn new(hir_owner: LocalDefId) -> TypeckResults<'tcx> { + pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> { TypeckResults { hir_owner, type_dependent_defs: Default::default(), @@ -874,7 +874,7 @@ pub type CanonicalUserTypeAnnotations<'tcx> = #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalUserTypeAnnotation<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, + pub user_ty: Box<CanonicalUserType<'tcx>>, pub span: Span, pub inferred_ty: Ty<'tcx>, } @@ -986,11 +986,7 @@ impl<'tcx> CommonLifetimes<'tcx> { )) }; - CommonLifetimes { - re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)), - re_static: mk(ty::ReStatic), - re_erased: mk(ty::ReErased), - } + CommonLifetimes { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased) } } } @@ -1072,10 +1068,9 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, definitions: RwLock<Definitions>, - cstore: Box<CrateStoreDyn>, /// Output of the resolver. - pub(crate) untracked_resolutions: ty::ResolverOutputs, + pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt, untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>, /// The entire crate as AST. This field serves as the input for the hir_crate query, /// which lowers it from AST to HIR. It must not be read or used by anything else. @@ -1089,7 +1084,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, - query_kinds: &'tcx [DepKindStruct], + pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>, @@ -1238,27 +1233,29 @@ impl<'tcx> TyCtxt<'tcx> { lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, - definitions: Definitions, - cstore: Box<CrateStoreDyn>, - untracked_resolutions: ty::ResolverOutputs, - untracked_resolver_for_lowering: ty::ResolverAstLowering, + resolver_outputs: ResolverOutputs, krate: Lrc<ast::Crate>, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, - query_kinds: &'tcx [DepKindStruct], + query_kinds: &'tcx [DepKindStruct<'tcx>], crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { + let ResolverOutputs { + definitions, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = resolver_outputs; let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { - s.fatal(&err); + s.emit_fatal(err); }); let interners = CtxtInterners::new(arena); let common_types = CommonTypes::new( &interners, s, &definitions, - &*cstore, + &*untracked_resolutions.cstore, // This is only used to create a stable hashing context. &untracked_resolutions.source_span, ); @@ -1273,7 +1270,6 @@ impl<'tcx> TyCtxt<'tcx> { interners, dep_graph, definitions: RwLock::new(definitions), - cstore, prof: s.prof.clone(), types: common_types, lifetimes: common_lifetimes, @@ -1296,10 +1292,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { - &self.query_kinds[k as usize] - } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. #[track_caller] pub fn ty_error(self) -> Ty<'tcx> { @@ -1378,7 +1370,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_key(id) } else { - self.cstore.def_key(id) + self.untracked_resolutions.cstore.def_key(id) } } @@ -1392,7 +1384,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_path(id) } else { - self.cstore.def_path(id) + self.untracked_resolutions.cstore.def_path(id) } } @@ -1402,7 +1394,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(def_id) = def_id.as_local() { self.definitions_untracked().def_path_hash(def_id) } else { - self.cstore.def_path_hash(def_id) + self.untracked_resolutions.cstore.def_path_hash(def_id) } } @@ -1411,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { if crate_num == LOCAL_CRATE { self.sess.local_stable_crate_id() } else { - self.cstore.stable_crate_id(crate_num) + self.untracked_resolutions.cstore.stable_crate_id(crate_num) } } @@ -1422,7 +1414,7 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.sess.local_stable_crate_id() { LOCAL_CRATE } else { - self.cstore.stable_crate_id_to_crate_num(stable_crate_id) + self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id) } } @@ -1441,8 +1433,9 @@ impl<'tcx> TyCtxt<'tcx> { } else { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. - let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id); - self.cstore.def_path_hash_to_def_id(cnum, hash) + let cstore = &*self.untracked_resolutions.cstore; + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + cstore.def_path_hash_to_def_id(cnum, hash) } } @@ -1454,7 +1447,7 @@ impl<'tcx> TyCtxt<'tcx> { let (crate_name, stable_crate_id) = if def_id.is_local() { (self.crate_name, self.sess.local_stable_crate_id()) } else { - let cstore = &self.cstore; + let cstore = &*self.untracked_resolutions.cstore; (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate)) }; @@ -1498,17 +1491,17 @@ impl<'tcx> TyCtxt<'tcx> { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.iter_local_def_id() } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_table() @@ -1517,10 +1510,10 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path_hash_to_def_index_map( self, ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_hash_to_def_index_map() @@ -1529,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn { - &*self.cstore + &*self.untracked_resolutions.cstore } /// Note that this is *untracked* and should only be used within the query @@ -1555,7 +1548,7 @@ impl<'tcx> TyCtxt<'tcx> { let hcx = StableHashingContext::new( self.sess, &*definitions, - &*self.cstore, + &*self.untracked_resolutions.cstore, &self.untracked_resolutions.source_span, ); f(hcx) @@ -1596,7 +1589,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. + /// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo> { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { @@ -1728,6 +1721,11 @@ impl<'tcx> TyCtxt<'tcx> { .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) } + + #[inline] + pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { + self.visibility(def_id).expect_local() + } } /// A trait implemented for all `X<'a>` types that can be safely and @@ -1821,7 +1819,9 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } +CloneLiftImpls! { for<'tcx> { + Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint, +} } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; @@ -1829,9 +1829,9 @@ pub mod tls { use crate::dep_graph::TaskDepsRef; use crate::ty::query; use rustc_data_structures::sync::{self, Lock}; - use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use std::mem; + use thin_vec::ThinVec; #[cfg(not(parallel_compiler))] use std::cell::Cell; @@ -1857,8 +1857,8 @@ pub mod tls { /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>, - /// Used to prevent layout from recursing too deeply. - pub layout_depth: usize, + /// Used to prevent queries from calling too deeply. + pub query_depth: usize, /// The current dep graph task. This is used to add dependencies to queries /// when executing them. @@ -1872,7 +1872,7 @@ pub mod tls { tcx, query: None, diagnostics: None, - layout_depth: 0, + query_depth: 0, task_deps: TaskDepsRef::Ignore, } } @@ -2366,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> { st, self.sess, &self.definitions.read(), - &*self.cstore, + &*self.untracked_resolutions.cstore, // This is only used to create a stable hashing context. &self.untracked_resolutions.source_span, ) @@ -2546,8 +2546,9 @@ impl<'tcx> TyCtxt<'tcx> { self, obj: &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>, reg: ty::Region<'tcx>, + repr: DynKind, ) -> Ty<'tcx> { - self.mk_ty(Dynamic(obj, reg)) + self.mk_ty(Dynamic(obj, reg, repr)) } #[inline] @@ -2810,44 +2811,6 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_bound_variable_kinds(xs)) } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. - /// It stops at `bound` and just returns it if reached. - pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { - let hir = self.hir(); - loop { - if id == bound { - return bound; - } - - if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { - return id; - } - let next = hir.get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - - pub fn lint_level_at_node( - self, - lint: &'static Lint, - mut id: hir::HirId, - ) -> (Level, LintLevelSource) { - let sets = self.lint_levels(()); - loop { - if let Some(pair) = sets.level_and_source(lint, id, self.sess) { - return pair; - } - let next = self.hir().get_parent_node(id); - if next == id { - bug!("lint traversal reached the root of the crate"); - } - id = next; - } - } - /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// typically generated by `#[derive(LintDiagnostic)]`). pub fn emit_spanned_lint( @@ -2857,18 +2820,28 @@ impl<'tcx> TyCtxt<'tcx> { span: impl Into<MultiSpan>, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag)) + self.struct_span_lint_hir(lint, hir_id, span, decorator.msg(), |diag| { + decorator.decorate_lint(diag) + }) } + /// Emit a lint at the appropriate level for a hir node, with an associated span. + /// + /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. + /// + /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature pub fn struct_span_lint_hir( self, lint: &'static Lint, hir_id: HirId, span: impl Into<MultiSpan>, - decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>), + msg: impl Into<DiagnosticMessage>, + decorate: impl for<'a, 'b> FnOnce( + &'b mut DiagnosticBuilder<'a, ()>, + ) -> &'b mut DiagnosticBuilder<'a, ()>, ) { let (level, src) = self.lint_level_at_node(lint, hir_id); - struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate); + struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate); } /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically @@ -2879,17 +2852,25 @@ impl<'tcx> TyCtxt<'tcx> { id: HirId, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag)) + self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag)) } + /// Emit a lint at the appropriate level for a hir node. + /// + /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. + /// + /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature pub fn struct_lint_node( self, lint: &'static Lint, id: HirId, - decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>), + msg: impl Into<DiagnosticMessage>, + decorate: impl for<'a, 'b> FnOnce( + &'b mut DiagnosticBuilder<'a, ()>, + ) -> &'b mut DiagnosticBuilder<'a, ()>, ) { let (level, src) = self.lint_level_at_node(lint, id); - struct_lint_level(self.sess, lint, level, src, None, decorate); + struct_lint_level(self.sess, lint, level, src, None, msg, decorate); } pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { @@ -2904,7 +2885,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map_or(false, |set| { + self.is_late_bound_map(id.owner.def_id).map_or(false, |set| { let def_id = self.hir().local_def_id(id); set.contains(&def_id) }) @@ -2975,6 +2956,21 @@ impl<'tcx> TyCtxtAt<'tcx> { } } +/// Parameter attributes that can only be determined by examining the body of a function instead +/// of just its signature. +/// +/// These can be useful for optimization purposes when a function is directly called. We compute +/// them and store them into the crate metadata so that downstream crates can make use of them. +/// +/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the +/// future. +#[derive(Clone, Copy, PartialEq, Debug, Default, TyDecodable, TyEncodable, HashStable)] +pub struct DeducedParamAttrs { + /// The parameter is marked immutable in the function and contains no `UnsafeCell` (i.e. its + /// type is freeze). + pub read_only: bool, +} + // We are comparing types with different invariant lifetimes, so `ptr::eq` // won't work for us. fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index dd2f43210..b8fd01e6a 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -102,13 +102,25 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( generics: &hir::Generics<'_>, err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, + associated_ty: Option<(&'static str, Ty<'tcx>)>, ) -> bool { if !trait_pred.is_suggestable(tcx, false) { return false; } let param_name = trait_pred.skip_binder().self_ty().to_string(); - let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + + if let Some((name, term)) = associated_ty { + // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. + // That should be extracted into a helper function. + if constraint.ends_with('>') { + constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term); + } else { + constraint.push_str(&format!("<{} = {}>", name, term)); + } + } + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); // Skip, there is a param named Self @@ -396,7 +408,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { ) => { self.0.push(ty); } - hir::TyKind::OpaqueDef(item_id, _) => { + hir::TyKind::OpaqueDef(item_id, _, _) => { self.0.push(ty); let item = self.1.item(item_id); hir::intravisit::walk_item(self, item); @@ -455,7 +467,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } - Dynamic(dty, _) => { + Dynamic(dty, _, _) => { for pred in *dty { match pred.skip_binder() { ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { @@ -499,3 +511,11 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { c.super_visit_with(self) } } + +#[derive(Diagnostic)] +#[diag(borrowck_const_not_used_in_type_alias)] +pub(super) struct ConstNotUsedTraitAlias { + pub ct: String, + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 3226950e7..ffdac93bc 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,4 +1,3 @@ -use crate::mir; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::ty::visit::TypeVisitable; use crate::ty::{self, Ty, TyCtxt, TypeFlags}; @@ -67,8 +66,4 @@ impl<'tcx> TypeFolder<'tcx> for RegionEraserVisitor<'tcx> { _ => self.tcx.lifetimes.re_erased, } } - - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { - c.super_fold_with(self) - } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 4b0bc3c11..4e6cdb786 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -2,6 +2,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; +use hir::def::DefKind; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -13,7 +14,7 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::fmt; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)] pub struct ExpectedFound<T> { pub expected: T, pub found: T, @@ -30,7 +31,8 @@ impl<T> ExpectedFound<T> { } // Data structures used in type unification -#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] +#[rustc_pass_by_value] pub enum TypeError<'tcx> { Mismatch, ConstnessMismatch(ExpectedFound<ty::BoundConstness>), @@ -73,6 +75,18 @@ pub enum TypeError<'tcx> { TargetFeatureCast(DefId), } +impl TypeError<'_> { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsOverlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } +} + /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related @@ -211,7 +225,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(&self) -> bool { + pub fn must_include_note(self) -> bool { use self::TypeError::*; match self { CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) @@ -263,10 +277,23 @@ impl<'tcx> Ty<'tcx> { } ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(), ty::Slice(_) => "slice".into(), - ty::RawPtr(_) => "*-ptr".into(), + ty::RawPtr(tymut) => { + let tymut_string = match tymut.mutbl { + hir::Mutability::Mut => tymut.to_string(), + hir::Mutability::Not => format!("const {}", tymut.ty), + }; + + if tymut_string != "_" && (tymut.ty.is_simple_text() || tymut_string.len() < "const raw pointer".len()) { + format!("`*{}`", tymut_string).into() + } else { + // Unknown type name, it's long or has type arguments + "raw pointer".into() + } + }, ty::Ref(_, ty, mutbl) => { let tymut = ty::TypeAndMut { ty, mutbl }; let tymut_string = tymut.to_string(); + if tymut_string != "_" && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len()) { @@ -347,7 +374,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn note_and_explain_type_err( self, diag: &mut Diagnostic, - err: &TypeError<'tcx>, + err: TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, body_owner_def_id: DefId, @@ -512,7 +539,7 @@ impl<T> Trait<T> for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Projection(proj_ty), _) => { + (ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => { self.expected_projection( diag, proj_ty, @@ -521,7 +548,7 @@ impl<T> Trait<T> for X { cause.code(), ); } - (_, ty::Projection(proj_ty)) => { + (_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => { let msg = format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, @@ -568,7 +595,7 @@ impl<T> Trait<T> for X { } TargetFeatureCast(def_id) => { let target_spans = - self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span); + self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); @@ -640,7 +667,7 @@ impl<T> Trait<T> for X { self, diag: &mut Diagnostic, proj_ty: &ty::ProjectionTy<'tcx>, - values: &ExpectedFound<Ty<'tcx>>, + values: ExpectedFound<Ty<'tcx>>, body_owner_def_id: DefId, cause_code: &ObligationCauseCode<'_>, ) { @@ -834,7 +861,7 @@ fn foo(&self) -> Self::T { String::new() } // When `body_owner` is an `impl` or `trait` item, look in its associated types for // `expected` and point at it. let parent_id = self.hir().get_parent_item(hir_id); - let item = self.hir().find_by_def_id(parent_id); + let item = self.hir().find_by_def_id(parent_id.def_id); debug!("expected_projection parent item {:?}", item); match item { Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => { @@ -845,9 +872,9 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: account for returning some type in a trait fn impl that has // an assoc type as a return type (#72076). if let hir::Defaultness::Default { has_value: true } = - self.impl_defaultness(item.id.def_id) + self.impl_defaultness(item.id.owner_id) { - if self.type_of(item.id.def_id) == found { + if self.type_of(item.id.owner_id) == found { diag.span_label( item.span, "associated type defaults can't be assumed inside the \ @@ -867,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() } })) => { for item in &items[..] { if let hir::AssocItemKind::Type = item.kind { - if self.type_of(item.id.def_id) == found { + if self.type_of(item.id.owner_id) == found { diag.span_label(item.span, "expected this associated type"); return true; } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 8d019a3ba..3be0bc4de 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -132,7 +132,7 @@ pub fn simplify_type<'tcx>( // don't unify with anything else as long as they are fully normalized. // // We will have to be careful with lazy normalization here. - TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => { + TreatParams::AsPlaceholder if !ty.has_non_region_infer() => { debug!("treating `{}` as a placeholder", ty); Some(PlaceholderSimplifiedType) } @@ -384,14 +384,7 @@ impl DeepRejectCtxt { // they might unify with any value. ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true, ty::ConstKind::Value(obl) => match k { - ty::ConstKind::Value(imp) => { - // FIXME(valtrees): Once we have valtrees, we can just - // compare them directly here. - match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) { - (Some(obl), Some(imp)) => obl == imp, - _ => true, - } - } + ty::ConstKind::Value(imp) => obl == imp, _ => true, }, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ea6bb8a7a..7201737be 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -1,5 +1,5 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, InferConst, Term, Ty, TypeFlags}; +use crate::ty::{self, InferConst, Ty, TypeFlags}; use std::slice; #[derive(Debug)] @@ -34,12 +34,6 @@ impl FlagComputation { result.flags } - pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags { - let mut result = FlagComputation::new(); - result.add_unevaluated_const(uv); - result.flags - } - fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -171,7 +165,7 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Dynamic(obj, r) => { + &ty::Dynamic(obj, r, _) => { for predicate in obj.iter() { self.bound_computation(predicate, |computation, predicate| match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), @@ -243,9 +237,9 @@ impl FlagComputation { } ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { self.add_projection_ty(projection_ty); - match term { - Term::Ty(ty) => self.add_ty(ty), - Term::Const(c) => self.add_const(c), + match term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(c) => self.add_const(c), } } ty::PredicateKind::WellFormed(arg) => { @@ -256,7 +250,7 @@ impl FlagComputation { self.add_substs(substs); } ty::PredicateKind::ConstEvaluatable(uv) => { - self.add_unevaluated_const(uv); + self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); @@ -289,7 +283,10 @@ impl FlagComputation { fn add_const(&mut self, c: ty::Const<'_>) { self.add_ty(c.ty()); match c.kind() { - ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated), + ty::ConstKind::Unevaluated(uv) => { + self.add_substs(uv.substs); + self.add_flags(TypeFlags::HAS_CT_PROJECTION); + } ty::ConstKind::Infer(infer) => { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); match infer { @@ -313,16 +310,11 @@ impl FlagComputation { } } - fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, P>) { - self.add_substs(ct.substs); - self.add_flags(TypeFlags::HAS_CT_PROJECTION); - } - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); - match projection.term { - ty::Term::Ty(ty) => self.add_ty(ty), - ty::Term::Const(ct) => self.add_const(ct), + match projection.term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e96e278b..54f1499eb 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -13,8 +13,7 @@ //! //! There are three groups of traits involved in each traversal. //! - `TypeFoldable`. This is implemented once for many types, including: -//! - Types of interest, for which the the methods delegate to the -//! folder. +//! - Types of interest, for which the methods delegate to the folder. //! - All other types, including generic containers like `Vec` and `Option`. //! It defines a "skeleton" of how they should be folded. //! - `TypeSuperFoldable`. This is implemented only for each type of interest, @@ -43,7 +42,6 @@ //! - ty.super_fold_with(folder) //! - u.fold_with(folder) //! ``` -use crate::mir; use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; @@ -128,17 +126,9 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> { c.super_fold_with(self) } - fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> { - uv.super_fold_with(self) - } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { p.super_fold_with(self) } - - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { - bug!("most type folders should not be folding MIR datastructures: {:?}", c) - } } /// This trait is implemented for every folding traversal. There is a fold @@ -172,26 +162,12 @@ pub trait FallibleTypeFolder<'tcx>: Sized { c.try_super_fold_with(self) } - fn try_fold_unevaluated( - &mut self, - c: ty::Unevaluated<'tcx>, - ) -> Result<ty::Unevaluated<'tcx>, Self::Error> { - c.try_super_fold_with(self) - } - fn try_fold_predicate( &mut self, p: ty::Predicate<'tcx>, ) -> Result<ty::Predicate<'tcx>, Self::Error> { p.try_super_fold_with(self) } - - fn try_fold_mir_const( - &mut self, - c: mir::ConstantKind<'tcx>, - ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { - bug!("most type folders should not be folding MIR datastructures: {:?}", c) - } } // This blanket implementation of the fallible trait for infallible folders @@ -225,23 +201,9 @@ where Ok(self.fold_const(c)) } - fn try_fold_unevaluated( - &mut self, - c: ty::Unevaluated<'tcx>, - ) -> Result<ty::Unevaluated<'tcx>, !> { - Ok(self.fold_unevaluated(c)) - } - fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> { Ok(self.fold_predicate(p)) } - - fn try_fold_mir_const( - &mut self, - c: mir::ConstantKind<'tcx>, - ) -> Result<mir::ConstantKind<'tcx>, !> { - Ok(self.fold_mir_const(c)) - } } /////////////////////////////////////////////////////////////////////////// @@ -302,6 +264,17 @@ impl<'tcx> TyCtxt<'tcx> { { value.fold_with(&mut RegionFolder::new(self, &mut f)) } + + pub fn super_fold_regions<T>( + self, + value: T, + mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> T + where + T: TypeSuperFoldable<'tcx>, + { + value.super_fold_with(&mut RegionFolder::new(self, &mut f)) + } } /// Folds over the substructure of a type, visiting its component @@ -353,7 +326,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { t } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { @@ -377,17 +350,13 @@ pub trait BoundVarReplacerDelegate<'tcx> { fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>; } -pub struct FnMutDelegate<R, T, C> { - pub regions: R, - pub types: T, - pub consts: C, +pub struct FnMutDelegate<'a, 'tcx> { + pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), + pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a), } -impl<'tcx, R, T, C> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<R, T, C> -where - R: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - T: FnMut(ty::BoundTy) -> Ty<'tcx>, - C: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>, -{ + +impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> { (self.regions)(br) } @@ -511,7 +480,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_late_bound_regions_uncached<T, F>( self, value: Binder<'tcx, T>, - replace_regions: F, + mut replace_regions: F, ) -> T where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -522,9 +491,9 @@ impl<'tcx> TyCtxt<'tcx> { value } else { let delegate = FnMutDelegate { - regions: replace_regions, - types: |b| bug!("unexpected bound ty in binder: {b:?}"), - consts: |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + regions: &mut replace_regions, + types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), + consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); value.fold_with(&mut replacer) @@ -584,19 +553,19 @@ impl<'tcx> TyCtxt<'tcx> { self.replace_escaping_bound_vars_uncached( value, FnMutDelegate { - regions: |r: ty::BoundRegion| { + regions: &mut |r: ty::BoundRegion| { self.mk_region(ty::ReLateBound( ty::INNERMOST, ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, )) }, - types: |t: ty::BoundTy| { + types: &mut |t: ty::BoundTy| { self.mk_ty(ty::Bound( ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, )) }, - consts: |c, ty: Ty<'tcx>| { + consts: &mut |c, ty: Ty<'tcx>| { self.mk_const(ty::ConstS { kind: ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index add2df258..19754d145 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,7 +1,5 @@ -use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::ty; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::EarlyBinder; +use crate::ty::{EarlyBinder, SubstsRef}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; @@ -13,7 +11,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { Lifetime, - Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool }, + Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } @@ -28,8 +26,9 @@ impl GenericParamDefKind { pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, - GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type, - GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const, + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + ast::ParamKindOrd::TypeOrConst + } } } @@ -122,6 +121,21 @@ pub struct Generics { } impl<'tcx> Generics { + /// Looks through the generics and all parents to find the index of the + /// given param def-id. This is in comparison to the `param_def_id_to_index` + /// struct member, which only stores information about this item's own + /// generics. + pub fn param_def_id_to_index(&self, tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<u32> { + if let Some(idx) = self.param_def_id_to_index.get(&def_id) { + Some(*idx) + } else if let Some(parent) = self.parent { + let parent = tcx.generics_of(parent); + parent.param_def_id_to_index(tcx, def_id) + } else { + None + } + } + #[inline] pub fn count(&self) -> usize { self.parent_count + self.params.len() @@ -252,7 +266,7 @@ impl<'tcx> Generics { // Filter the default arguments. // // This currently uses structural equality instead - // of semantic equivalance. While not ideal, that's + // of semantic equivalence. While not ideal, that's // good enough for now as this should only be used // for diagnostics anyways. own_params.end -= self @@ -314,6 +328,7 @@ impl<'tcx> GenericPredicates<'tcx> { } } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index cd00b26b8..d1c0d62ac 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -113,7 +113,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { } // `Relocations` with default type parameters is a sorted map. -impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Prov> +impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::ProvenanceMap<Prov> where Prov: HashStable<StableHashingContext<'a>>, { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs deleted file mode 100644 index c4ad698ba..000000000 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::ty::context::TyCtxt; -use crate::ty::{DefId, DefIdTree}; -use rustc_span::def_id::CRATE_DEF_ID; -use smallvec::SmallVec; -use std::mem; - -use DefIdForest::*; - -/// Represents a forest of `DefId`s closed under the ancestor relation. That is, -/// if a `DefId` representing a module is contained in the forest then all -/// `DefId`s defined in that module or submodules are also implicitly contained -/// in the forest. -/// -/// This is used to represent a set of modules in which a type is visibly -/// uninhabited. -/// -/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are -/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is -/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored. -#[derive(Copy, Clone, HashStable, Debug)] -pub enum DefIdForest<'a> { - Empty, - Single(DefId), - /// This variant is very rare. - /// Invariant: >1 elements - Multiple(&'a [DefId]), -} - -/// Tests whether a slice of roots contains a given DefId. -#[inline] -fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool { - slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id)) -} - -impl<'tcx> DefIdForest<'tcx> { - /// Creates an empty forest. - pub fn empty() -> DefIdForest<'tcx> { - DefIdForest::Empty - } - - /// Creates a forest consisting of a single tree representing the entire - /// crate. - #[inline] - pub fn full() -> DefIdForest<'tcx> { - DefIdForest::from_id(CRATE_DEF_ID.to_def_id()) - } - - /// Creates a forest containing a `DefId` and all its descendants. - pub fn from_id(id: DefId) -> DefIdForest<'tcx> { - DefIdForest::Single(id) - } - - fn as_slice(&self) -> &[DefId] { - match self { - Empty => &[], - Single(id) => std::slice::from_ref(id), - Multiple(root_ids) => root_ids, - } - } - - // Only allocates in the rare `Multiple` case. - fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> { - match &root_ids[..] { - [] => Empty, - [id] => Single(*id), - _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)), - } - } - - /// Tests whether the forest is empty. - pub fn is_empty(&self) -> bool { - match self { - Empty => true, - Single(..) | Multiple(..) => false, - } - } - - /// Iterate over the set of roots. - fn iter(&self) -> impl Iterator<Item = DefId> + '_ { - self.as_slice().iter().copied() - } - - /// Tests whether the forest contains a given DefId. - pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool { - slice_contains(tcx, self.as_slice(), id) - } - - /// Calculate the intersection of a collection of forests. - pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx> - where - I: IntoIterator<Item = DefIdForest<'tcx>>, - { - let mut iter = iter.into_iter(); - let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() { - SmallVec::from_slice(first.as_slice()) - } else { - return DefIdForest::full(); - }; - - let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); - for next_forest in iter { - // No need to continue if the intersection is already empty. - if ret.is_empty() || next_forest.is_empty() { - return DefIdForest::empty(); - } - - // We keep the elements in `ret` that are also in `next_forest`. - next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id))); - // We keep the elements in `next_forest` that are also in `ret`. - next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id))); - - mem::swap(&mut next_ret, &mut ret); - next_ret.clear(); - } - DefIdForest::from_vec(tcx, ret) - } - - /// Calculate the union of a collection of forests. - pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx> - where - I: IntoIterator<Item = DefIdForest<'tcx>>, - { - let mut ret: SmallVec<[_; 1]> = SmallVec::new(); - let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); - for next_forest in iter { - // Union with the empty set is a no-op. - if next_forest.is_empty() { - continue; - } - - // We add everything in `ret` that is not in `next_forest`. - next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id))); - // We add everything in `next_forest` that we haven't added yet. - for id in next_forest.iter() { - if !slice_contains(tcx, &next_ret, id) { - next_ret.push(id); - } - } - - mem::swap(&mut next_ret, &mut ret); - next_ret.clear(); - } - DefIdForest::from_vec(tcx, ret) - } -} diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs new file mode 100644 index 000000000..b7aa45572 --- /dev/null +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -0,0 +1,204 @@ +use crate::ty::context::TyCtxt; +use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty}; + +/// Represents whether some type is inhabited in a given context. +/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct +/// containing either of those types. +/// A type's inhabitedness may depend on the `ParamEnv` as well as what types +/// are visible in the current module. +#[derive(Clone, Copy, Debug, PartialEq, HashStable)] +pub enum InhabitedPredicate<'tcx> { + /// Inhabited + True, + /// Uninhabited + False, + /// Uninhabited when a const value is non-zero. This occurs when there is an + /// array of uninhabited items, but the array is inhabited if it is empty. + ConstIsZero(ty::Const<'tcx>), + /// Uninhabited if within a certain module. This occurs when an uninhabited + /// type has restricted visibility. + NotInModule(DefId), + /// Inhabited if some generic type is inhabited. + /// These are replaced by calling [`Self::subst`]. + GenericType(Ty<'tcx>), + /// A AND B + And(&'tcx [InhabitedPredicate<'tcx>; 2]), + /// A OR B + Or(&'tcx [InhabitedPredicate<'tcx>; 2]), +} + +impl<'tcx> InhabitedPredicate<'tcx> { + /// Returns true if the corresponding type is inhabited in the given + /// `ParamEnv` and module + pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool { + let Ok(result) = self + .apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id))); + result + } + + /// Same as `apply`, but returns `None` if self contains a module predicate + pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { + self.apply_inner(tcx, param_env, &|_| Err(())).ok() + } + + fn apply_inner<E>( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + in_module: &impl Fn(DefId) -> Result<bool, E>, + ) -> Result<bool, E> { + match self { + Self::False => Ok(false), + Self::True => Ok(true), + Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) { + None | Some(0) => Ok(true), + Some(1..) => Ok(false), + }, + Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod), + Self::GenericType(_) => Ok(true), + Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)), + Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)), + } + } + + pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self { + self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other]))) + } + + pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self { + self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other]))) + } + + pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self { + let mut result = Self::True; + for pred in iter { + if matches!(pred, Self::False) { + return Self::False; + } + result = result.and(tcx, pred); + } + result + } + + pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self { + let mut result = Self::False; + for pred in iter { + if matches!(pred, Self::True) { + return Self::True; + } + result = result.or(tcx, pred); + } + result + } + + fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> { + match (self, other) { + (Self::True, a) | (a, Self::True) => Some(a), + (Self::False, _) | (_, Self::False) => Some(Self::False), + (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => { + Some(Self::NotInModule(b)) + } + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => { + Some(Self::NotInModule(a)) + } + (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)), + (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => { + if let Some(ac) = a.reduce_and(tcx, c) { + Some(ac.and(tcx, b)) + } else if let Some(bc) = b.reduce_and(tcx, c) { + Some(Self::And(tcx.arena.alloc([a, bc]))) + } else { + None + } + } + _ => None, + } + } + + fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> { + match (self, other) { + (Self::True, _) | (_, Self::True) => Some(Self::True), + (Self::False, a) | (a, Self::False) => Some(a), + (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => { + Some(Self::NotInModule(a)) + } + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => { + Some(Self::NotInModule(b)) + } + (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)), + (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => { + if let Some(ac) = a.reduce_or(tcx, c) { + Some(ac.or(tcx, b)) + } else if let Some(bc) = b.reduce_or(tcx, c) { + Some(Self::Or(tcx.arena.alloc([a, bc]))) + } else { + None + } + } + _ => None, + } + } + + /// Replaces generic types with its corresponding predicate + pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self { + self.subst_opt(tcx, substs).unwrap_or(self) + } + + fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> { + match self { + Self::ConstIsZero(c) => { + let c = ty::EarlyBinder(c).subst(tcx, substs); + let pred = match c.kind().try_to_machine_usize(tcx) { + Some(0) => Self::True, + Some(1..) => Self::False, + None => Self::ConstIsZero(c), + }; + Some(pred) + } + Self::GenericType(t) => { + Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx)) + } + Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { + None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), + Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False), + Some(a) => Some(a.and(tcx, b.subst_opt(tcx, substs).unwrap_or(b))), + }, + Self::Or(&[a, b]) => match a.subst_opt(tcx, substs) { + None => b.subst_opt(tcx, substs).map(|b| a.or(tcx, b)), + Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True), + Some(a) => Some(a.or(tcx, b.subst_opt(tcx, substs).unwrap_or(b))), + }, + _ => None, + } + } +} + +// this is basically like `f(a)? && f(b)?` but different in the case of +// `Ok(false) && Err(_) -> Ok(false)` +fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> { + let a = f(a); + if matches!(a, Ok(false)) { + return Ok(false); + } + match (a, f(b)) { + (_, Ok(false)) | (Ok(false), _) => Ok(false), + (Ok(true), Ok(true)) => Ok(true), + (Err(e), _) | (_, Err(e)) => Err(e), + } +} + +fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> { + let a = f(a); + if matches!(a, Ok(true)) { + return Ok(true); + } + match (a, f(b)) { + (_, Ok(true)) | (Ok(true), _) => Ok(true), + (Ok(false), Ok(false)) => Ok(false), + (Err(e), _) | (_, Err(e)) => Err(e), + } +} diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 3d22f5a04..279a728ea 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -1,57 +1,60 @@ -pub use self::def_id_forest::DefIdForest; +//! This module contains logic for determining whether a type is inhabited or +//! uninhabited. The [`InhabitedPredicate`] type captures the minimum +//! information needed to determine whether a type is inhabited given a +//! `ParamEnv` and module ID. +//! +//! # Example +//! ```rust +//! enum Void {} +//! mod a { +//! pub mod b { +//! pub struct SecretlyUninhabited { +//! _priv: !, +//! } +//! } +//! } +//! +//! mod c { +//! pub struct AlsoSecretlyUninhabited { +//! _priv: Void, +//! } +//! mod d { +//! } +//! } +//! +//! struct Foo { +//! x: a::b::SecretlyUninhabited, +//! y: c::AlsoSecretlyUninhabited, +//! } +//! ``` +//! In this code, the type `Foo` will only be visibly uninhabited inside the +//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will +//! return `NotInModule(b) AND NotInModule(c)`. +//! +//! We need this information for pattern-matching on `Foo` or types that contain +//! `Foo`. +//! +//! # Example +//! ```rust +//! let foo_result: Result<T, Foo> = ... ; +//! let Ok(t) = foo_result; +//! ``` +//! This code should only compile in modules where the uninhabitedness of `Foo` +//! is visible. -use crate::ty; use crate::ty::context::TyCtxt; -use crate::ty::{AdtDef, FieldDef, Ty, VariantDef}; -use crate::ty::{AdtKind, Visibility}; -use crate::ty::{DefId, SubstsRef}; +use crate::ty::{self, DefId, Ty, VariantDef, Visibility}; use rustc_type_ir::sty::TyKind::*; -mod def_id_forest; +pub mod inhabited_predicate; -// The methods in this module calculate `DefIdForest`s of modules in which an -// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited. -// -// # Example -// ```rust -// enum Void {} -// mod a { -// pub mod b { -// pub struct SecretlyUninhabited { -// _priv: !, -// } -// } -// } -// -// mod c { -// pub struct AlsoSecretlyUninhabited { -// _priv: Void, -// } -// mod d { -// } -// } -// -// struct Foo { -// x: a::b::SecretlyUninhabited, -// y: c::AlsoSecretlyUninhabited, -// } -// ``` -// In this code, the type `Foo` will only be visibly uninhabited inside the -// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will -// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the -// set {`b`, `c`}). -// -// We need this information for pattern-matching on `Foo` or types that contain -// `Foo`. -// -// # Example -// ```rust -// let foo_result: Result<T, Foo> = ... ; -// let Ok(t) = foo_result; -// ``` -// This code should only compile in modules where the uninhabitedness of `Foo` is -// visible. +pub use inhabited_predicate::InhabitedPredicate; + +pub(crate) fn provide(providers: &mut ty::query::Providers) { + *providers = + ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; +} impl<'tcx> TyCtxt<'tcx> { /// Checks whether a type is visibly uninhabited from a particular module. @@ -100,135 +103,92 @@ impl<'tcx> TyCtxt<'tcx> { ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { - // To check whether this type is uninhabited at all (not just from the - // given node), you could check whether the forest is empty. - // ``` - // forest.is_empty() - // ``` - ty.uninhabited_from(self, param_env).contains(self, module) + !ty.inhabited_predicate(self).apply(self, param_env, module) } } -impl<'tcx> AdtDef<'tcx> { - /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. - fn uninhabited_from( - self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - // Non-exhaustive ADTs from other crates are always considered inhabited. - if self.is_variant_list_non_exhaustive() && !self.did().is_local() { - DefIdForest::empty() - } else { - DefIdForest::intersection( - tcx, - self.variants() - .iter() - .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)), - ) +/// Returns an `InhabitedPredicate` that is generic over type parameters and +/// requires calling [`InhabitedPredicate::subst`] +fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { + if let Some(def_id) = def_id.as_local() { + if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + return InhabitedPredicate::True; } } + let adt = tcx.adt_def(def_id); + InhabitedPredicate::any( + tcx, + adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)), + ) } impl<'tcx> VariantDef { /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited. - pub fn uninhabited_from( + pub fn inhabited_predicate( &self, tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - adt_kind: AdtKind, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - let is_enum = match adt_kind { - // For now, `union`s are never considered uninhabited. - // The precise semantics of inhabitedness with respect to unions is currently undecided. - AdtKind::Union => return DefIdForest::empty(), - AdtKind::Enum => true, - AdtKind::Struct => false, - }; - // Non-exhaustive variants from other crates are always considered inhabited. + adt: ty::AdtDef<'_>, + ) -> InhabitedPredicate<'tcx> { + debug_assert!(!adt.is_union()); if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { - DefIdForest::empty() - } else { - DefIdForest::union( - tcx, - self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)), - ) + // Non-exhaustive variants from other crates are always considered inhabited. + return InhabitedPredicate::True; } - } -} - -impl<'tcx> FieldDef { - /// Calculates the forest of `DefId`s from which this field is visibly uninhabited. - fn uninhabited_from( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - is_enum: bool, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); - // FIXME(canndrew): Currently enum fields are (incorrectly) stored with - // `Visibility::Invisible` so we need to override `self.vis` if we're - // dealing with an enum. - if is_enum { - data_uninhabitedness() - } else { - match self.vis { - Visibility::Invisible => DefIdForest::empty(), - Visibility::Restricted(from) => { - let forest = DefIdForest::from_id(from); - let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); - DefIdForest::intersection(tcx, iter) + InhabitedPredicate::all( + tcx, + self.fields.iter().map(|field| { + let pred = tcx.type_of(field.did).inhabited_predicate(tcx); + if adt.is_enum() { + return pred; } - Visibility::Public => data_uninhabitedness(), - } - } + match field.vis { + Visibility::Public => pred, + Visibility::Restricted(from) => { + pred.or(tcx, InhabitedPredicate::NotInModule(from)) + } + } + }), + ) } } impl<'tcx> Ty<'tcx> { - /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from( - self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - tcx.type_uninhabited_from(param_env.and(self)) + pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> { + match self.kind() { + // For now, union`s are always considered inhabited + Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, + // Non-exhaustive ADTs from other crates are always considered inhabited + Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { + InhabitedPredicate::True + } + Never => InhabitedPredicate::False, + Param(_) | Projection(_) => InhabitedPredicate::GenericType(self), + Tuple(tys) if tys.is_empty() => InhabitedPredicate::True, + // use a query for more complex cases + Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self), + // references and other types are inhabited + _ => InhabitedPredicate::True, + } } } -// Query provider for `type_uninhabited_from`. -pub(crate) fn type_uninhabited_from<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> DefIdForest<'tcx> { - let ty = key.value; - let param_env = key.param_env; +/// N.B. this query should only be called through `Ty::inhabited_predicate` +fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> { match *ty.kind() { - Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), + Adt(adt, substs) => tcx.inhabited_predicate_adt(adt.did()).subst(tcx, substs), - Never => DefIdForest::full(), - - Tuple(ref tys) => { - DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env))) + Tuple(tys) => { + InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx))) } - Array(ty, len) => match len.try_eval_usize(tcx, param_env) { - Some(0) | None => DefIdForest::empty(), - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(1..) => ty.uninhabited_from(tcx, param_env), + // If we can evaluate the array length before having a `ParamEnv`, then + // we can simplify the predicate. This is an optimization. + Array(ty, len) => match len.kind().try_to_machine_usize(tcx) { + Some(0) => InhabitedPredicate::True, + Some(1..) => ty.inhabited_predicate(tcx), + None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)), }, - // References to uninitialised memory are valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - // The precise semantics of inhabitedness with respect to references is currently - // undecided. - Ref(..) => DefIdForest::empty(), - - _ => DefIdForest::empty(), + _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"), } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 53218225d..6c1414f7b 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,9 +1,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{ - self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable, -}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable}; +use crate::ty::{EarlyBinder, InternalSubsts, SubstsRef}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; @@ -20,14 +18,14 @@ use std::fmt; /// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval /// will do all required substitution as they run. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, Lift)] +#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct Instance<'tcx> { pub def: InstanceDef<'tcx>, pub substs: SubstsRef<'tcx>, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum InstanceDef<'tcx> { /// A user-defined callable item. /// diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ad78d24e9..3312f44c6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,38 +1,23 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::subst::Subst; -use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable}; +use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitable}; use rustc_ast as ast; use rustc_attr as attr; +use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo}; -use rustc_span::symbol::Symbol; +use rustc_index::vec::Idx; +use rustc_session::config::OptLevel; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, -}; +use rustc_target::abi::call::FnAbi; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; -use std::cmp; +use std::cmp::{self}; use std::fmt; -use std::iter; use std::num::NonZeroUsize; use std::ops::Bound; -use rand::{seq::SliceRandom, SeedableRng}; -use rand_xoshiro::Xoshiro128StarStar; - -pub fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; -} - pub trait IntegerExt { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer; @@ -204,6 +189,31 @@ pub enum LayoutError<'tcx> { NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), } +impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> { + let mut diag = handler.struct_fatal(""); + + match self { + LayoutError::Unknown(ty) => { + diag.set_arg("ty", ty); + diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout); + } + LayoutError::SizeOverflow(ty) => { + diag.set_arg("ty", ty); + diag.set_primary_message(rustc_errors::fluent::middle_values_too_big); + } + LayoutError::NormalizationFailure(ty, e) => { + diag.set_arg("ty", ty); + diag.set_arg("failure_ty", e.get_type_for_failure()); + diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized); + } + } + diag + } +} + +// FIXME: Once the other errors that embed this error have been converted to translateable +// diagnostics, this Display impl should be removed. impl<'tcx> fmt::Display for LayoutError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -221,1842 +231,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -/// Enforce some basic invariants on layouts. -fn sanity_check_layout<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - layout: &TyAndLayout<'tcx>, -) { - // Type-level uninhabitedness should always imply ABI uninhabitedness. - if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) { - assert!(layout.abi.is_uninhabited()); - } - - if layout.size.bytes() % layout.align.abi.bytes() != 0 { - bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); - } - - if cfg!(debug_assertions) { - fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) { - match layout.abi() { - Abi::Scalar(scalar) => { - // No padding in scalars. - assert_eq!( - layout.align().abi, - scalar.align(&tcx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.size(), - scalar.size(&tcx), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::Vector { count, element } => { - // No padding in vectors. Alignment can be strengthened, though. - assert!( - layout.align().abi >= element.align(&tcx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - let size = element.size(&tcx) * count; - assert_eq!( - layout.size(), - size.align_to(tcx.data_layout().vector_align(size).abi), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::ScalarPair(scalar1, scalar2) => { - // Sanity-check scalar pairs. These are a bit more flexible and support - // padding, but we can at least ensure both fields actually fit into the layout - // and the alignment requirement has not been weakened. - let align1 = scalar1.align(&tcx).abi; - let align2 = scalar2.align(&tcx).abi; - assert!( - layout.align().abi >= cmp::max(align1, align2), - "alignment mismatch between ABI and layout in {layout:#?}", - ); - let field2_offset = scalar1.size(&tcx).align_to(align2); - assert!( - layout.size() >= field2_offset + scalar2.size(&tcx), - "size mismatch between ABI and layout in {layout:#?}" - ); - } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. - } - } - - check_layout_abi(tcx, layout.layout); - - if let Variants::Multiple { variants, .. } = &layout.variants { - for variant in variants { - check_layout_abi(tcx, *variant); - // No nested "multiple". - assert!(matches!(variant.variants(), Variants::Single { .. })); - // Skip empty variants. - if variant.size() == Size::ZERO - || variant.fields().count() == 0 - || variant.abi().is_uninhabited() - { - // These are never actually accessed anyway, so we can skip them. (Note that - // sometimes, variants with fields have size 0, and sometimes, variants without - // fields have non-0 size.) - continue; - } - // Variants should have the same or a smaller size as the full thing. - if variant.size() > layout.size { - bug!( - "Type with size {} bytes has variant with size {} bytes: {layout:#?}", - layout.size.bytes(), - variant.size().bytes(), - ) - } - // The top-level ABI and the ABI of the variants should be coherent. - let abi_coherent = match (layout.abi, variant.abi()) { - (Abi::Scalar(..), Abi::Scalar(..)) => true, - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, - (Abi::Uninhabited, _) => true, - (Abi::Aggregate { .. }, _) => true, - _ => false, - }; - if !abi_coherent { - bug!( - "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}", - variant - ); - } - } - } - } -} - -#[instrument(skip(tcx, query), level = "debug")] -fn layout_of<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> { - ty::tls::with_related_context(tcx, move |icx| { - let (param_env, ty) = query.into_parts(); - debug!(?ty); - - if !tcx.recursion_limit().value_within_limit(icx.layout_depth) { - tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); - } - - // Update the ImplicitCtxt to increase the layout_depth - let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| { - let param_env = param_env.with_reveal_all_normalized(tcx); - let unnormalized_ty = ty; - - // FIXME: We might want to have two different versions of `layout_of`: - // One that can be called after typecheck has completed and can use - // `normalize_erasing_regions` here and another one that can be called - // before typecheck has completed and uses `try_normalize_erasing_regions`. - let ty = match tcx.try_normalize_erasing_regions(param_env, ty) { - Ok(t) => t, - Err(normalization_error) => { - return Err(LayoutError::NormalizationFailure(ty, normalization_error)); - } - }; - - if ty != unnormalized_ty { - // Ensure this layout is also cached for the normalized type. - return tcx.layout_of(param_env.and(ty)); - } - - let cx = LayoutCx { tcx, param_env }; - - let layout = cx.layout_of_uncached(ty)?; - let layout = TyAndLayout { ty, layout }; - - cx.record_layout_for_printing(layout); - - sanity_check_layout(tcx, param_env, &layout); - - Ok(layout) - }) - }) -} - +#[derive(Clone, Copy)] pub struct LayoutCx<'tcx, C> { pub tcx: C, pub param_env: ty::ParamEnv<'tcx>, } -#[derive(Copy, Clone, Debug)] -enum StructKind { - /// A tuple, closure, or univariant which cannot be coerced to unsized. - AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. - MaybeUnsized, - /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag). - Prefixed(Size, Align), -} - -// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. -// This is used to go between `memory_index` (source field order to memory order) -// and `inverse_memory_index` (memory order to source field order). -// See also `FieldsShape::Arbitrary::memory_index` for more details. -// FIXME(eddyb) build a better abstraction for permutations, if possible. -fn invert_mapping(map: &[u32]) -> Vec<u32> { - let mut inverse = vec![0; map.len()]; - for i in 0..map.len() { - inverse[map[i] as usize] = i as u32; - } - inverse -} - -impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> { - let dl = self.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); - - // HACK(nox): We iter on `b` and then `a` because `max_by_key` - // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b) - .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a)) - .max_by_key(|niche| niche.available(dl)); - - LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Arbitrary { - offsets: vec![Size::ZERO, b_offset], - memory_index: vec![0, 1], - }, - abi: Abi::ScalarPair(a, b), - largest_niche, - align, - size, - } - } - - fn univariant_uninterned( - &self, - ty: Ty<'tcx>, - fields: &[TyAndLayout<'_>], - repr: &ReprOptions, - kind: StructKind, - ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> { - let dl = self.data_layout(); - let pack = repr.pack; - if pack.is_some() && repr.align.is_some() { - self.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned"); - return Err(LayoutError::Unknown(ty)); - } - - let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - - let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); - - let optimize = !repr.inhibit_struct_field_reordering_opt(); - if optimize { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index[..end]; - let field_align = |f: &TyAndLayout<'_>| { - if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } - }; - - // If `-Z randomize-layout` was enabled for the type definition we can shuffle - // the field ordering to try and catch some code making assumptions about layouts - // we don't guarantee - if repr.can_randomize_type_layout() { - // `ReprOptions.layout_seed` is a deterministic seed that we can use to - // randomize field ordering with - let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); - - // Shuffle the ordering of the fields - optimizing.shuffle(&mut rng); - - // Otherwise we just leave things alone and actually optimize the type's fields - } else { - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - optimizing.sort_by_key(|&x| { - // Place ZSTs first to avoid "interesting offsets", - // especially with only one or two non-ZST fields. - let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(field_align(f))) - }); - } - - StructKind::Prefixed(..) => { - // Sort in ascending alignment so that the layout stays optimal - // regardless of the prefix - optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); - } - } - - // FIXME(Kixiron): We can always shuffle fields within a given alignment class - // regardless of the status of `-Z randomize-layout` - } - } - - // inverse_memory_index holds field indices by increasing memory offset. - // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5. - // We now write field offsets to the corresponding offset slot; - // field 5 with offset 0 puts 0 in offsets[5]. - // At the bottom of this function, we invert `inverse_memory_index` to - // produce `memory_index` (see `invert_mapping`). - - let mut sized = true; - let mut offsets = vec![Size::ZERO; fields.len()]; - let mut offset = Size::ZERO; - let mut largest_niche = None; - let mut largest_niche_available = 0; - - if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = - if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAndPrefAlign::new(prefix_align)); - offset = prefix_size.align_to(prefix_align); - } - - for &i in &inverse_memory_index { - let field = fields[i as usize]; - if !sized { - self.tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "univariant: field #{} of `{}` comes after unsized field", - offsets.len(), - ty - ), - ); - } - - if field.is_unsized() { - sized = false; - } - - // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let field_align = if let Some(pack) = pack { - field.align.min(AbiAndPrefAlign::new(pack)) - } else { - field.align - }; - offset = offset.align_to(field_align.abi); - align = align.max(field_align); - - debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[i as usize] = offset; - - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } - } - - offset = offset.checked_add(field.size, dl).ok_or(LayoutError::SizeOverflow(ty))?; - } - - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - - debug!("univariant min_size: {:?}", offset); - let min_size = offset; - - // As stated above, inverse_memory_index holds field indices by increasing offset. - // This makes it an already-sorted view of the offsets vec. - // To invert it, consider: - // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. - // Field 5 would be the first element, so memory_index is i: - // Note: if we didn't optimize, it's already right. - - let memory_index = - if optimize { invert_mapping(&inverse_memory_index) } else { inverse_memory_index }; - - let size = min_size.align_to(align.abi); - let mut abi = Abi::Aggregate { sized }; - - // Unpack newtype ABIs and find scalar pairs. - if sized && size.bytes() > 0 { - // All other fields must be ZSTs. - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); - - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size - { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi; - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; - } - _ => {} - } - } - } - - // Two non-ZST fields, and they're both scalars. - (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = self.scalar_pair(a, b); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - _ => {} - } - } - - _ => {} - } - } - - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } - - Ok(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, - largest_niche, - align, - size, - }) - } - - fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> { - let tcx = self.tcx; - let param_env = self.param_env; - let dl = self.data_layout(); - let scalar_unit = |value: Primitive| { - let size = value.size(dl); - assert!(size.bits() <= 128); - Scalar::Initialized { value, valid_range: WrappingRange::full(size) } - }; - let scalar = - |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value))); - - let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| { - Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?)) - }; - debug_assert!(!ty.has_infer_types_or_consts()); - - Ok(match *ty.kind() { - // Basic scalars. - ty::Bool => tcx.intern_layout(LayoutS::scalar( - self, - Scalar::Initialized { - value: Int(I8, false), - valid_range: WrappingRange { start: 0, end: 1 }, - }, - )), - ty::Char => tcx.intern_layout(LayoutS::scalar( - self, - Scalar::Initialized { - value: Int(I32, false), - valid_range: WrappingRange { start: 0, end: 0x10FFFF }, - }, - )), - ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)), - ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)), - ty::Float(fty) => scalar(match fty { - ty::FloatTy::F32 => F32, - ty::FloatTy::F64 => F64, - }), - ty::FnPtr(_) => { - let mut ptr = scalar_unit(Pointer); - ptr.valid_range_mut().start = 1; - tcx.intern_layout(LayoutS::scalar(self, ptr)) - } - - // The never type. - ty::Never => tcx.intern_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }), - - // Potentially-wide pointers. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let mut data_ptr = scalar_unit(Pointer); - if !ty.is_unsafe_ptr() { - data_ptr.valid_range_mut().start = 1; - } - - let pointee = tcx.normalize_erasing_regions(param_env, pointee); - if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { - return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr))); - } - - let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = match unsized_part.kind() { - ty::Foreign(..) => { - return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr))); - } - ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), - ty::Dynamic(..) => { - let mut vtable = scalar_unit(Pointer); - vtable.valid_range_mut().start = 1; - vtable - } - _ => return Err(LayoutError::Unknown(unsized_part)), - }; - - // Effectively a (ptr, meta) tuple. - tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) - } - - // Arrays and slices. - ty::Array(element, mut count) => { - if count.has_projections() { - count = tcx.normalize_erasing_regions(param_env, count); - if count.has_projections() { - return Err(LayoutError::Unknown(ty)); - } - } - - let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?; - let element = self.layout_of(element)?; - let size = - element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; - - let abi = - if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; - - let largest_niche = if count != 0 { element.largest_niche } else { None }; - - tcx.intern_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Array { stride: element.size, count }, - abi, - largest_niche, - align: element.align, - size, - }) - } - ty::Slice(element) => { - let element = self.layout_of(element)?; - tcx.intern_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Array { stride: element.size, count: 0 }, - abi: Abi::Aggregate { sized: false }, - largest_niche: None, - align: element.align, - size: Size::ZERO, - }) - } - ty::Str => tcx.intern_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }), - - // Odd unit types. - ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(..) | ty::Foreign(..) => { - let mut unit = self.univariant_uninterned( - ty, - &[], - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; - match unit.abi { - Abi::Aggregate { ref mut sized } => *sized = false, - _ => bug!(), - } - tcx.intern_layout(unit) - } - - ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?, - - ty::Closure(_, ref substs) => { - let tys = substs.as_closure().upvar_tys(); - univariant( - &tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - StructKind::AlwaysSized, - )? - } - - ty::Tuple(tys) => { - let kind = - if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - - univariant( - &tys.iter().map(|k| self.layout_of(k)).collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - kind, - )? - } - - // SIMD vector types. - ty::Adt(def, substs) if def.repr().simd() => { - if !def.is_struct() { - // Should have yielded E0517 by now. - tcx.sess.delay_span_bug( - DUMMY_SP, - "#[repr(simd)] was applied to an ADT that is not a struct", - ); - return Err(LayoutError::Unknown(ty)); - } - - // Supported SIMD vectors are homogeneous ADTs with at least one field: - // - // * #[repr(simd)] struct S(T, T, T, T); - // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } - // * #[repr(simd)] struct S([T; 4]) - // - // where T is a primitive scalar (integer/float/pointer). - - // SIMD vectors with zero fields are not supported. - // (should be caught by typeck) - if def.non_enum_variant().fields.is_empty() { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); - } - - // Type of the first ADT field: - let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs); - - // Heterogeneous SIMD vectors are not supported: - // (should be caught by typeck) - for fi in &def.non_enum_variant().fields { - if fi.ty(tcx, substs) != f0_ty { - tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty)); - } - } - - // The element type and number of elements of the SIMD vector - // are obtained from: - // - // * the element type and length of the single array field, if - // the first field is of array type, or - // - // * the homogenous field type and the number of fields. - let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { - // First ADT field is an array: - - // SIMD vectors with multiple array fields are not supported: - // (should be caught by typeck) - if def.non_enum_variant().fields.len() != 1 { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with more than one array field", - ty - )); - } - - // Extract the number of elements from the layout of the array field: - let FieldsShape::Array { count, .. } = self.layout_of(f0_ty)?.layout.fields() else { - return Err(LayoutError::Unknown(ty)); - }; - - (*e_ty, *count, true) - } else { - // First ADT field is not an array: - (f0_ty, def.non_enum_variant().fields.len() as _, false) - }; - - // SIMD vectors of zero length are not supported. - // Additionally, lengths are capped at 2^16 as a fixed maximum backends must - // support. - // - // Can't be caught in typeck if the array length is generic. - if e_len == 0 { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); - } else if e_len > MAX_SIMD_LANES { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` of length greater than {}", - ty, MAX_SIMD_LANES, - )); - } - - // Compute the ABI of the element type: - let e_ly = self.layout_of(e_ty)?; - let Abi::Scalar(e_abi) = e_ly.abi else { - // This error isn't caught in typeck, e.g., if - // the element type of the vector is generic. - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with a non-primitive-scalar \ - (integer/float/pointer) element type `{}`", - ty, e_ty - )) - }; - - // Compute the size and alignment of the vector: - let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?; - let align = dl.vector_align(size); - let size = size.align_to(align.abi); - - // Compute the placement of the vector fields: - let fields = if is_array { - FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] } - } else { - FieldsShape::Array { stride: e_ly.size, count: e_len } - }; - - tcx.intern_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields, - abi: Abi::Vector { element: e_abi, count: e_len }, - largest_niche: e_ly.largest_niche, - size, - align, - }) - } - - // ADTs. - ty::Adt(def, substs) => { - // Cache the field layouts. - let variants = def - .variants() - .iter() - .map(|v| { - v.fields - .iter() - .map(|field| self.layout_of(field.ty(tcx, substs))) - .collect::<Result<Vec<_>, _>>() - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - if def.is_union() { - if def.repr().pack.is_some() && def.repr().align.is_some() { - self.tcx.sess.delay_span_bug( - tcx.def_span(def.did()), - "union cannot be packed and aligned", - ); - return Err(LayoutError::Unknown(ty)); - } - - let mut align = - if def.repr().pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - - if let Some(repr_align) = def.repr().align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - - let optimize = !def.repr().inhibit_union_abi_opt(); - let mut size = Size::ZERO; - let mut abi = Abi::Aggregate { sized: true }; - let index = VariantIdx::new(0); - for field in &variants[index] { - assert!(!field.is_unsized()); - align = align.max(field.align); - - // If all non-ZST fields have the same ABI, forward this ABI - if optimize && !field.is_zst() { - // Discard valid range information and allow undef - let field_abi = match field.abi { - Abi::Scalar(x) => Abi::Scalar(x.to_union()), - Abi::ScalarPair(x, y) => { - Abi::ScalarPair(x.to_union(), y.to_union()) - } - Abi::Vector { element: x, count } => { - Abi::Vector { element: x.to_union(), count } - } - Abi::Uninhabited | Abi::Aggregate { .. } => { - Abi::Aggregate { sized: true } - } - }; - - if size == Size::ZERO { - // first non ZST: initialize 'abi' - abi = field_abi; - } else if abi != field_abi { - // different fields have different ABI: reset to Aggregate - abi = Abi::Aggregate { sized: true }; - } - } - - size = cmp::max(size, field.size); - } - - if let Some(pack) = def.repr().pack { - align = align.min(AbiAndPrefAlign::new(pack)); - } - - return Ok(tcx.intern_layout(LayoutS { - variants: Variants::Single { index }, - fields: FieldsShape::Union( - NonZeroUsize::new(variants[index].len()) - .ok_or(LayoutError::Unknown(ty))?, - ), - abi, - largest_niche: None, - align, - size: size.align_to(align.abi), - })); - } - - // A variant is absent if it's uninhabited and only has ZST fields. - // Present uninhabited variants only require space for their fields, - // but *not* an encoding of the discriminant (e.g., a tag value). - // See issue #49298 for more details on the need to leave space - // for non-ZST uninhabited data (mostly partial initialization). - let absent = |fields: &[TyAndLayout<'_>]| { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); - let is_zst = fields.iter().all(|f| f.is_zst()); - uninhabited && is_zst - }; - let (present_first, present_second) = { - let mut present_variants = variants - .iter_enumerated() - .filter_map(|(i, v)| if absent(v) { None } else { Some(i) }); - (present_variants.next(), present_variants.next()) - }; - let present_first = match present_first { - Some(present_first) => present_first, - // Uninhabited because it has no variants, or only absent ones. - None if def.is_enum() => { - return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout); - } - // If it's a struct, still compute a layout so that we can still compute the - // field offsets. - None => VariantIdx::new(0), - }; - - let is_struct = !def.is_enum() || - // Only one variant is present. - (present_second.is_none() && - // Representation optimizations are allowed. - !def.repr().inhibit_enum_layout_opt()); - if is_struct { - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - - let v = present_first; - let kind = if def.is_enum() || variants[v].is_empty() { - StructKind::AlwaysSized - } else { - let param_env = tcx.param_env(def.did()); - let last_field = def.variant(v).fields.last().unwrap(); - let always_sized = - tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env); - if !always_sized { - StructKind::MaybeUnsized - } else { - StructKind::AlwaysSized - } - }; - - let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?; - st.variants = Variants::Single { index: v }; - - if def.is_unsafe_cell() { - let hide_niches = |scalar: &mut _| match scalar { - Scalar::Initialized { value, valid_range } => { - *valid_range = WrappingRange::full(value.size(dl)) - } - // Already doesn't have any niches - Scalar::Union { .. } => {} - }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { - hide_niches(a); - hide_niches(b); - } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} - } - st.largest_niche = None; - return Ok(tcx.intern_layout(st)); - } - - let (start, end) = self.tcx.layout_scalar_valid_range(def.did()); - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - // the asserts ensure that we are not using the - // `#[rustc_layout_scalar_valid_range(n)]` - // attribute to widen the range of anything as that would probably - // result in UB somewhere - // FIXME(eddyb) the asserts are probably not needed, - // as larger validity ranges would result in missed - // optimizations, *not* wrongly assuming the inner - // value is valid. e.g. unions enlarge validity ranges, - // because the values may be uninitialized. - if let Bound::Included(start) = start { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - let valid_range = scalar.valid_range_mut(); - assert!(valid_range.start <= start); - valid_range.start = start; - } - if let Bound::Included(end) = end { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - let valid_range = scalar.valid_range_mut(); - assert!(valid_range.end >= end); - valid_range.end = end; - } - - // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); - } - } - None => st.largest_niche = Some(niche), - } - } - } - _ => assert!( - start == Bound::Unbounded && end == Bound::Unbounded, - "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}", - def, - st, - ), - } - - return Ok(tcx.intern_layout(st)); - } - - // At this point, we have handled all unions and - // structs. (We have also handled univariant enums - // that allow representation optimization.) - assert!(def.is_enum()); - - // The current code for niche-filling relies on variant indices - // instead of actual discriminants, so dataful enums with - // explicit discriminants (RFC #2363) would misbehave. - let no_explicit_discriminants = def - .variants() - .iter_enumerated() - .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32())); - - let mut niche_filling_layout = None; - - // Niche-filling enum optimization. - if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants { - let mut dataful_variant = None; - let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); - - // Find one non-ZST variant. - 'variants: for (v, fields) in variants.iter_enumerated() { - if absent(fields) { - continue 'variants; - } - for f in fields { - if !f.is_zst() { - if dataful_variant.is_none() { - dataful_variant = Some(v); - continue 'variants; - } else { - dataful_variant = None; - break 'variants; - } - } - } - niche_variants = *niche_variants.start().min(&v)..=v; - } - - if niche_variants.start() > niche_variants.end() { - dataful_variant = None; - } - - if let Some(i) = dataful_variant { - let count = (niche_variants.end().as_u32() - - niche_variants.start().as_u32() - + 1) as u128; - - // Find the field with the largest niche - let niche_candidate = variants[i] - .iter() - .enumerate() - .filter_map(|(j, field)| Some((j, field.largest_niche?))) - .max_by_key(|(_, niche)| niche.available(dl)); - - if let Some((field_index, niche, (niche_start, niche_scalar))) = - niche_candidate.and_then(|(field_index, niche)| { - Some((field_index, niche, niche.reserve(self, count)?)) - }) - { - let mut align = dl.aggregate_align; - let st = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = self.univariant_uninterned( - ty, - v, - &def.repr(), - StructKind::AlwaysSized, - )?; - st.variants = Variants::Single { index: j }; - - align = align.max(st.align); - - Ok(tcx.intern_layout(st)) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - let offset = st[i].fields().offset(field_index) + niche.offset; - - // Align the total size to the largest alignment. - let size = st[i].size().align_to(align.abi); - - let abi = if st.iter().all(|v| v.abi().is_uninhabited()) { - Abi::Uninhabited - } else if align == st[i].align() && size == st[i].size() { - // When the total alignment and size match, we can use the - // same ABI as the scalar variant with the reserved niche. - match st[i].abi() { - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { - // Only the niche is guaranteed to be initialised, - // so use union layout for the other primitive. - if offset.bytes() == 0 { - Abi::ScalarPair(niche_scalar, second.to_union()) - } else { - Abi::ScalarPair(first.to_union(), niche_scalar) - } - } - _ => Abi::Aggregate { sized: true }, - } - } else { - Abi::Aggregate { sized: true } - }; - - let largest_niche = Niche::from_scalar(dl, offset, niche_scalar); - - niche_filling_layout = Some(LayoutS { - variants: Variants::Multiple { - tag: niche_scalar, - tag_encoding: TagEncoding::Niche { - dataful_variant: i, - niche_variants, - niche_start, - }, - tag_field: 0, - variants: st, - }, - fields: FieldsShape::Arbitrary { - offsets: vec![offset], - memory_index: vec![0], - }, - abi, - largest_niche, - size, - align, - }); - } - } - } - - let (mut min, mut max) = (i128::MAX, i128::MIN); - let discr_type = def.repr().discr_type(); - let bits = Integer::from_attr(self, discr_type).size().bits(); - for (i, discr) in def.discriminants(tcx) { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { - continue; - } - let mut x = discr.val as i128; - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - x = (x << (128 - bits)) >> (128 - bits); - } - if x < min { - min = x; - } - if x > max { - max = x; - } - } - // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::MAX, i128::MIN) { - min = 0; - max = 0; - } - assert!(min <= max, "discriminant range is {}...{}", min, max); - let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr(), min, max); - - let mut align = dl.aggregate_align; - let mut size = Size::ZERO; - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256).unwrap(); - assert_eq!(Integer::for_align(dl, start_align), None); - - // repr(C) on an enum tells us to make a (tag, union) layout, - // so we need to grow the prefix alignment to be at least - // the alignment of the union. (This value is used both for - // determining the alignment of the overall enum, and the - // determining the alignment of the payload after the tag.) - let mut prefix_align = min_ity.align(dl).abi; - if def.repr().c() { - for fields in &variants { - for field in fields { - prefix_align = prefix_align.max(field.align.abi); - } - } - } - - // Create the set of structs that represent each variant. - let mut layout_variants = variants - .iter_enumerated() - .map(|(i, field_layouts)| { - let mut st = self.univariant_uninterned( - ty, - &field_layouts, - &def.repr(), - StructKind::Prefixed(min_ity.size(), prefix_align), - )?; - st.variants = Variants::Single { index: i }; - // Find the first field we can't move later - // to make room for a larger discriminant. - for field in - st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) - { - if !field.is_zst() || field.align.abi.bytes() != 1 { - start_align = start_align.min(field.align.abi); - break; - } - } - size = cmp::max(size, st.size); - align = align.max(st.align); - Ok(st) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); - } - - let typeck_ity = Integer::from_attr(dl, def.repr().discr_type()); - if typeck_ity < min_ity { - // It is a bug if Layout decided on a greater discriminant size than typeck for - // some reason at this point (based on values discriminant can take on). Mostly - // because this discriminant will be loaded, and then stored into variable of - // type calculated by typeck. Consider such case (a bug): typeck decided on - // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in codegen, in order - // to store this 16-bit discriminant into 8-bit sized temporary some of the - // space necessary to represent would have to be discarded (or layout is wrong - // on thinking it needs 16 bits) - bug!( - "layout decided on a larger discriminant type ({:?}) than typeck ({:?})", - min_ity, - typeck_ity - ); - // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in codegen. - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about its contents and - // won't be so conservative. - - // Use the initial field alignment - let mut ity = if def.repr().c() || def.repr().int.is_some() { - min_ity - } else { - Integer::for_align(dl, start_align).unwrap_or(min_ity) - }; - - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = min_ity.size(); - let new_ity_size = ity.size(); - for variant in &mut layout_variants { - match variant.fields { - FieldsShape::Arbitrary { ref mut offsets, .. } => { - for i in offsets { - if *i <= old_ity_size { - assert_eq!(*i, old_ity_size); - *i = new_ity_size; - } - } - // We might be making the struct larger. - if variant.size <= old_ity_size { - variant.size = new_ity_size; - } - } - _ => bug!(), - } - } - } - - let tag_mask = ity.size().unsigned_int_max(); - let tag = Scalar::Initialized { - value: Int(ity, signed), - valid_range: WrappingRange { - start: (min as u128 & tag_mask), - end: (max as u128 & tag_mask), - }, - }; - let mut abi = Abi::Aggregate { sized: true }; - - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; - } else if tag.size(dl) == size { - // Make sure we only use scalar layout when the enum is entirely its - // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); - } else { - // Try to use a ScalarPair for all tagged enums. - let mut common_prim = None; - let mut common_prim_initialized_in_all_variants = true; - for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) { - let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { - bug!(); - }; - let mut fields = - iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); - let (field, offset) = match (fields.next(), fields.next()) { - (None, None) => { - common_prim_initialized_in_all_variants = false; - continue; - } - (Some(pair), None) => pair, - _ => { - common_prim = None; - break; - } - }; - let prim = match field.abi { - Abi::Scalar(scalar) => { - common_prim_initialized_in_all_variants &= - matches!(scalar, Scalar::Initialized { .. }); - scalar.primitive() - } - _ => { - common_prim = None; - break; - } - }; - if let Some(pair) = common_prim { - // This is pretty conservative. We could go fancier - // by conflating things like i32 and u32, or even - // realising that (u8, u8) could just cohabit with - // u16 or even u32. - if pair != (prim, offset) { - common_prim = None; - break; - } - } else { - common_prim = Some((prim, offset)); - } - } - if let Some((prim, offset)) = common_prim { - let prim_scalar = if common_prim_initialized_in_all_variants { - scalar_unit(prim) - } else { - // Common prim might be uninit. - Scalar::Union { value: prim } - }; - let pair = self.scalar_pair(tag, prim_scalar); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if pair_offsets[0] == Size::ZERO - && pair_offsets[1] == *offset - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - } - - // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the - // variants to ensure they are consistent. This is because a downcast is - // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - for variant in &mut layout_variants { - // We only do this for variants with fields; the others are not accessed anyway. - // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 - && matches!(variant.abi, Abi::Aggregate { .. }) - { - variant.abi = abi; - // Also need to bump up the size and alignment, so that the entire value fits in here. - variant.size = cmp::max(variant.size, size); - variant.align.abi = cmp::max(variant.align.abi, align.abi); - } - } - } - - let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - - let layout_variants = - layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect(); - - let tagged_layout = LayoutS { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: 0, - variants: layout_variants, - }, - fields: FieldsShape::Arbitrary { - offsets: vec![Size::ZERO], - memory_index: vec![0], - }, - largest_niche, - abi, - align, - size, - }; - - let best_layout = match (tagged_layout, niche_filling_layout) { - (tagged_layout, Some(niche_filling_layout)) => { - // Pick the smaller layout; otherwise, - // pick the layout with the larger niche; otherwise, - // pick tagged as it has simpler codegen. - cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| { - let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl)); - (layout.size, cmp::Reverse(niche_size)) - }) - } - (tagged_layout, None) => tagged_layout, - }; - - tcx.intern_layout(best_layout) - } - - // Types with no meaningful known layout. - ty::Projection(_) | ty::Opaque(..) => { - // NOTE(eddyb) `layout_of` query should've normalized these away, - // if that was possible, so there's no reason to try again here. - return Err(LayoutError::Unknown(ty)); - } - - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { - bug!("Layout::compute: unexpected type `{}`", ty) - } - - ty::Bound(..) | ty::Param(_) | ty::Error(_) => { - return Err(LayoutError::Unknown(ty)); - } - }) - } -} - -/// Overlap eligibility and variant assignment for each GeneratorSavedLocal. -#[derive(Clone, Debug, PartialEq)] -enum SavedLocalEligibility { - Unassigned, - Assigned(VariantIdx), - // FIXME: Use newtype_index so we aren't wasting bytes - Ineligible(Option<u32>), -} - -// When laying out generators, we divide our saved local fields into two -// categories: overlap-eligible and overlap-ineligible. -// -// Those fields which are ineligible for overlap go in a "prefix" at the -// beginning of the layout, and always have space reserved for them. -// -// Overlap-eligible fields are only assigned to one variant, so we lay -// those fields out for each variant and put them right after the -// prefix. -// -// Finally, in the layout details, we point to the fields from the -// variants they are assigned to. It is possible for some fields to be -// included in multiple variants. No field ever "moves around" in the -// layout; its offset is always the same. -// -// Also included in the layout are the upvars and the discriminant. -// These are included as fields on the "outer" layout; they are not part -// of any variant. -impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - /// Compute the eligibility and assignment of each local. - fn generator_saved_local_eligibility( - &self, - info: &GeneratorLayout<'tcx>, - ) -> (BitSet<GeneratorSavedLocal>, IndexVec<GeneratorSavedLocal, SavedLocalEligibility>) { - use SavedLocalEligibility::*; - - let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> = - IndexVec::from_elem_n(Unassigned, info.field_tys.len()); - - // The saved locals not eligible for overlap. These will get - // "promoted" to the prefix of our generator. - let mut ineligible_locals = BitSet::new_empty(info.field_tys.len()); - - // Figure out which of our saved locals are fields in only - // one variant. The rest are deemed ineligible for overlap. - for (variant_index, fields) in info.variant_fields.iter_enumerated() { - for local in fields { - match assignments[*local] { - Unassigned => { - assignments[*local] = Assigned(variant_index); - } - Assigned(idx) => { - // We've already seen this local at another suspension - // point, so it is no longer a candidate. - trace!( - "removing local {:?} in >1 variant ({:?}, {:?})", - local, - variant_index, - idx - ); - ineligible_locals.insert(*local); - assignments[*local] = Ineligible(None); - } - Ineligible(_) => {} - } - } - } - - // Next, check every pair of eligible locals to see if they - // conflict. - for local_a in info.storage_conflicts.rows() { - let conflicts_a = info.storage_conflicts.count(local_a); - if ineligible_locals.contains(local_a) { - continue; - } - - for local_b in info.storage_conflicts.iter(local_a) { - // local_a and local_b are storage live at the same time, therefore they - // cannot overlap in the generator layout. The only way to guarantee - // this is if they are in the same variant, or one is ineligible - // (which means it is stored in every variant). - if ineligible_locals.contains(local_b) - || assignments[local_a] == assignments[local_b] - { - continue; - } - - // If they conflict, we will choose one to make ineligible. - // This is not always optimal; it's just a greedy heuristic that - // seems to produce good results most of the time. - let conflicts_b = info.storage_conflicts.count(local_b); - let (remove, other) = - if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; - ineligible_locals.insert(remove); - assignments[remove] = Ineligible(None); - trace!("removing local {:?} due to conflict with {:?}", remove, other); - } - } - - // Count the number of variants in use. If only one of them, then it is - // impossible to overlap any locals in our layout. In this case it's - // always better to make the remaining locals ineligible, so we can - // lay them out with the other locals in the prefix and eliminate - // unnecessary padding bytes. - { - let mut used_variants = BitSet::new_empty(info.variant_fields.len()); - for assignment in &assignments { - if let Assigned(idx) = assignment { - used_variants.insert(*idx); - } - } - if used_variants.count() < 2 { - for assignment in assignments.iter_mut() { - *assignment = Ineligible(None); - } - ineligible_locals.insert_all(); - } - } - - // Write down the order of our locals that will be promoted to the prefix. - { - for (idx, local) in ineligible_locals.iter().enumerate() { - assignments[local] = Ineligible(Some(idx as u32)); - } - } - debug!("generator saved local assignments: {:?}", assignments); - - (ineligible_locals, assignments) - } - - /// Compute the full generator layout. - fn generator_layout( - &self, - ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - substs: SubstsRef<'tcx>, - ) -> Result<Layout<'tcx>, LayoutError<'tcx>> { - use SavedLocalEligibility::*; - let tcx = self.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs); - - let Some(info) = tcx.generator_layout(def_id) else { - return Err(LayoutError::Unknown(ty)); - }; - let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info); - - // Build a prefix layout, including "promoting" all ineligible - // locals as part of the prefix. We compute the layout of all of - // these fields at once to get optimal packing. - let tag_index = substs.as_generator().prefix_tys().count(); - - // `info.variant_fields` already accounts for the reserved variants, so no need to add them. - let max_discr = (info.variant_fields.len() - 1) as u128; - let discr_int = Integer::fit_unsigned(max_discr); - let discr_int_ty = discr_int.to_ty(tcx, false); - let tag = Scalar::Initialized { - value: Primitive::Int(discr_int, false), - valid_range: WrappingRange { start: 0, end: max_discr }, - }; - let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag)); - let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout }; - - let promoted_layouts = ineligible_locals - .iter() - .map(|local| subst_field(info.field_tys[local])) - .map(|ty| tcx.mk_maybe_uninit(ty)) - .map(|ty| self.layout_of(ty)); - let prefix_layouts = substs - .as_generator() - .prefix_tys() - .map(|ty| self.layout_of(ty)) - .chain(iter::once(Ok(tag_layout))) - .chain(promoted_layouts) - .collect::<Result<Vec<_>, _>>()?; - let prefix = self.univariant_uninterned( - ty, - &prefix_layouts, - &ReprOptions::default(), - StructKind::AlwaysSized, - )?; - - let (prefix_size, prefix_align) = (prefix.size, prefix.align); - - // Split the prefix layout into the "outer" fields (upvars and - // discriminant) and the "promoted" fields. Promoted fields will - // get included in each variant that requested them in - // GeneratorLayout. - debug!("prefix = {:#?}", prefix); - let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { - FieldsShape::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = invert_mapping(&memory_index); - - // "a" (`0..b_start`) and "b" (`b_start..`) correspond to - // "outer" and "promoted" fields respectively. - let b_start = (tag_index + 1) as u32; - let offsets_b = offsets.split_off(b_start as usize); - let offsets_a = offsets; - - // Disentangle the "a" and "b" components of `inverse_memory_index` - // by preserving the order but keeping only one disjoint "half" each. - // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: Vec<_> = - inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect(); - inverse_memory_index.retain(|&i| i < b_start); - let inverse_memory_index_a = inverse_memory_index; - - // Since `inverse_memory_index_{a,b}` each only refer to their - // respective fields, they can be safely inverted - let memory_index_a = invert_mapping(&inverse_memory_index_a); - let memory_index_b = invert_mapping(&inverse_memory_index_b); - - let outer_fields = - FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; - (outer_fields, offsets_b, memory_index_b) - } - _ => bug!(), - }; - - let mut size = prefix.size; - let mut align = prefix.align; - let variants = info - .variant_fields - .iter_enumerated() - .map(|(index, variant_fields)| { - // Only include overlap-eligible fields when we compute our variant layout. - let variant_only_tys = variant_fields - .iter() - .filter(|local| match assignments[**local] { - Unassigned => bug!(), - Assigned(v) if v == index => true, - Assigned(_) => bug!("assignment does not match variant"), - Ineligible(_) => false, - }) - .map(|local| subst_field(info.field_tys[*local])); - - let mut variant = self.univariant_uninterned( - ty, - &variant_only_tys - .map(|ty| self.layout_of(ty)) - .collect::<Result<Vec<_>, _>>()?, - &ReprOptions::default(), - StructKind::Prefixed(prefix_size, prefix_align.abi), - )?; - variant.variants = Variants::Single { index }; - - let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { - bug!(); - }; - - // Now, stitch the promoted and variant-only fields back together in - // the order they are mentioned by our GeneratorLayout. - // Because we only use some subset (that can differ between variants) - // of the promoted fields, we can't just pick those elements of the - // `promoted_memory_index` (as we'd end up with gaps). - // So instead, we build an "inverse memory_index", as if all of the - // promoted fields were being used, but leave the elements not in the - // subset as `INVALID_FIELD_IDX`, which we can filter out later to - // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: u32 = !0; - let mut combined_inverse_memory_index = - vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()]; - let mut offsets_and_memory_index = iter::zip(offsets, memory_index); - let combined_offsets = variant_fields - .iter() - .enumerate() - .map(|(i, local)| { - let (offset, memory_index) = match assignments[*local] { - Unassigned => bug!(), - Assigned(_) => { - let (offset, memory_index) = - offsets_and_memory_index.next().unwrap(); - (offset, promoted_memory_index.len() as u32 + memory_index) - } - Ineligible(field_idx) => { - let field_idx = field_idx.unwrap() as usize; - (promoted_offsets[field_idx], promoted_memory_index[field_idx]) - } - }; - combined_inverse_memory_index[memory_index as usize] = i as u32; - offset - }) - .collect(); - - // Remove the unused slots and invert the mapping to obtain the - // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = invert_mapping(&combined_inverse_memory_index); - - variant.fields = FieldsShape::Arbitrary { - offsets: combined_offsets, - memory_index: combined_memory_index, - }; - - size = size.max(variant.size); - align = align.max(variant.align); - Ok(tcx.intern_layout(variant)) - }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; - - size = size.align_to(align.abi); - - let abi = - if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; - - let layout = tcx.intern_layout(LayoutS { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: tag_index, - variants, - }, - fields: outer_fields, - abi, - largest_niche: prefix.largest_niche, - size, - align, - }); - debug!("generator layout ({:?}): {:#?}", ty, layout); - Ok(layout) - } - - /// This is invoked by the `layout_of` query to record the final - /// layout of each type. - #[inline(always)] - fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) { - // If we are running with `-Zprint-type-sizes`, maybe record layouts - // for dumping later. - if self.tcx.sess.opts.unstable_opts.print_type_sizes { - self.record_layout_for_printing_outlined(layout) - } - } - - fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) { - // Ignore layouts that are done with non-empty environments or - // non-monomorphic layouts, as the user only wants to see the stuff - // resulting from the final codegen session. - if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() { - return; - } - - // (delay format until we actually need it) - let record = |kind, packed, opt_discr_size, variants| { - let type_desc = format!("{:?}", layout.ty); - self.tcx.sess.code_stats.record_type_size( - kind, - type_desc, - layout.align.abi, - layout.size, - packed, - opt_discr_size, - variants, - ); - }; - - let adt_def = match *layout.ty.kind() { - ty::Adt(ref adt_def, _) => { - debug!("print-type-size t: `{:?}` process adt", layout.ty); - adt_def - } - - ty::Closure(..) => { - debug!("print-type-size t: `{:?}` record closure", layout.ty); - record(DataTypeKind::Closure, false, None, vec![]); - return; - } - - _ => { - debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty); - return; - } - }; - - let adt_kind = adt_def.adt_kind(); - let adt_packed = adt_def.repr().pack.is_some(); - - let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| { - let mut min_size = Size::ZERO; - let field_info: Vec<_> = flds - .iter() - .enumerate() - .map(|(i, &name)| { - let field_layout = layout.field(self, i); - let offset = layout.fields.offset(i); - let field_end = offset + field_layout.size; - if min_size < field_end { - min_size = field_end; - } - FieldInfo { - name, - offset: offset.bytes(), - size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), - } - }) - .collect(); - - VariantInfo { - name: n, - kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, - align: layout.align.abi.bytes(), - size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, - fields: field_info, - } - }; - - match layout.variants { - Variants::Single { index } => { - if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive { - debug!( - "print-type-size `{:#?}` variant {}", - layout, - adt_def.variant(index).name - ); - let variant_def = &adt_def.variant(index); - let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); - record( - adt_kind.into(), - adt_packed, - None, - vec![build_variant_info(Some(variant_def.name), &fields, layout)], - ); - } else { - // (This case arises for *empty* enums; so give it - // zero variants.) - record(adt_kind.into(), adt_packed, None, vec![]); - } - } - - Variants::Multiple { tag, ref tag_encoding, .. } => { - debug!( - "print-type-size `{:#?}` adt general variants def {}", - layout.ty, - adt_def.variants().len() - ); - let variant_infos: Vec<_> = adt_def - .variants() - .iter_enumerated() - .map(|(i, variant_def)| { - let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); - build_variant_info( - Some(variant_def.name), - &fields, - layout.for_variant(self, i), - ) - }) - .collect(); - record( - adt_kind.into(), - adt_packed, - match tag_encoding { - TagEncoding::Direct => Some(tag.size(self)), - _ => None, - }, - variant_infos, - ); - } - } - } -} - /// Type size "skeleton", i.e., the only information determining a type's size. /// While this is conservative, (aside from constant sizes, only pointers, /// newtypes thereof and null pointer optimized enums are allowed), it is @@ -2083,7 +263,7 @@ impl<'tcx> SizeSkeleton<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> { - debug_assert!(!ty.has_infer_types_or_consts()); + debug_assert!(!ty.has_non_region_infer()); // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { @@ -2099,7 +279,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); match tail.kind() { ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.has_param_types_or_consts()); + debug_assert!(tail.has_non_region_param()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( @@ -2468,7 +648,9 @@ where | ty::FnDef(..) | ty::GeneratorWitness(..) | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this), + | ty::Dynamic(_, _, ty::Dyn) => { + bug!("TyAndLayout::field({:?}): not applicable", this) + } // Potentially-fat pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { @@ -2497,7 +679,7 @@ where match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), - ty::Dynamic(_, _) => { + ty::Dynamic(_, _, ty::Dyn) => { TyMaybeWithLayout::Ty(tcx.mk_imm_ref( tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3), @@ -2566,6 +748,22 @@ where } } + ty::Dynamic(_, _, ty::DynStar) => { + if i == 0 { + TyMaybeWithLayout::Ty(tcx.types.usize) + } else if i == 1 { + // FIXME(dyn-star) same FIXME as above applies here too + TyMaybeWithLayout::Ty( + tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + ), + ) + } else { + bug!("no field {i} on dyn*") + } + } + ty::Projection(_) | ty::Bound(..) | ty::Placeholder(..) @@ -2632,7 +830,7 @@ where } else { match mt { hir::Mutability::Not => { - if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) { + if ty.is_freeze(tcx, cx.param_env()) { PointerKind::Frozen } else { PointerKind::SharedMutable @@ -2643,7 +841,7 @@ where // noalias, as another pointer to the structure can be obtained, that // is not based-on the original reference. We consider all !Unpin // types to be potentially self-referential here. - if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) { + if ty.is_unpin(tcx, cx.param_env()) { PointerKind::UniqueBorrowed } else { PointerKind::UniqueBorrowedPinned @@ -2674,11 +872,11 @@ where // using more niches than just null (e.g., the first page of // the address space, or unaligned pointers). Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, tag_field, .. } if this.fields.offset(tag_field) == offset => { - Some(this.for_variant(cx, dataful_variant)) + Some(this.for_variant(cx, untagged_variant)) } _ => Some(this), }; @@ -2755,111 +953,6 @@ where } } -impl<'tcx> ty::Instance<'tcx> { - // NOTE(eddyb) this is private to avoid using it from outside of - // `fn_abi_of_instance` - any other uses are either too high-level - // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), - // or should go through `FnAbi` instead, to avoid losing any - // adjustments `fn_abi_of_instance` might be performing. - fn fn_sig_for_fn_abi( - &self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> ty::PolyFnSig<'tcx> { - let ty = self.ty(tcx, param_env); - match *ty.kind() { - ty::FnDef(..) => { - // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering - // parameters unused if they show up in the signature, but not in the `mir::Body` - // (i.e. due to being inside a projection that got normalized, see - // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping - // track of a polymorphization `ParamEnv` to allow normalizing later. - let mut sig = match *ty.kind() { - ty::FnDef(def_id, substs) => tcx - .normalize_erasing_regions(tcx.param_env(def_id), tcx.bound_fn_sig(def_id)) - .subst(tcx, substs), - _ => unreachable!(), - }; - - if let ty::InstanceDef::VTableShim(..) = self.def { - // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - sig = sig.map_bound(|mut sig| { - let mut inputs_and_output = sig.inputs_and_output.to_vec(); - inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); - sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - sig - }); - } - sig - } - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(); - - let bound_vars = tcx.mk_bound_variable_kinds( - sig.bound_vars() - .iter() - .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), - ); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BoundRegionKind::BrEnv, - }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); - let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); - - let sig = sig.skip_binder(); - ty::Binder::bind_with_vars( - tcx.mk_fn_sig( - iter::once(env_ty).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ), - bound_vars, - ) - } - ty::Generator(_, substs, _) => { - let sig = substs.as_generator().poly_sig(); - - let bound_vars = tcx.mk_bound_variable_kinds( - sig.bound_vars() - .iter() - .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), - ); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BoundRegionKind::BrEnv, - }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); - let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - - let pin_did = tcx.require_lang_item(LangItem::Pin, None); - let pin_adt_ref = tcx.adt_def(pin_did); - let pin_substs = tcx.intern_substs(&[env_ty.into()]); - let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); - - let sig = sig.skip_binder(); - let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - ty::Binder::bind_with_vars( - tcx.mk_fn_sig( - [env_ty, sig.resume_ty].iter(), - &ret_ty, - false, - hir::Unsafety::Normal, - rustc_target::spec::abi::Abi::Rust, - ), - bound_vars, - ) - } - _ => bug!("unexpected type {:?} in Instance::fn_sig", ty), - } - } -} - /// Calculates whether a function's ABI can unwind or not. /// /// This takes two primary parameters: @@ -2907,6 +1000,7 @@ impl<'tcx> ty::Instance<'tcx> { /// with `-Cpanic=abort` will look like they can't unwind when in fact they /// might (from a foreign exception or similar). #[inline] +#[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool { if let Some(did) = fn_def_id { // Special attribute for functions which can't unwind. @@ -3001,40 +1095,6 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: Spe } } -#[inline] -pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { - use rustc_target::spec::abi::Abi::*; - match tcx.sess.target.adjust_abi(abi) { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, - RustCold => Conv::RustCold, - - // It's the ABI's job to select this, not ours. - System { .. } => bug!("system abi should be selected elsewhere"), - EfiApi => bug!("eficall abi should be selected elsewhere"), - - Stdcall { .. } => Conv::X86Stdcall, - Fastcall { .. } => Conv::X86Fastcall, - Vectorcall { .. } => Conv::X86VectorCall, - Thiscall { .. } => Conv::X86ThisCall, - C { .. } => Conv::C, - Unadjusted => Conv::C, - Win64 { .. } => Conv::X86_64Win64, - SysV64 { .. } => Conv::X86_64SysV, - Aapcs { .. } => Conv::ArmAapcs, - CCmseNonSecureCall => Conv::CCmseNonSecureCall, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - AvrInterrupt => Conv::AvrInterrupt, - AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, - Wasm => Conv::C, - - // These API constants ought to be more specific... - Cdecl { .. } => Conv::C, - } -} - /// Error produced by attempting to compute or adjust a `FnAbi`. #[derive(Copy, Clone, Debug, HashStable)] pub enum FnAbiError<'tcx> { @@ -3066,6 +1126,12 @@ impl<'tcx> fmt::Display for FnAbiError<'tcx> { } } +impl<'tcx> IntoDiagnostic<'tcx, !> for FnAbiError<'tcx> { + fn into_diagnostic(self, handler: &'tcx Handler) -> DiagnosticBuilder<'tcx, !> { + handler.struct_fatal(self.to_string()) + } +} + // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not // just for error handling. #[derive(Debug)] @@ -3123,6 +1189,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// NB: that includes virtual calls, which are represented by "direct calls" /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`). #[inline] + #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( &self, instance: ty::Instance<'tcx>, @@ -3146,359 +1213,3 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} - -fn fn_abi_of_fn_ptr<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, -) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - let (param_env, (sig, extra_args)) = query.into_parts(); - - LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false) -} - -fn fn_abi_of_instance<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, -) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - let (param_env, (instance, extra_args)) = query.into_parts(); - - let sig = instance.fn_sig_for_fn_abi(tcx, param_env); - - let caller_location = if instance.def.requires_caller_location(tcx) { - Some(tcx.caller_location_ty()) - } else { - None - }; - - LayoutCx { tcx, param_env }.fn_abi_new_uncached( - sig, - extra_args, - caller_location, - Some(instance.def_id()), - matches!(instance.def, ty::InstanceDef::Virtual(..)), - ) -} - -impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) - // arguments of this method, into a separate `struct`. - fn fn_abi_new_uncached( - &self, - sig: ty::PolyFnSig<'tcx>, - extra_args: &[Ty<'tcx>], - caller_location: Option<Ty<'tcx>>, - fn_def_id: Option<DefId>, - // FIXME(eddyb) replace this with something typed, like an `enum`. - force_thin_self_ptr: bool, - ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args); - - let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig); - - let conv = conv_from_spec_abi(self.tcx(), sig.abi); - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - if let Some(input) = sig.inputs().last() { - if let ty::Tuple(tupled_arguments) = input.kind() { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments - } else { - bug!( - "argument to function with \"rust-call\" ABI \ - is not a tuple" - ); - } - } else { - bug!( - "argument to function with \"rust-call\" ABI \ - is not a tuple" - ); - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args - }; - - let target = &self.tcx.sess.target; - let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc"); - let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu"; - let linux_s390x_gnu_like = - target.os == "linux" && target.arch == "s390x" && target_env_gnu_like; - let linux_sparc64_gnu_like = - target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like; - let linux_powerpc_gnu_like = - target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like; - use SpecAbi::*; - let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: Scalar, - layout: TyAndLayout<'tcx>, - offset: Size, - is_return: bool| { - // Booleans are always a noundef i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.ext(ArgExtension::Zext); - attrs.set(ArgAttribute::NoUndef); - return; - } - - // Scalars which have invalid values cannot be undef. - if !scalar.is_always_valid(self) { - attrs.set(ArgAttribute::NoUndef); - } - - // Only pointer types handled below. - let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; - - if !valid_range.contains(0) { - attrs.set(ArgAttribute::NonNull); - } - - if let Some(pointee) = layout.pointee_info_at(self, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_align = Some(pointee.align); - - // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable - // for the entire duration of the function as they can be deallocated - // at any time. Same for shared mutable references. If LLVM had a - // way to say "dereferenceable on entry" we could use it here. - attrs.pointee_size = match kind { - PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned - | PointerKind::Frozen => pointee.size, - PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, - }; - - // `Box`, `&T`, and `&mut T` cannot be undef. - // Note that this only applies to the value of the pointer itself; - // this attribute doesn't make it UB for the pointed-to data to be undef. - attrs.set(ArgAttribute::NoUndef); - - // The aliasing rules for `Box<T>` are still not decided, but currently we emit - // `noalias` for it. This can be turned off using an unstable flag. - // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 - let noalias_for_box = - self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true); - - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell<U>` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - // - // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute - // for UniqueBorrowed arguments, so that the codegen backend can decide whether - // or not to actually emit the attribute. It can also be controlled with the - // `-Zmutable-noalias` debugging option. - let no_alias = match kind { - PointerKind::SharedMutable - | PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned => false, - PointerKind::UniqueOwned => noalias_for_box, - PointerKind::Frozen => !is_return, - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - - if kind == PointerKind::UniqueBorrowed && !is_return { - attrs.set(ArgAttribute::NoAliasMutRef); - } - } - } - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> { - let is_return = arg_idx.is_none(); - - let layout = self.layout_of(ty)?; - let layout = if force_thin_self_ptr && arg_idx == Some(0) { - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - make_thin_self_ptr(self, layout) - } else { - layout - }; - - let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| { - let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return); - attrs - }); - - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}. - if is_return - || rust_abi - || (!win_x64_gnu - && !linux_s390x_gnu_like - && !linux_sparc64_gnu_like - && !linux_powerpc_gnu_like) - { - arg.mode = PassMode::Ignore; - } - } - - Ok(arg) - }; - - let mut fn_abi = FnAbi { - ret: arg_of(sig.output(), None)?, - args: inputs - .iter() - .copied() - .chain(extra_args.iter().copied()) - .chain(caller_location) - .enumerate() - .map(|(i, ty)| arg_of(ty, Some(i))) - .collect::<Result<_, _>>()?, - c_variadic: sig.c_variadic, - fixed_count: inputs.len(), - conv, - can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi), - }; - self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?; - debug!("fn_abi_new_uncached = {:?}", fn_abi); - Ok(self.tcx.arena.alloc(fn_abi)) - } - - fn fn_abi_adjust_for_abi( - &self, - fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, - abi: SpecAbi, - ) -> Result<(), FnAbiError<'tcx>> { - if abi == SpecAbi::Unadjusted { - return Ok(()); - } - - if abi == SpecAbi::Rust - || abi == SpecAbi::RustCall - || abi == SpecAbi::RustIntrinsic - || abi == SpecAbi::PlatformIntrinsic - { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { - return; - } - - match arg.layout.abi { - Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - Abi::Vector { .. } - if abi != SpecAbi::PlatformIntrinsic - && self.tcx.sess.target.simd_types_indirect => - { - arg.make_indirect(); - return; - } - - _ => return, - } - - let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(self) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); - } - }; - fixup(&mut fn_abi.ret); - for arg in &mut fn_abi.args { - fixup(arg); - } - } else { - fn_abi.adjust_for_foreign_abi(self, abi)?; - } - - Ok(()) - } -} - -fn make_thin_self_ptr<'tcx>( - cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), - layout: TyAndLayout<'tcx>, -) -> TyAndLayout<'tcx> { - let tcx = cx.tcx(); - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - tcx.mk_mut_ptr(layout.ty) - } else { - match layout.abi { - Abi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout), - } - - // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self> - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes; - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox<dyn Trait>` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit()); - - TyAndLayout { - ty: fat_pointer_ty, - - // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result` - // should always work because the type is always `*mut ()`. - ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap() - } -} diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index db3b5cfd1..79365ef28 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -65,6 +65,10 @@ impl<T> List<T> { pub fn len(&self) -> usize { self.len } + + pub fn as_slice(&self) -> &[T] { + self + } } impl<T: Copy> List<T> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 02da02568..a42d05706 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -15,8 +15,9 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; +use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; -use crate::middle::privacy::AccessLevels; +use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, GeneratorLayout}; use crate::traits::{self, Reveal}; use crate::ty; @@ -25,6 +26,7 @@ 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; @@ -36,10 +38,13 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::Definitions; use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; +use rustc_serialize::{Decodable, Encodable}; +use rustc_session::cstore::CrateStoreDyn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; @@ -49,10 +54,14 @@ pub use vtable::*; use std::fmt::Debug; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::mem; +use std::num::NonZeroUsize; use std::ops::ControlFlow; use std::{fmt, str}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; pub use rustc_type_ir::TyKind::*; @@ -67,11 +76,11 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree, + Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, - CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, + CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; @@ -83,9 +92,9 @@ pub use self::sty::BoundRegionKind::*; pub use self::sty::{ Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, - EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, - ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, - InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, + 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, }; @@ -125,6 +134,7 @@ mod generics; mod impls_ty; mod instance; mod list; +mod opaque_types; mod parameterized; mod rvalue_scopes; mod structural_impls; @@ -134,8 +144,15 @@ mod sty; pub type RegisteredTools = FxHashSet<Ident>; -#[derive(Debug)] pub struct ResolverOutputs { + pub definitions: Definitions, + pub global_ctxt: ResolverGlobalCtxt, + pub ast_lowering: ResolverAstLowering, +} + +#[derive(Debug)] +pub struct ResolverGlobalCtxt { + pub cstore: Box<CrateStoreDyn>, pub visibilities: FxHashMap<LocalDefId, Visibility>, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, @@ -143,7 +160,7 @@ pub struct ResolverOutputs { pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>, /// Reference span for definitions. pub source_span: IndexVec<LocalDefId, Span>, - pub access_levels: AccessLevels, + pub effective_visibilities: EffectiveVisibilities, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, @@ -177,11 +194,6 @@ pub struct ResolverAstLowering { pub label_res_map: NodeMap<ast::NodeId>, /// Resolutions for lifetimes. pub lifetimes_res_map: NodeMap<LifetimeRes>, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>, /// Lifetime parameters that lowering will have to introduce. pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>, @@ -262,13 +274,11 @@ impl fmt::Display for ImplPolarity { } #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] -pub enum Visibility { +pub enum Visibility<Id = LocalDefId> { /// Visible everywhere (including in other crates). Public, /// Visible only in the given crate-local module. - Restricted(DefId), - /// Not visible anywhere in the local crate. This is the visibility of private external items. - Invisible, + Restricted(Id), } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] @@ -359,31 +369,45 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> { } } -impl Visibility { - /// Returns `true` if an item with this visibility is accessible from the given block. - pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool { - let restriction = match self { - // Public items are visible everywhere. - Visibility::Public => return true, - // Private items from other crates are visible nowhere. - Visibility::Invisible => return false, - // Restricted items are visible in an arbitrary local module. - Visibility::Restricted(other) if other.krate != module.krate => return false, - Visibility::Restricted(module) => module, - }; +impl<Id> Visibility<Id> { + pub fn is_public(self) -> bool { + matches!(self, Visibility::Public) + } - tree.is_descendant_of(module, restriction) + pub fn map_id<OutId>(self, f: impl FnOnce(Id) -> OutId) -> Visibility<OutId> { + match self { + Visibility::Public => Visibility::Public, + Visibility::Restricted(id) => Visibility::Restricted(f(id)), + } + } +} + +impl<Id: Into<DefId>> Visibility<Id> { + pub fn to_def_id(self) -> Visibility<DefId> { + self.map_id(Into::into) + } + + /// Returns `true` if an item with this visibility is accessible from the given module. + pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool { + match self { + // Public items are visible everywhere. + Visibility::Public => true, + Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()), + } } /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool { - let vis_restriction = match vis { - Visibility::Public => return self == Visibility::Public, - Visibility::Invisible => return true, - Visibility::Restricted(module) => module, - }; + pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool { + match vis { + Visibility::Public => self.is_public(), + Visibility::Restricted(id) => self.is_accessible_from(id, tree), + } + } +} - self.is_accessible_from(vis_restriction, tree) +impl Visibility<DefId> { + pub fn expect_local(self) -> Visibility { + self.map_id(|id| id.expect_local()) } // Returns `true` if this item is visible anywhere in the local crate. @@ -391,13 +415,8 @@ impl Visibility { match self { Visibility::Public => true, Visibility::Restricted(def_id) => def_id.is_local(), - Visibility::Invisible => false, } } - - pub fn is_public(self) -> bool { - matches!(self, Visibility::Public) - } } /// The crate variances map is computed during typeck and contains the @@ -468,15 +487,6 @@ pub(crate) struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyS<'_>, 40); - -// We are actually storing a stable hash cache next to the type, so let's -// also check the full size -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(WithStableHash<TyS<'_>>, 56); - /// Use this rather than `TyS`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] @@ -533,10 +543,6 @@ pub(crate) struct PredicateS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateS<'_>, 56); - /// Use this rather than `PredicateS`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] @@ -593,6 +599,29 @@ impl<'tcx> Predicate<'tcx> { } self } + + /// Whether this projection can be soundly normalized. + /// + /// Wf predicates must not be normalized, as normalization + /// can remove required bounds which would cause us to + /// unsoundly accept some programs. See #91068. + #[inline] + pub fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + PredicateKind::WellFormed(_) => false, + PredicateKind::Trait(_) + | PredicateKind::RegionOutlives(_) + | PredicateKind::TypeOutlives(_) + | PredicateKind::Projection(_) + | PredicateKind::ObjectSafe(_) + | PredicateKind::ClosureKind(_, _, _) + | PredicateKind::Subtype(_) + | PredicateKind::Coerce(_) + | PredicateKind::ConstEvaluatable(_) + | PredicateKind::ConstEquate(_, _) + | PredicateKind::TypeWellFormedFromEnv(_) => true, + } + } } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { @@ -617,7 +646,7 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -663,7 +692,7 @@ pub enum PredicateKind<'tcx> { Coerce(CoercePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::Unevaluated<'tcx, ()>), + ConstEvaluatable(ty::Const<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(Const<'tcx>, Const<'tcx>), @@ -789,7 +818,7 @@ impl<'tcx> Predicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, @@ -842,6 +871,11 @@ impl<'tcx> TraitPredicate<'tcx> { (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false, } } + + pub fn without_const(mut self) -> Self { + self.constness = BoundConstness::NotConst; + self + } } impl<'tcx> PolyTraitPredicate<'tcx> { @@ -869,7 +903,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B` pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; @@ -880,7 +914,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicat /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct SubtypePredicate<'tcx> { pub a_is_expected: bool, pub a: Ty<'tcx>, @@ -890,49 +924,142 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; /// Encodes that we have to coerce *from* the `a` type to the `b` type. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CoercePredicate<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, } pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub enum Term<'tcx> { - Ty(Ty<'tcx>), - Const(Const<'tcx>), +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Term<'tcx> { + ptr: NonZeroUsize, + marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, +} + +impl Debug for Term<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data = if let Some(ty) = self.ty() { + format!("Term::Ty({:?})", ty) + } else if let Some(ct) = self.ct() { + format!("Term::Ct({:?})", ct) + } else { + unreachable!() + }; + f.write_str(&data) + } } impl<'tcx> From<Ty<'tcx>> for Term<'tcx> { fn from(ty: Ty<'tcx>) -> Self { - Term::Ty(ty) + TermKind::Ty(ty).pack() } } impl<'tcx> From<Const<'tcx>> for Term<'tcx> { fn from(c: Const<'tcx>) -> Self { - Term::Const(c) + TermKind::Const(c).pack() + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(self.unpack().try_fold_with(folder)?.pack()) + } +} + +impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.unpack().visit_with(visitor) + } +} + +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Term<'tcx> { + fn encode(&self, e: &mut E) { + self.unpack().encode(e) + } +} + +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> { + fn decode(d: &mut D) -> Self { + let res: TermKind<'tcx> = Decodable::decode(d); + res.pack() } } impl<'tcx> Term<'tcx> { + #[inline] + pub fn unpack(self) -> TermKind<'tcx> { + let ptr = self.ptr.get(); + // SAFETY: use of `Interned::new_unchecked` here is ok because these + // pointers were originally created from `Interned` types in `pack()`, + // and this is just going in the other direction. + unsafe { + match ptr & TAG_MASK { + TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>), + ))), + CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), + ))), + _ => core::intrinsics::unreachable(), + } + } + } + pub fn ty(&self) -> Option<Ty<'tcx>> { - if let Term::Ty(ty) = self { Some(*ty) } else { None } + if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None } } pub fn ct(&self) -> Option<Const<'tcx>> { - if let Term::Const(c) = self { Some(*c) } else { None } + if let TermKind::Const(c) = self.unpack() { Some(c) } else { None } } pub fn into_arg(self) -> GenericArg<'tcx> { - match self { - Term::Ty(ty) => ty.into(), - Term::Const(c) => c.into(), + match self.unpack() { + TermKind::Ty(ty) => ty.into(), + TermKind::Const(c) => c.into(), } } } +const TAG_MASK: usize = 0b11; +const TYPE_TAG: usize = 0b00; +const CONST_TAG: usize = 0b01; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] +pub enum TermKind<'tcx> { + Ty(Ty<'tcx>), + Const(Const<'tcx>), +} + +impl<'tcx> TermKind<'tcx> { + #[inline] + fn pack(self) -> Term<'tcx> { + let (tag, ptr) = match self { + 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<ty::TyS<'tcx>> as usize) + } + TermKind::Const(ct) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) + } + }; + + Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -946,7 +1073,7 @@ impl<'tcx> Term<'tcx> { /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub term: Term<'tcx>, @@ -1002,6 +1129,12 @@ pub trait ToPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } +impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1166,20 +1299,117 @@ pub struct OpaqueHiddenType<'tcx> { impl<'tcx> OpaqueHiddenType<'tcx> { pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { // Found different concrete types for the opaque type. - let mut err = tcx.sess.struct_span_err( - other.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); - if self.span == other.span { - err.span_label( - self.span, - "this expression supplies two conflicting concrete types for the same opaque type", - ); + let sub_diag = if self.span == other.span { + TypeMismatchReason::ConflictType { span: self.span } } else { - err.span_note(self.span, "previous use here"); - } - err.emit(); + TypeMismatchReason::PreviousUse { span: self.span } + }; + tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + self_ty: self.ty, + other_ty: other.ty, + other_span: other.span, + sub: sub_diag, + }); + } + + #[instrument(level = "debug", skip(tcx), ret)] + pub fn remap_generic_params_to_declaration_params( + self, + opaque_type_key: OpaqueTypeKey<'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; + + // Use substs to build up a reverse map from regions to their + // identity mappings. This is necessary because of `impl + // Trait` lifetimes are computed by replacing existing + // lifetimes with 'static and remapping only those used in the + // `impl Trait` return type, resulting in the parameters + // shifting. + 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>, 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<ty::Region<'tcx>>, + } + + impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + 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<Foo<'a>>; + // 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() + } + }; + debug!("map = {:#?}", map); + + // Convert the type from the function into a type valid outside + // the function, by replacing invalid regions with 'static, + // after producing an error for each of them. + self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors)) } } @@ -1411,7 +1641,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { Ok(ParamEnv::new( self.caller_bounds().try_fold_with(folder)?, self.reveal().try_fold_with(folder)?, - self.constness().try_fold_with(folder)?, + self.constness(), )) } } @@ -1419,8 +1649,7 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.caller_bounds().visit_with(visitor)?; - self.reveal().visit_with(visitor)?; - self.constness().visit_with(visitor) + self.reveal().visit_with(visitor) } } @@ -1577,7 +1806,7 @@ impl<'tcx> PolyTraitRef<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] -#[derive(HashStable)] +#[derive(HashStable, Lift)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, pub value: T, @@ -1779,7 +2008,7 @@ pub enum VariantDiscr { pub struct FieldDef { pub did: DefId, pub name: Symbol, - pub vis: Visibility, + pub vis: Visibility<DefId>, } impl PartialEq for FieldDef { @@ -2256,7 +2485,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { - self.get_attrs(did, attr).next() + if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); + } else { + self.get_attrs(did, attr).next() + } } /// Determines whether an item is annotated with an attribute. @@ -2358,6 +2591,25 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } + /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion + /// site. Only applies when `Span` is the result of macro expansion. + /// + /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default + /// and only when a macro definition is annotated with `#[collapse_debuginfo]`. + /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. + /// + /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. + pub fn should_collapse_debuginfo(self, span: Span) -> bool { + !self.sess.opts.unstable_opts.debug_macros + && 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() + } + } + pub fn is_object_safe(self, key: DefId) -> bool { self.object_safety_violations(key).is_empty() } @@ -2372,6 +2624,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn is_const_default_method(self, def_id: DefId) -> bool { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } + + pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId { + while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { + debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); + def_id = self.parent(def_id); + } + def_id + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. @@ -2445,7 +2705,7 @@ pub fn provide(providers: &mut ty::query::Providers) { closure::provide(providers); context::provide(providers); erase_regions::provide(providers); - layout::provide(providers); + inhabitedness::provide(providers); util::provide(providers); print::provide(providers); super::util::bug::provide(providers); @@ -2453,7 +2713,6 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, - type_uninhabited_from: inhabitedness::type_uninhabited_from, const_param_default: consts::const_param_default, vtable_allocation: vtable::vtable_allocation_provider, ..*providers @@ -2516,3 +2775,15 @@ pub struct DestructuredConst<'tcx> { pub variant: Option<VariantIdx>, pub fields: &'tcx [ty::Const<'tcx>], } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +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<TyS<'_>>, 56); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9d8a81165..ee13920d5 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -10,8 +10,7 @@ use crate::mir; use crate::traits::query::NoSolution; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, EarlyBinder, Ty, TyCtxt}; +use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt}; #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)] pub enum NormalizationError<'tcx> { @@ -36,6 +35,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, @@ -100,6 +100,7 @@ impl<'tcx> TyCtxt<'tcx> { /// N.B., currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in /// codegen, we need to normalize the contents. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_late_bound_regions<T>( self, param_env: ty::ParamEnv<'tcx>, @@ -188,13 +189,11 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { - #[instrument(skip(self), level = "debug")] fn normalize_generic_arg_after_erasing_regions( &self, arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.param_env.and(arg); - debug!(?arg); self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", @@ -215,15 +214,6 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const() } - - #[inline] - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { - // FIXME: This *probably* needs canonicalization too! - let arg = self.param_env.and(c); - self.tcx - .try_normalize_mir_const_after_erasing_regions(arg) - .unwrap_or_else(|_| bug!("failed to normalize {:?}", c)) - } } struct TryNormalizeAfterErasingRegionsFolder<'tcx> { @@ -268,16 +258,4 @@ impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'t Err(_) => Err(NormalizationError::Const(c)), } } - - fn try_fold_mir_const( - &mut self, - c: mir::ConstantKind<'tcx>, - ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { - // FIXME: This *probably* needs canonicalization too! - let arg = self.param_env.and(c); - match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) { - Ok(c) => Ok(c), - Err(_) => Err(NormalizationError::ConstantKind(c)), - } - } } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs new file mode 100644 index 000000000..b05c63109 --- /dev/null +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -0,0 +1,218 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_span::Span; + +/// Converts generic params of a TypeFoldable from one +/// item's generics to another. Usually from a function's generics +/// list to the opaque type's own generics. +pub(super) struct ReverseMapper<'tcx> { + tcx: TyCtxt<'tcx>, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + /// see call sites to fold_kind_no_missing_regions_error + /// for an explanation of this field. + do_not_error: bool, + + /// We do not want to emit any errors in typeck because + /// the spans in typeck are subpar at the moment. + /// Borrowck will do the same work again (this time with + /// lifetime information) and thus report better errors. + ignore_errors: bool, + + /// Span of function being checked. + span: Span, +} + +impl<'tcx> ReverseMapper<'tcx> { + pub(super) fn new( + tcx: TyCtxt<'tcx>, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + span: Span, + ignore_errors: bool, + ) -> Self { + Self { tcx, map, do_not_error: false, ignore_errors, span } + } + + fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + self.do_not_error = true; + let kind = kind.fold_with(self); + self.do_not_error = false; + kind + } + + fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + kind.fold_with(self) + } +} + +impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + #[instrument(skip(self), level = "debug")] + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + // Ignore bound regions and `'static` regions that appear in the + // type, we only need to remap regions that reference lifetimes + // from the function declaration. + // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) | ty::ReStatic => return r, + + // If regions have been erased (by writeback), don't try to unerase + // them. + ty::ReErased => return r, + + // The regions that we expect from borrow checking. + ty::ReEarlyBound(_) | ty::ReFree(_) => {} + + ty::RePlaceholder(_) | ty::ReVar(_) => { + // All of the regions in the type should either have been + // erased by writeback, or mapped back to named regions by + // borrow checking. + bug!("unexpected region kind in opaque type: {:?}", r); + } + } + + match self.map.get(&r.into()).map(|k| k.unpack()) { + Some(GenericArgKind::Lifetime(r1)) => r1, + Some(u) => panic!("region mapped to unexpected kind: {:?}", u), + None if self.do_not_error => self.tcx.lifetimes.re_static, + None => { + self.tcx + .sess + .struct_span_err(self.span, "non-defining opaque type use in defining scope") + .span_label( + self.span, + format!( + "lifetime `{}` is part of concrete type but not used in \ + parameter list of the `impl Trait` type alias", + r + ), + ) + .emit(); + + self.tcx().lifetimes.re_static + } + } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Closure(def_id, substs) => { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_closure(def_id, substs) + } + + ty::Generator(def_id, substs, movability) => { + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_generator(def_id, substs, movability) + } + + ty::Param(param) => { + // Look it up in the substitution list. + match self.map.get(&ty.into()).map(|k| k.unpack()) { + // Found it in the substitution list; replace with the parameter from the + // opaque type. + Some(GenericArgKind::Type(t1)) => t1, + Some(u) => panic!("type mapped to unexpected kind: {:?}", u), + None => { + debug!(?param, ?self.map); + if !self.ignore_errors { + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "type parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ty + ), + ) + .emit(); + } + + self.tcx().ty_error() + } + } + } + + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + trace!("checking const {:?}", ct); + // Find a const parameter + match ct.kind() { + ty::ConstKind::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ct.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // opaque type. + Some(GenericArgKind::Const(c1)) => c1, + Some(u) => panic!("const mapped to unexpected kind: {:?}", u), + None => { + if !self.ignore_errors { + self.tcx.sess.emit_err(ty::ConstNotUsedTraitAlias { + ct: ct.to_string(), + span: self.span, + }); + } + + self.tcx().const_error(ct.ty()) + } + } + } + + _ => ct, + } + } +} diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e189ee2fc..e1e705a92 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -1,4 +1,5 @@ -use rustc_hir::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::{DefId, DefIndex}; use rustc_index::vec::{Idx, IndexVec}; use crate::middle::exported_symbols::ExportedSymbol; @@ -29,6 +30,10 @@ impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVe type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; } +impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for FxHashMap<I, T> { + type Value<'tcx> = FxHashMap<I, T::Value<'tcx>>; +} + impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> { type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>; } @@ -53,17 +58,21 @@ trivially_parameterized_over_tcx! { crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, crate::middle::exported_symbols::SymbolExportInfo, + crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, + ty::AssocItemContainer, + ty::DeducedParamAttrs, ty::Generics, ty::ImplPolarity, ty::ReprOptions, ty::TraitDef, - ty::Visibility, + ty::Visibility<DefIndex>, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedTypeGen<DefId>, rustc_ast::Attribute, rustc_ast::MacArgs, rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, rustc_attr::Stability, rustc_hir::Constness, @@ -74,6 +83,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def::DefKind, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, + rustc_index::bit_set::BitSet<u32>, rustc_index::bit_set::FiniteBitSet<u32>, rustc_session::cstore::ForeignModule, rustc_session::cstore::LinkagePreference, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d57cf8f01..44b9548db 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,9 +1,9 @@ -use crate::ty::subst::{GenericArg, Subst}; +use crate::ty::GenericArg; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; -use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; // `pretty` is a separate module only for organization. @@ -325,3 +325,12 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { cx.print_const(*self) } } + +// This is only used by query descriptions +pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { + if def_id.is_top_level_module() { + "top-level module".to_string() + } else { + format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) + } +} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7f2e81a71..ef9aa236b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,9 +1,9 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; -use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{ - self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable, + self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, }; +use crate::ty::{GenericArg, GenericArgKind}; use rustc_apfloat::ieee::{Double, Single}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sso::SsoHashSet; @@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use smallvec::SmallVec; use std::cell::Cell; use std::char; @@ -62,6 +63,7 @@ thread_local! { static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) }; static NO_QUERIES: Cell<bool> = const { Cell::new(false) }; static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) }; + static NO_VERBOSE_CONSTANTS: Cell<bool> = const { Cell::new(false) }; } macro_rules! define_helper { @@ -116,6 +118,9 @@ define_helper!( /// Prevent selection of visible paths. `Display` impl of DefId will prefer /// visible (public) reexports of types as paths. fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH); + /// Prevent verbose printing of constants. Verbose printing of constants is + /// never desirable in some contexts like `std::any::type_name`. + fn with_no_verbose_constants(NoVerboseConstantsGuard, NO_VERBOSE_CONSTANTS); ); /// The "region highlights" are used to control region printing during @@ -619,12 +624,16 @@ pub trait PrettyPrinter<'tcx>: ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, repr) => { let print_r = self.should_print_region(r); if print_r { p!("("); } - p!("dyn ", print(data)); + match repr { + ty::Dyn => p!("dyn "), + ty::DynStar => p!("dyn* "), + } + p!(print(data)); if print_r { p!(" + ", print(r), ")"); } @@ -632,7 +641,15 @@ pub trait PrettyPrinter<'tcx>: ty::Foreign(def_id) => { p!(print_def_path(def_id, &[])); } - ty::Projection(ref data) => p!(print(data)), + ty::Projection(ref data) => { + if !(self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get())) + && self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder + { + return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs); + } else { + p!(print(data)) + } + } ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), ty::Opaque(def_id, substs) => { // FIXME(eddyb) print this with `print_def_path`. @@ -746,7 +763,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Array(ty, sz) => { p!("[", print(ty), "; "); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("{:?}", sz)); } else if let ty::ConstKind::Unevaluated(..) = sz.kind() { // Do not try to evaluate unevaluated constants. If we are const evaluating an @@ -782,9 +799,9 @@ pub trait PrettyPrinter<'tcx>: let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); let mut is_sized = false; + let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - let predicate = predicate.subst(tcx, substs); + for (predicate, _) in bounds.subst_iter_copied(tcx, substs) { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -813,6 +830,9 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } + ty::PredicateKind::TypeOutlives(outlives) => { + lifetimes.push(outlives.1); + } _ => {} } } @@ -855,7 +875,7 @@ pub trait PrettyPrinter<'tcx>: } p!(")"); - if let Term::Ty(ty) = return_ty.skip_binder() { + if let Some(ty) = return_ty.skip_binder().ty() { if !ty.is_unit() { p!(" -> ", print(return_ty)); } @@ -916,12 +936,14 @@ pub trait PrettyPrinter<'tcx>: // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, // unless we can find out what generator return type it comes from. let term = if let Some(ty) = term.skip_binder().ty() - && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() - && Some(*item_def_id) == tcx.lang_items().generator_return() + && let ty::Projection(proj) = ty.kind() + && let Some(assoc) = tcx.opt_associated_item(proj.item_def_id) + && assoc.trait_container(tcx) == tcx.lang_items().gen_trait() + && assoc.name == rustc_span::sym::Return { if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { let return_ty = substs.as_generator().return_ty(); - if !return_ty.is_ty_infer() { + if !return_ty.is_ty_var() { return_ty.into() } else { continue; @@ -942,13 +964,9 @@ pub trait PrettyPrinter<'tcx>: p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); - match term { - Term::Ty(ty) => { - p!(print(ty)) - } - Term::Const(c) => { - p!(print(c)); - } + match term.unpack() { + TermKind::Ty(ty) => p!(print(ty)), + TermKind::Const(c) => p!(print(c)), }; } @@ -968,6 +986,11 @@ pub trait PrettyPrinter<'tcx>: write!(self, "Sized")?; } + for re in lifetimes { + write!(self, " + ")?; + self = self.print_region(re)?; + } + Ok(self) } @@ -1080,17 +1103,9 @@ pub trait PrettyPrinter<'tcx>: .generics_of(principal.def_id) .own_substs_no_defaults(cx.tcx(), principal.substs); - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => !r.is_erased(), - _ => false, - }); - let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); let mut projections = predicates.projection_bounds(); + let mut args = args.iter().cloned(); let arg0 = args.next(); let projection0 = projections.next(); if arg0.is_some() || projection0.is_some() { @@ -1170,7 +1185,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("Const({:?}: {:?})", ct.kind(), ct.ty())); return Ok(self); } @@ -1193,15 +1208,7 @@ pub trait PrettyPrinter<'tcx>: } match ct.kind() { - ty::ConstKind::Unevaluated(ty::Unevaluated { - def, - substs, - promoted: Some(promoted), - }) => { - p!(print_value_path(def.did, substs)); - p!(write("::{:?}", promoted)); - } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => { + ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { match self.tcx().def_kind(def.did) { DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => { p!(print_value_path(def.did, substs)) @@ -1275,7 +1282,7 @@ pub trait PrettyPrinter<'tcx>: let range = AllocRange { start: offset, size: Size::from_bytes(len) }; if let Ok(byte_str) = - alloc.inner().get_bytes(&self.tcx(), range) + alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) { p!(pretty_print_byte_str(byte_str)) } else { @@ -1401,14 +1408,7 @@ pub trait PrettyPrinter<'tcx>: } fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> { - define_scoped_cx!(self); - p!("b\""); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; - } - } - p!("\""); + write!(self, "b\"{}\"", byte_str.escape_ascii())?; Ok(self) } @@ -1420,7 +1420,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("ValTree({:?}: ", valtree), print(ty), ")"); return Ok(self); } @@ -1513,6 +1513,10 @@ pub trait PrettyPrinter<'tcx>: } return Ok(self); } + (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { + p!(write("&")); + return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + } (ty::ValTree::Leaf(leaf), _) => { return self.pretty_print_const_scalar_int(leaf, ty, print_ty); } @@ -1532,6 +1536,34 @@ pub trait PrettyPrinter<'tcx>: } Ok(self) } + + fn pretty_closure_as_impl( + mut self, + closure: ty::ClosureSubsts<'tcx>, + ) -> Result<Self::Const, Self::Error> { + let sig = closure.sig(); + let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); + + write!(self, "impl ")?; + self.wrap_binder(&sig, |sig, mut cx| { + define_scoped_cx!(cx); + + p!(print(kind), "("); + for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() { + if i > 0 { + p!(", "); + } + p!(print(arg)); + } + p!(")"); + + if !sig.output().is_unit() { + p!(" -> ", print(sig.output())); + } + + Ok(cx) + }) + } } // HACK(eddyb) boxed to avoid moving around a large struct by-value. @@ -1545,7 +1577,9 @@ pub struct FmtPrinterData<'a, 'tcx> { in_value: bool, pub print_alloc_ids: bool, + // set of all named (non-anonymous) region names used_region_names: FxHashSet<Symbol>, + region_index: usize, binder_depth: usize, printed_type_count: usize, @@ -1820,22 +1854,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { ) -> Result<Self::Path, Self::Error> { self = print_prefix(self)?; - // Don't print `'_` if there's no unerased regions. - let print_regions = self.tcx.sess.verbose() - || args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => !r.is_erased(), - _ => false, - }); - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - - if args.clone().next().is_some() { + if args.first().is_some() { if self.in_value { write!(self, "::")?; } - self.generic_delimiters(|cx| cx.comma_sep(args)) + self.generic_delimiters(|cx| cx.comma_sep(args.iter().cloned())) } else { Ok(self) } @@ -1950,7 +1973,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { ty::ReVar(_) | ty::ReErased => false, - ty::ReStatic | ty::ReEmpty(_) => true, + ty::ReStatic => true, } } @@ -2034,14 +2057,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { p!("'static"); return Ok(self); } - ty::ReEmpty(ty::UniverseIndex::ROOT) => { - p!("'<empty>"); - return Ok(self); - } - ty::ReEmpty(ui) => { - p!(write("'<empty:{:?}>", ui)); - return Ok(self); - } } p!("'_"); @@ -2055,7 +2070,14 @@ struct RegionFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, - name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), + name: &'a mut ( + dyn FnMut( + Option<ty::DebruijnIndex>, // Debruijn index of the folded late-bound region + ty::DebruijnIndex, // Index corresponding to binder level + ty::BoundRegion, + ) -> ty::Region<'tcx> + + 'a + ), } impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { @@ -2086,7 +2108,9 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; let region = match *r { - ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)), + ty::ReLateBound(db, br) if db >= self.current_index => { + *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) + } ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => { // If this is an anonymous placeholder, don't rename. Otherwise, in some // async fns, we get a `for<'r> Send` bound @@ -2095,7 +2119,10 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { _ => { // Index doesn't matter, since this is just for naming and these never get bound let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind }; - *self.region_map.entry(br).or_insert_with(|| name(br)) + *self + .region_map + .entry(br) + .or_insert_with(|| name(None, self.current_index, br)) } } } @@ -2120,23 +2147,31 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { where T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, { - fn name_by_region_index(index: usize) -> Symbol { - match index { - 0 => Symbol::intern("'r"), - 1 => Symbol::intern("'s"), - i => Symbol::intern(&format!("'t{}", i - 2)), + fn name_by_region_index( + index: usize, + available_names: &mut Vec<Symbol>, + num_available: usize, + ) -> Symbol { + if let Some(name) = available_names.pop() { + name + } else { + Symbol::intern(&format!("'z{}", index - num_available)) } } + debug!("name_all_regions"); + // Replace any anonymous late-bound regions with named // variants, using new unique identifiers, so that we can // clearly differentiate between named and unnamed regions in // the output. We'll probably want to tweak this over time to // decide just how much information to give. if self.binder_depth == 0 { - self.prepare_late_bound_region_info(value); + self.prepare_region_info(value); } + debug!("self.used_region_names: {:?}", &self.used_region_names); + let mut empty = true; let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| { let w = if empty { @@ -2153,13 +2188,30 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { define_scoped_cx!(self); + let possible_names = + ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))).collect::<Vec<_>>(); + + let mut available_names = possible_names + .into_iter() + .filter(|name| !self.used_region_names.contains(&name)) + .collect::<Vec<_>>(); + debug!(?available_names); + let num_available = available_names.len(); + let mut region_index = self.region_index; - let mut next_name = |this: &Self| loop { - let name = name_by_region_index(region_index); - region_index += 1; - if !this.used_region_names.contains(&name) { - break name; + let mut next_name = |this: &Self| { + let mut name; + + loop { + name = name_by_region_index(region_index, &mut available_names, num_available); + region_index += 1; + + if !this.used_region_names.contains(&name) { + break; + } } + + name }; // If we want to print verbosely, then print *all* binders, even if they @@ -2180,6 +2232,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { ty::BrAnon(_) | ty::BrEnv => { start_or_continue(&mut self, "for<", ", "); let name = next_name(&self); + debug!(?name); do_continue(&mut self, name); ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) } @@ -2208,24 +2261,63 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { }) } else { let tcx = self.tcx; - let mut name = |br: ty::BoundRegion| { - start_or_continue(&mut self, "for<", ", "); - let kind = match br.kind { + + // Closure used in `RegionFolder` to create names for anonymous late-bound + // regions. We use two `DebruijnIndex`es (one for the currently folded + // late-bound region and the other for the binder level) to determine + // whether a name has already been created for the currently folded region, + // see issue #102392. + let mut name = |lifetime_idx: Option<ty::DebruijnIndex>, + binder_level_idx: ty::DebruijnIndex, + br: ty::BoundRegion| { + let (name, kind) = match br.kind { ty::BrAnon(_) | ty::BrEnv => { let name = next_name(&self); - do_continue(&mut self, name); - ty::BrNamed(CRATE_DEF_ID.to_def_id(), name) + + if let Some(lt_idx) = lifetime_idx { + if lt_idx > binder_level_idx { + let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name); + return tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + )); + } + } + + (name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)) } ty::BrNamed(def_id, kw::UnderscoreLifetime) => { let name = next_name(&self); - do_continue(&mut self, name); - ty::BrNamed(def_id, name) + + if let Some(lt_idx) = lifetime_idx { + if lt_idx > binder_level_idx { + let kind = ty::BrNamed(def_id, name); + return tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + )); + } + } + + (name, ty::BrNamed(def_id, name)) } ty::BrNamed(_, name) => { - do_continue(&mut self, name); - br.kind + if let Some(lt_idx) = lifetime_idx { + if lt_idx > binder_level_idx { + let kind = br.kind; + return tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + )); + } + } + + (name, br.kind) } }; + + start_or_continue(&mut self, "for<", ", "); + do_continue(&mut self, name); tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind })) }; let mut folder = RegionFolder { @@ -2273,29 +2365,37 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { Ok(inner) } - fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) + fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeVisitable<'tcx>, { - struct LateBoundRegionNameCollector<'a, 'tcx> { - used_region_names: &'a mut FxHashSet<Symbol>, + struct RegionNameCollector<'tcx> { + used_region_names: FxHashSet<Symbol>, type_collector: SsoHashSet<Ty<'tcx>>, } - impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { + impl<'tcx> RegionNameCollector<'tcx> { + fn new() -> Self { + RegionNameCollector { + used_region_names: Default::default(), + type_collector: SsoHashSet::new(), + } + } + } + + impl<'tcx> ty::visit::TypeVisitor<'tcx> for RegionNameCollector<'tcx> { type BreakTy = (); fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { trace!("address: {:p}", r.0.0); - if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { - self.used_region_names.insert(name); - } else if let ty::RePlaceholder(ty::PlaceholderRegion { - name: ty::BrNamed(_, name), - .. - }) = *r - { + + // Collect all named lifetimes. These allow us to prevent duplication + // of already existing lifetime names when introducing names for + // anonymous late-bound regions. + if let Some(name) = r.get_name() { self.used_region_names.insert(name); } + r.super_visit_with(self) } @@ -2311,12 +2411,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } } - self.used_region_names.clear(); - let mut collector = LateBoundRegionNameCollector { - used_region_names: &mut self.used_region_names, - type_collector: SsoHashSet::new(), - }; + let mut collector = RegionNameCollector::new(); value.visit_with(&mut collector); + self.used_region_names = collector.used_region_names; self.region_index = 0; } } @@ -2446,6 +2543,11 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { } } +#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct PrintClosureAsImpl<'tcx> { + pub closure: ty::ClosureSubsts<'tcx>, +} + forward_display_to_print! { ty::Region<'tcx>, Ty<'tcx>, @@ -2538,6 +2640,10 @@ define_print_and_forward_display! { p!(print(self.0.trait_ref.print_only_trait_path())); } + PrintClosureAsImpl<'tcx> { + p!(pretty_closure_as_impl(self.closure)) + } + ty::ParamTy { p!(write("{}", self.name)) } @@ -2567,9 +2673,9 @@ define_print_and_forward_display! { } ty::Term<'tcx> { - match self { - ty::Term::Ty(ty) => p!(print(ty)), - ty::Term::Const(c) => p!(print(c)), + match self.unpack() { + ty::TermKind::Ty(ty) => p!(print(ty)), + ty::TermKind::Const(c) => p!(print(c)), } } @@ -2609,8 +2715,8 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(uv) => { - p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated") + ty::PredicateKind::ConstEvaluatable(ct) => { + p!("the constant `", print(ct), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") @@ -2634,7 +2740,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); for id in hir.items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Use) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Use) { continue; } @@ -2643,7 +2749,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N continue; } - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); collect_fn(&item.ident, ns, def_id); } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2452bcf6a..ec90590ad 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -1,11 +1,11 @@ use crate::dep_graph; use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintLevelMap; +use crate::lint::LintExpectation; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; -use crate::middle::privacy::AccessLevels; +use crate::middle::privacy::EffectiveVisibilities; use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes}; use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; @@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::GeneratorDiagnosticData; -use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; @@ -40,17 +40,19 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; +use rustc_hir::hir_id::OwnerId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; -use rustc_session::utils::NativeLibKind; +use rustc_session::lint::LintExpectationId; use rustc_session::Limits; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -121,8 +123,8 @@ macro_rules! query_storage { ([][$K:ty, $V:ty]) => { <DefaultCacheSelector as CacheSelector<$K, $V>>::Cache }; - ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { - <$ty as CacheSelector<$K, $V>>::Cache + ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => { + <ArenaCacheSelector<'tcx> as CacheSelector<$K, $V>>::Cache }; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { query_storage!([$($modifiers)*][$($args)*]) @@ -173,7 +175,7 @@ macro_rules! opt_remap_env_constness { } macro_rules! define_callbacks { - (<$tcx:tt> + ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { @@ -187,33 +189,33 @@ macro_rules! define_callbacks { pub mod query_keys { use super::*; - $(pub type $name<$tcx> = $($K)*;)* + $(pub type $name<'tcx> = $($K)*;)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { use super::*; - $(pub type $name<$tcx> = $V;)* + $(pub type $name<'tcx> = $V;)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_storage { use super::*; - $(pub type $name<$tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)* + $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)* } #[allow(nonstandard_style, unused_lifetimes)] pub mod query_stored { use super::*; - $(pub type $name<$tcx> = <query_storage::$name<$tcx> as QueryStorage>::Stored;)* + $(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)* } #[derive(Default)] - pub struct QueryCaches<$tcx> { - $($(#[$attr])* pub $name: query_storage::$name<$tcx>,)* + pub struct QueryCaches<'tcx> { + $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* } - impl<$tcx> TyCtxtEnsure<$tcx> { + impl<'tcx> TyCtxtEnsure<'tcx> { $($(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { @@ -231,20 +233,20 @@ macro_rules! define_callbacks { })* } - impl<$tcx> TyCtxt<$tcx> { + impl<'tcx> TyCtxt<'tcx> { $($(#[$attr])* #[inline(always)] #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> { self.at(DUMMY_SP).$name(key) })* } - impl<$tcx> TyCtxtAt<$tcx> { + impl<'tcx> TyCtxtAt<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx> { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); @@ -275,8 +277,9 @@ macro_rules! define_callbacks { fn default() -> Self { Providers { $($name: |_, key| bug!( - "`tcx.{}({:?})` unsupported by its crate; \ - perhaps the `{}` query was never assigned a provider function", + "`tcx.{}({:?})` is not supported for external or local crate;\n + hint: Queries can be either made to the local crate, or the external crate. This error means you tried to use it for one that's not supported (likely the local crate).\n + If that's not the case, {} was likely never assigned to a provider function.\n", stringify!($name), key, stringify!($name), @@ -311,11 +314,11 @@ macro_rules! define_callbacks { $($(#[$attr])* fn $name( &'tcx self, - tcx: TyCtxt<$tcx>, + tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<$tcx>, + key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option<query_stored::$name<$tcx>>;)* + ) -> Option<query_stored::$name<'tcx>>;)* } }; } @@ -332,10 +335,10 @@ macro_rules! define_callbacks { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { [define_callbacks!][<'tcx>] } +rustc_query_append! { define_callbacks! } mod sealed { - use super::{DefId, LocalDefId}; + use super::{DefId, LocalDefId, OwnerId}; /// An analogue of the `Into` trait that's intended only for query parameters. /// @@ -365,6 +368,13 @@ mod sealed { self.to_def_id() } } + + impl IntoQueryParam<DefId> for OwnerId { + #[inline(always)] + fn into_query_param(self) -> DefId { + self.to_def_id() + } + } } use sealed::IntoQueryParam; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 818affa71..b25b4bd4f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -5,8 +5,8 @@ //! subtyping, type equality, etc. use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{GenericArg, GenericArgKind, SubstsRef}; use rustc_hir as ast; use rustc_hir::def_id::DefId; use rustc_span::DUMMY_SP; @@ -441,7 +441,9 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { + (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate_with_variance( ty::Contravariant, @@ -450,7 +452,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_region, ) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) + Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) @@ -572,8 +574,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( /// it. pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, + mut a: ty::Const<'tcx>, + mut b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); @@ -594,9 +596,16 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( ); } - let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env()); - let a = eagerly_eval(a); - let b = eagerly_eval(b); + // HACK(const_generics): We still need to eagerly evaluate consts when + // relating them because during `normalize_param_env_or_error`, + // we may relate an evaluated constant in a obligation against + // an unnormalized (i.e. unevaluated) const in the param-env. + // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants + // these `eval` calls can be removed. + if !relation.tcx().features().generic_const_exprs { + a = a.eval(tcx, relation.param_env()); + b = b.eval(tcx, relation.param_env()); + } // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -617,15 +626,13 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if tcx.features().generic_const_exprs => { - tcx.try_unify_abstract_consts(relation.param_env().and((au.shrink(), bu.shrink()))) + tcx.try_unify_abstract_consts(relation.param_env().and((au, bu))) } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can // be stabilized. - (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) - if au.def == bu.def && au.promoted == bu.promoted => - { + (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { let substs = relation.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), @@ -633,11 +640,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( bu.substs, )?; return Ok(tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(ty::Unevaluated { - def: au.def, - substs, - promoted: au.promoted, - }), + kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: au.def, substs }), ty: a.ty(), })); } @@ -803,15 +806,15 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Term<'tcx> { +impl<'tcx> Relate<'tcx> for Term<'tcx> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { - Ok(match (a, b) { - (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(), - (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(), + Ok(match (a.unpack(), b.unpack()) { + (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index e86dafae3..e79b79a25 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; /// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by -/// rules laid out in `rustc_typeck::check::rvalue_scopes`. +/// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`. #[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)] pub struct RvalueScopes { map: FxHashMap<hir::ItemLocalId, Option<Scope>>, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7660a2f3a..2cad333e3 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -3,13 +3,12 @@ //! hand, though we've recently added some macros and proc-macros to help with the tedium. use crate::mir::interpret; -use crate::mir::ProjectionKind; +use crate::mir::{Field, ProjectionKind}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; -use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; @@ -167,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(uv) => { - write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs) + ty::PredicateKind::ConstEvaluatable(ct) => { + write!(f, "ConstEvaluatable({ct:?})") } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::TypeWellFormedFromEnv(ty) => { @@ -238,12 +237,24 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::Variance, ::rustc_span::Span, ::rustc_errors::ErrorGuaranteed, + Field, + interpret::Scalar, + rustc_target::abi::Size, + ty::DelaySpanBugEmitted, + rustc_type_ir::DebruijnIndex, + ty::BoundVar, + ty::Placeholder<ty::BoundVar>, +} + +TrivialTypeTraversalAndLiftImpls! { + for<'tcx> { + ty::ValTree<'tcx>, + } } /////////////////////////////////////////////////////////////////////////// // Lift implementations -// FIXME(eddyb) replace all the uses of `Option::map` with `?`. impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { type Lifted = (A::Lifted, B::Lifted); fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { @@ -261,10 +272,10 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> { type Lifted = Option<T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - Some(x) => tcx.lift(x).map(Some), - None => Some(None), - } + Some(match self { + Some(x) => Some(tcx.lift(x)?), + None => None, + }) } } @@ -281,21 +292,21 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> { type Lifted = Box<T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(*self).map(Box::new) + Some(Box::new(tcx.lift(*self)?)) } } impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> { type Lifted = Rc<T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.as_ref().clone()).map(Rc::new) + Some(Rc::new(tcx.lift(self.as_ref().clone())?)) } } impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> { type Lifted = Arc<T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.as_ref().clone()).map(Arc::new) + Some(Arc::new(tcx.lift(self.as_ref().clone())?)) } } impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> { @@ -312,159 +323,18 @@ impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { - type Lifted = ty::TraitRef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { - type Lifted = ty::ExistentialTraitRef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> { - type Lifted = ty::ExistentialPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::ExistentialPredicate::Trait(x) => tcx.lift(x).map(ty::ExistentialPredicate::Trait), - ty::ExistentialPredicate::Projection(x) => { - tcx.lift(x).map(ty::ExistentialPredicate::Projection) - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - Some(ty::ExistentialPredicate::AutoTrait(def_id)) - } - } - } -} - impl<'a, 'tcx> Lift<'tcx> for Term<'a> { type Lifted = ty::Term<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - Some(match self { - Term::Ty(ty) => Term::Ty(tcx.lift(ty)?), - Term::Const(c) => Term::Const(tcx.lift(c)?), - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { - type Lifted = ty::TraitPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> { - tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref, - constness: self.constness, - polarity: self.polarity, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { - type Lifted = ty::SubtypePredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::SubtypePredicate<'tcx>> { - tcx.lift((self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a, - b, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> { - type Lifted = ty::CoercePredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> { - tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b }) - } -} - -impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> { - type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift((self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b)) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> { - type Lifted = ty::ProjectionTy<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> { - tcx.lift(self.substs) - .map(|substs| ty::ProjectionTy { item_def_id: self.item_def_id, substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { - type Lifted = ty::ProjectionPredicate<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> { - tcx.lift((self.projection_ty, self.term)) - .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { - type Lifted = ty::ExistentialProjection<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.substs).map(|substs| ty::ExistentialProjection { - substs, - term: tcx.lift(self.term).expect("type must lift when substs do"), - item_def_id: self.item_def_id, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { - type Lifted = ty::PredicateKind<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait), - ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype), - ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce), - ty::PredicateKind::RegionOutlives(data) => { - tcx.lift(data).map(ty::PredicateKind::RegionOutlives) - } - ty::PredicateKind::TypeOutlives(data) => { - tcx.lift(data).map(ty::PredicateKind::TypeOutlives) - } - ty::PredicateKind::Projection(data) => { - tcx.lift(data).map(ty::PredicateKind::Projection) - } - ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed), - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { - tcx.lift(closure_substs).map(|closure_substs| { - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) - }) + Some( + match self.unpack() { + TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?), + TermKind::Const(c) => TermKind::Const(tcx.lift(c)?), } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - Some(ty::PredicateKind::ObjectSafe(trait_def_id)) - } - ty::PredicateKind::ConstEvaluatable(uv) => { - tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv)) - } - ty::PredicateKind::ConstEquate(c1, c2) => { - tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) - } - ty::PredicateKind::TypeWellFormedFromEnv(ty) => { - tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv) - } - } - } -} - -impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T> -where - <T as Lift<'tcx>>::Lifted: TypeVisitable<'tcx>, -{ - type Lifted = ty::Binder<'tcx, T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - let bound_vars = tcx.lift(self.bound_vars()); - tcx.lift(self.skip_binder()) - .zip(bound_vars) - .map(|(value, vars)| ty::Binder::bind_with_vars(value, vars)) + .pack(), + ) } } - impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { @@ -473,178 +343,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { } } -impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> { - type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.param_env).and_then(|param_env| { - tcx.lift(self.value).map(|value| ty::ParamEnvAnd { param_env, value }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { - type Lifted = ty::ClosureSubsts<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.substs).map(|substs| ty::ClosureSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> { - type Lifted = ty::GeneratorSubsts<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.substs).map(|substs| ty::GeneratorSubsts { substs }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { - type Lifted = ty::adjustment::Adjustment<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - let ty::adjustment::Adjustment { kind, target } = self; - tcx.lift(kind).and_then(|kind| { - tcx.lift(target).map(|target| ty::adjustment::Adjustment { kind, target }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { - type Lifted = ty::adjustment::Adjust<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::adjustment::Adjust::NeverToAny => Some(ty::adjustment::Adjust::NeverToAny), - ty::adjustment::Adjust::Pointer(ptr) => Some(ty::adjustment::Adjust::Pointer(ptr)), - ty::adjustment::Adjust::Deref(overloaded) => { - tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref) - } - ty::adjustment::Adjust::Borrow(autoref) => { - tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow) - } - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { - type Lifted = ty::adjustment::OverloadedDeref<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.region).map(|region| ty::adjustment::OverloadedDeref { - region, - mutbl: self.mutbl, - span: self.span, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { - type Lifted = ty::adjustment::AutoBorrow<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::adjustment::AutoBorrow::Ref(r, m) => { - tcx.lift(r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m)) - } - ty::adjustment::AutoBorrow::RawPtr(m) => Some(ty::adjustment::AutoBorrow::RawPtr(m)), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { - type Lifted = ty::GenSig<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift((self.resume_ty, self.yield_ty, self.return_ty)) - .map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { - type Lifted = ty::FnSig<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.inputs_and_output).map(|x| ty::FnSig { - inputs_and_output: x, - c_variadic: self.c_variadic, - unsafety: self.unsafety, - abi: self.abi, - }) - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> { - type Lifted = ty::error::ExpectedFound<T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - let ty::error::ExpectedFound { expected, found } = self; - tcx.lift(expected).and_then(|expected| { - tcx.lift(found).map(|found| ty::error::ExpectedFound { expected, found }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { - type Lifted = ty::error::TypeError<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - use crate::ty::error::TypeError::*; - - Some(match self { - Mismatch => Mismatch, - ConstnessMismatch(x) => ConstnessMismatch(x), - PolarityMismatch(x) => PolarityMismatch(x), - UnsafetyMismatch(x) => UnsafetyMismatch(x), - AbiMismatch(x) => AbiMismatch(x), - Mutability => Mutability, - ArgumentMutability(i) => ArgumentMutability(i), - TupleSize(x) => TupleSize(x), - FixedArraySize(x) => FixedArraySize(x), - ArgCount => ArgCount, - FieldMisMatch(x, y) => FieldMisMatch(x, y), - RegionsDoesNotOutlive(a, b) => { - return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)); - } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(b).map(|b| RegionsInsufficientlyPolymorphic(a, b)); - } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(b).map(|b| RegionsOverlyPolymorphic(a, b)); - } - RegionsPlaceholderMismatch => RegionsPlaceholderMismatch, - IntMismatch(x) => IntMismatch(x), - FloatMismatch(x) => FloatMismatch(x), - Traits(x) => Traits(x), - VariadicMismatch(x) => VariadicMismatch(x), - CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)), - CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)), - ProjectionMismatched(x) => ProjectionMismatched(x), - ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)), - Sorts(x) => return tcx.lift(x).map(Sorts), - ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch), - ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch), - IntrinsicCast => IntrinsicCast, - TargetFeatureCast(x) => TargetFeatureCast(x), - ObjectUnsafeCoercion(x) => return tcx.lift(x).map(ObjectUnsafeCoercion), - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { - type Lifted = ty::InstanceDef<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - match self { - ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)), - ty::InstanceDef::VTableShim(def_id) => Some(ty::InstanceDef::VTableShim(def_id)), - ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)), - ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)), - ty::InstanceDef::FnPtrShim(def_id, ty) => { - Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller }) - } - ty::InstanceDef::DropGlue(def_id, ty) => { - Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) - } - ty::InstanceDef::CloneShim(def_id, ty) => { - Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)) - } - } - } -} - /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. @@ -844,27 +542,21 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> { } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|t| t.try_fold_with(folder)) - } -} - -impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> { +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &[T] { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> { +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_bound(|ty| ty.try_fold_with(folder)) + self.try_map_id(|t| t.try_fold_with(folder)) } } -impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::EarlyBinder<T> { +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.as_ref().0.visit_with(visitor) + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -901,88 +593,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia } } -impl<'tcx> TypeVisitable<'tcx> - for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> -{ - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|p| p.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ProjectionKind> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - use crate::ty::InstanceDef::*; - Ok(Self { - substs: self.substs.try_fold_with(folder)?, - def: match self.def { - Item(def) => Item(def.try_fold_with(folder)?), - VTableShim(did) => VTableShim(did.try_fold_with(folder)?), - ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?), - Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?), - FnPtrShim(did, ty) => { - FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i), - ClosureOnceShim { call_once, track_caller } => { - ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller } - } - DropGlue(did, ty) => { - DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - CloneShim(did, ty) => { - CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?) - } - }, - }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - use crate::ty::InstanceDef::*; - self.substs.visit_with(visitor)?; - match self.def { - Item(def) => def.visit_with(visitor), - VTableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { - did.visit_with(visitor) - } - FnPtrShim(did, ty) | CloneShim(did, ty) => { - did.visit_with(visitor)?; - ty.visit_with(visitor) - } - DropGlue(did, ty) => { - did.visit_with(visitor)?; - ty.visit_with(visitor) - } - ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor), - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.instance.visit_with(visitor) - } -} - impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_ty(self) @@ -1005,9 +621,11 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?), ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), - ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) - } + ty::Dynamic(trait_ty, region, representation) => ty::Dynamic( + trait_ty.try_fold_with(folder)?, + region.try_fold_with(folder)?, + representation, + ), ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), @@ -1051,7 +669,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg) => { + ty::Dynamic(ref trait_ty, ref reg, _) => { trait_ty.visit_with(visitor)?; reg.visit_with(visitor) } @@ -1156,12 +774,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|p| p.visit_with(visitor)) - } -} - impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|x| x.try_fold_with(folder)) @@ -1208,34 +820,6 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - Ok(match self { - ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?), - ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?), - ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ty::ConstKind::Value(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) - | ty::ConstKind::Error(_) => self, - }) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - match *self { - ty::ConstKind::Infer(ic) => ic.visit_with(visitor), - ty::ConstKind::Param(p) => p.visit_with(visitor), - ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ty::ConstKind::Value(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Error(_) => ControlFlow::CONTINUE, - } - } -} - impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> { Ok(self) @@ -1248,57 +832,8 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - folder.try_fold_unevaluated(self) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - visitor.visit_unevaluated(*self) - } -} - -impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> { - fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(ty::Unevaluated { - def: self.def, - substs: self.substs.try_fold_with(folder)?, - promoted: self.promoted, - }) - } -} - -impl<'tcx> TypeSuperVisitable<'tcx> for ty::Unevaluated<'tcx> { +impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.substs.visit_with(visitor) } } - -impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - Ok(self.expand().try_fold_with(folder)?.shrink()) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.expand().visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for hir::Constness { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { - Ok(self) - } -} - -impl<'tcx> TypeVisitable<'tcx> for hir::Constness { - fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52c3a3886..cf420bafe 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -3,7 +3,7 @@ #![allow(rustc::usage_of_ty_tykind)] use crate::infer::canonical::Canonical; -use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ @@ -11,6 +11,7 @@ use crate::ty::{ TypeVisitor, }; use crate::ty::{List, ParamEnv}; +use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; @@ -18,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_macros::HashStable; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi; use std::borrow::Cow; @@ -84,6 +85,17 @@ impl BoundRegionKind { _ => false, } } + + pub fn get_name(&self) -> Option<Symbol> { + if self.is_named() { + match *self { + BoundRegionKind::BrNamed(_, name) => return Some(name), + _ => unreachable!(), + } + } + + None + } } pub trait Article { @@ -201,7 +213,7 @@ static_assert_size!(TyKind<'_>, 32); /// * `GR`: The "return type", which is the type of value returned upon /// completion of the generator. /// * `GW`: The "generator witness". -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with a tuple containing the types of the upvars. @@ -303,7 +315,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// closure. // FIXME(eddyb) this should be unnecessary, as the shallowly resolved // type is known at the time of the creation of `ClosureSubsts`, - // see `rustc_typeck::check::closure`. + // see `rustc_hir_analysis::check::closure`. pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> { self.split().closure_sig_as_fn_ptr_ty.expect_ty() } @@ -325,10 +337,14 @@ impl<'tcx> ClosureSubsts<'tcx> { _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()), } } + + pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> { + ty::print::PrintClosureAsImpl { closure: self } + } } /// Similar to `ClosureSubsts`; see the above documentation for more. -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } @@ -546,7 +562,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { layout.variant_fields.iter().map(move |variant| { variant .iter() - .map(move |field| EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs)) + .map(move |field| ty::EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs)) }) } @@ -655,7 +671,7 @@ impl<'tcx> InlineConstSubsts<'tcx> { } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum ExistentialPredicate<'tcx> { /// E.g., `Iterator`. Trait(ExistentialTraitRef<'tcx>), @@ -687,6 +703,9 @@ impl<'tcx> ExistentialPredicate<'tcx> { } impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> { + /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example). pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { @@ -781,7 +800,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> { /// Trait references also appear in object types like `Foo<U>`, but in /// that case the `Self` parameter is absent from the substitutions. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -845,6 +864,12 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) @@ -853,7 +878,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -901,73 +926,6 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder<T>(pub T); - -impl<T> EarlyBinder<T> { - pub fn as_ref(&self) -> EarlyBinder<&T> { - EarlyBinder(&self.0) - } - - pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U> - where - F: FnOnce(&T) -> U, - { - self.as_ref().map_bound(f) - } - - pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U> - where - F: FnOnce(T) -> U, - { - let value = f(self.0); - EarlyBinder(value) - } - - pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E> - where - F: FnOnce(T) -> Result<U, E>, - { - let value = f(self.0)?; - Ok(EarlyBinder(value)) - } - - pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { - EarlyBinder(value) - } -} - -impl<T> EarlyBinder<Option<T>> { - pub fn transpose(self) -> Option<EarlyBinder<T>> { - self.0.map(|v| EarlyBinder(v)) - } -} - -impl<T, U> EarlyBinder<(T, U)> { - pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) { - (EarlyBinder(self.0.0), EarlyBinder(self.0.1)) - } -} - -pub struct EarlyBinderIter<T> { - t: T, -} - -impl<T: IntoIterator> EarlyBinder<T> { - pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> { - EarlyBinderIter { t: self.0.into_iter() } - } -} - -impl<T: Iterator> Iterator for EarlyBinderIter<T> { - type Item = EarlyBinder<T::Item>; - - fn next(&mut self) -> Option<Self::Item> { - self.t.next().map(|i| EarlyBinder(i)) - } -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { @@ -1009,7 +967,7 @@ impl BoundVariableKind { /// /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(HashStable)] +#[derive(HashStable, Lift)] pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>); impl<'tcx, T> Binder<'tcx, T> @@ -1171,7 +1129,7 @@ impl<'tcx, T> Binder<'tcx, Option<T>> { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `<T as Trait<..>>::N`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: SubstsRef<'tcx>, @@ -1186,7 +1144,13 @@ pub struct ProjectionTy<'tcx> { impl<'tcx> ProjectionTy<'tcx> { pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { - tcx.parent(self.item_def_id) + match tcx.def_kind(self.item_def_id) { + DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.item_def_id), + DefKind::ImplTraitPlaceholder => { + tcx.parent(tcx.impl_trait_in_trait_parent(self.item_def_id)) + } + kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"), + } } /// Extracts the underlying trait reference and own substs from this projection. @@ -1197,6 +1161,7 @@ impl<'tcx> ProjectionTy<'tcx> { tcx: TyCtxt<'tcx>, ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { let def_id = tcx.parent(self.item_def_id); + assert_eq!(tcx.def_kind(def_id), DefKind::Trait); let trait_generics = tcx.generics_of(def_id); ( ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) }, @@ -1221,7 +1186,7 @@ impl<'tcx> ProjectionTy<'tcx> { } } -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, @@ -1237,7 +1202,7 @@ pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>; /// - `output`: is the return type. /// - `c_variadic`: indicates whether this is a C-variadic function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List<Ty<'tcx>>, pub c_variadic: bool, @@ -1419,7 +1384,7 @@ impl From<BoundVar> for BoundTy { /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialProjection<'tcx> { pub item_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -1492,6 +1457,23 @@ impl<'tcx> Region<'tcx> { *self.0.0 } + pub fn get_name(self) -> Option<Symbol> { + if self.has_name() { + let name = match *self { + ty::ReEarlyBound(ebr) => Some(ebr.name), + ty::ReLateBound(_, br) => br.kind.get_name(), + ty::ReFree(fr) => fr.bound_region.get_name(), + ty::ReStatic => Some(kw::StaticLifetime), + ty::RePlaceholder(placeholder) => placeholder.name.get_name(), + _ => None, + }; + + return name; + } + + None + } + /// Is this region named by the user? pub fn has_name(self) -> bool { match *self { @@ -1501,7 +1483,6 @@ impl<'tcx> Region<'tcx> { ty::ReStatic => true, ty::ReVar(..) => false, ty::RePlaceholder(placeholder) => placeholder.name.is_named(), - ty::ReEmpty(_) => false, ty::ReErased => false, } } @@ -1527,11 +1508,6 @@ impl<'tcx> Region<'tcx> { } #[inline] - pub fn is_empty(self) -> bool { - matches!(*self, ty::ReEmpty(..)) - } - - #[inline] pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, @@ -1562,7 +1538,7 @@ impl<'tcx> Region<'tcx> { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; } - ty::ReEmpty(_) | ty::ReStatic => { + ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } ty::ReLateBound(..) => { @@ -1617,6 +1593,10 @@ impl<'tcx> Region<'tcx> { _ => self.is_free(), } } + + pub fn is_var(self) -> bool { + matches!(self.kind(), ty::ReVar(_)) + } } /// Type utilities @@ -1838,7 +1818,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_trait(self) -> bool { - matches!(self.kind(), Dynamic(..)) + matches!(self.kind(), Dynamic(_, _, ty::Dyn)) + } + + #[inline] + pub fn is_dyn_star(self) -> bool { + matches!(self.kind(), Dynamic(_, _, ty::DynStar)) } #[inline] @@ -2137,7 +2122,7 @@ impl<'tcx> Ty<'tcx> { /// /// Note that during type checking, we use an inference variable /// to represent the closure kind, because it has not yet been - /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`) + /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`) /// is complete, that type variable will be unified. pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> { match self.kind() { @@ -2220,7 +2205,10 @@ impl<'tcx> Ty<'tcx> { // These aren't even `Clone` ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false, - ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, + ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_)) + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) => true, // The voldemort ZSTs are fine. ty::FnDef(..) => true, @@ -2255,6 +2243,35 @@ impl<'tcx> Ty<'tcx> { } } } + + // If `self` is a primitive, return its [`Symbol`]. + pub fn primitive_symbol(self) -> Option<Symbol> { + match self.kind() { + ty::Bool => Some(sym::bool), + ty::Char => Some(sym::char), + ty::Float(f) => match f { + ty::FloatTy::F32 => Some(sym::f32), + ty::FloatTy::F64 => Some(sym::f64), + }, + ty::Int(f) => match f { + ty::IntTy::Isize => Some(sym::isize), + ty::IntTy::I8 => Some(sym::i8), + ty::IntTy::I16 => Some(sym::i16), + ty::IntTy::I32 => Some(sym::i32), + ty::IntTy::I64 => Some(sym::i64), + ty::IntTy::I128 => Some(sym::i128), + }, + ty::Uint(f) => match f { + ty::UintTy::Usize => Some(sym::usize), + ty::UintTy::U8 => Some(sym::u8), + ty::UintTy::U16 => Some(sym::u16), + ty::UintTy::U32 => Some(sym::u32), + ty::UintTy::U64 => Some(sym::u64), + ty::UintTy::U128 => Some(sym::u128), + }, + _ => None, + } + } } /// Extra information about why we ended up with a particular variance. diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 6262aa180..0660e9b79 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -1,12 +1,12 @@ // Type substitutions. -use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; +use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -189,6 +189,14 @@ impl<'tcx> GenericArg<'tcx> { _ => bug!("expected a const, but found another kind"), } } + + pub fn is_non_region_infer(self) -> bool { + match self.unpack() { + GenericArgKind::Lifetime(_) => false, + GenericArgKind::Type(ty) => ty.is_ty_infer(), + GenericArgKind::Const(ct) => ct.is_ct_infer(), + } + } } impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { @@ -459,12 +467,6 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } -impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { // This code is fairly hot, though not as hot as `SubstsRef`. @@ -497,24 +499,108 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { } } -impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<Ty<'tcx>> { +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> { + #[inline] fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } } -// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`. -#[rustc_on_unimplemented(message = "Calling `subst` must now be done through an `EarlyBinder`")] -pub trait Subst<'tcx>: Sized { - type Inner; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Encodable, Decodable, HashStable)] +pub struct EarlyBinder<T>(pub T); + +/// For early binders, you should first call `subst` before using any visitors. +impl<'tcx, T> !TypeFoldable<'tcx> for ty::EarlyBinder<T> {} +impl<'tcx, T> !TypeVisitable<'tcx> for ty::EarlyBinder<T> {} + +impl<T> EarlyBinder<T> { + pub fn as_ref(&self) -> EarlyBinder<&T> { + EarlyBinder(&self.0) + } + + pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U> + where + F: FnOnce(&T) -> U, + { + self.as_ref().map_bound(f) + } + + pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U> + where + F: FnOnce(T) -> U, + { + let value = f(self.0); + EarlyBinder(value) + } + + pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E> + where + F: FnOnce(T) -> Result<U, E>, + { + let value = f(self.0)?; + Ok(EarlyBinder(value)) + } + + pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { + EarlyBinder(value) + } +} + +impl<T> EarlyBinder<Option<T>> { + pub fn transpose(self) -> Option<EarlyBinder<T>> { + self.0.map(|v| EarlyBinder(v)) + } +} + +impl<T, U> EarlyBinder<(T, U)> { + pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) { + (EarlyBinder(self.0.0), EarlyBinder(self.0.1)) + } +} - fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner; +impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> { + pub fn subst_iter( + self, + tcx: TyCtxt<'tcx>, + substs: &'s [GenericArg<'tcx>], + ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> { + self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs)) + } } -impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder<T> { - type Inner = T; +impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a> + EarlyBinder<T> +{ + pub fn subst_iter_copied( + self, + tcx: TyCtxt<'tcx>, + substs: &'s [GenericArg<'tcx>], + ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> { + self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs)) + } +} + +pub struct EarlyBinderIter<T> { + t: T, +} + +impl<T: IntoIterator> EarlyBinder<T> { + pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> { + EarlyBinderIter { t: self.0.into_iter() } + } +} - fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner { +impl<T: Iterator> Iterator for EarlyBinderIter<T> { + type Item = EarlyBinder<T::Item>; + + fn next(&mut self) -> Option<Self::Item> { + self.t.next().map(|i| EarlyBinder(i)) + } +} + +impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> { + pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T { let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; self.0.fold_with(&mut folder) } @@ -550,9 +636,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { #[cold] #[inline(never)] - fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! { + fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! { + bug!( + "Region parameter out of range when substituting in region {} (index={}, substs = {:?})", + data.name, + data.index, + substs, + ) + } + + #[cold] + #[inline(never)] + fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! { bug!( - "Region parameter out of range when substituting in region {} (index={})", + "Unexpected parameter {:?} when substituting in region {} (index={})", + other, data.name, data.index ) @@ -568,7 +666,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { let rk = self.substs.get(data.index as usize).map(|k| k.unpack()); match rk { Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), - _ => region_param_out_of_range(data), + Some(other) => region_param_invalid(data, other), + None => region_param_out_of_range(data, self.substs), } } _ => r, @@ -593,11 +692,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { c.super_fold_with(self) } } - - #[inline] - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { - c.super_fold_with(self) - } } impl<'a, 'tcx> SubstFolder<'a, 'tcx> { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 541dace5c..ac79949fc 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -256,7 +256,6 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } // Query provider for `incoherent_impls`. -#[instrument(level = "debug", skip(tcx))] pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let mut impls = Vec::new(); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 591bb7831..f72e236ed 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,12 +2,11 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::layout::IntegerExt; -use crate::ty::query::TyCtxtAt; -use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::{ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, }; +use crate::ty::{GenericArgKind, SubstsRef}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -627,7 +626,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Expands the given impl trait type, stopping if the type is recursive. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -644,7 +643,6 @@ impl<'tcx> TyCtxt<'tcx> { }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); - trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } @@ -652,6 +650,13 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.type_of(def_id)) } + pub fn bound_trait_impl_trait_tys( + self, + def_id: DefId, + ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> { + ty::EarlyBinder(self.collect_trait_impl_trait_tys(def_id)) + } + pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> { ty::EarlyBinder(self.fn_sig(def_id)) } @@ -815,12 +820,8 @@ impl<'tcx> Ty<'tcx> { /// does copies even when the type actually doesn't satisfy the /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. - pub fn is_copy_modulo_regions( - self, - tcx_at: TyCtxtAt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self)) + pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self)) } /// Checks whether values of this type `T` have a size known at @@ -829,8 +830,8 @@ impl<'tcx> Ty<'tcx> { /// over-approximation in generic contexts, where one can have /// strange rules like `<T as Foo<'static>>::Bar: Sized` that /// actually carry lifetime requirements. - pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) + pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -840,8 +841,8 @@ impl<'tcx> Ty<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self)) + pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self)) } /// Fast path helper for testing if a type is `Freeze`. @@ -880,8 +881,8 @@ impl<'tcx> Ty<'tcx> { } /// Checks whether values of this type `T` implement the `Unpin` trait. - pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self)) + pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self)) } /// Fast path helper for testing if a type is `Unpin`. @@ -952,7 +953,7 @@ impl<'tcx> Ty<'tcx> { } } - /// Checks if `ty` has has a significant drop. + /// Checks if `ty` has a significant drop. /// /// Note that this method can return false even if `ty` has a destructor /// attached; even if that is the case then the adt has been marked with @@ -1283,12 +1284,24 @@ pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) } +/// Determines whether an item is annotated with `doc(notable_trait)`. +pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.get_attrs(def_id, sym::doc) + .filter_map(|attr| attr.meta_item_list()) + .any(|items| items.iter().any(|item| item.has_name(sym::notable_trait))) +} + /// Determines whether an item is an intrinsic by Abi. pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } pub fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers } + *providers = ty::query::Providers { + normalize_opaque_types, + is_doc_hidden, + is_doc_notable_trait, + is_intrinsic, + ..*providers + } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 536506720..c09f71f9a 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -10,8 +10,7 @@ //! //! There are three groups of traits involved in each traversal. //! - `TypeVisitable`. This is implemented once for many types, including: -//! - Types of interest, for which the the methods delegate to the -//! visitor. +//! - Types of interest, for which the methods delegate to the visitor. //! - All other types, including generic containers like `Vec` and `Option`. //! It defines a "skeleton" of how they should be visited. //! - `TypeSuperVisitable`. This is implemented only for each type of interest, @@ -39,7 +38,6 @@ //! - ty.super_visit_with(visitor) //! - u.visit_with(visitor) //! ``` -use crate::mir; use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; use rustc_errors::ErrorGuaranteed; @@ -84,7 +82,7 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { self.has_vars_bound_at_or_above(ty::INNERMOST) } - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } @@ -104,8 +102,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { None } } - fn has_param_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) + fn has_non_region_param(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM) } fn has_infer_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_INFER) @@ -113,8 +111,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { fn has_infer_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER) } - fn has_infer_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) + fn has_non_region_infer(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER) } fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_INFER) @@ -199,17 +197,9 @@ pub trait TypeVisitor<'tcx>: Sized { c.super_visit_with(self) } - fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { - uv.super_visit_with(self) - } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { p.super_visit_with(self) } - - fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> { - c.super_visit_with(self) - } } /////////////////////////////////////////////////////////////////////////// @@ -560,7 +550,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = t.flags(); trace!(t.flags=?t.flags()); @@ -572,7 +562,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = r.type_flags(); trace!(r.flags=?flags); @@ -584,7 +574,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = FlagComputation::for_const(c); trace!(r.flags=?flags); @@ -596,19 +586,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] - fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { - let flags = FlagComputation::for_unevaluated_const(uv); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", @@ -666,7 +644,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { - if let ty::Projection(..) = t.kind() { + if let ty::Projection(..) | ty::Opaque(..) = t.kind() { return ControlFlow::CONTINUE; } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 04a9fd1f7..5ca51c25a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::fmt; -use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit}; +use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; @@ -87,7 +87,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = ty::Instance::resolve_drop_in_place(tcx, ty); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(), VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(), @@ -97,14 +97,14 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = instance.polymorphize(tcx); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::TraitVPtr(trait_ref) => { let super_trait_ref = trait_ref .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref))); let vptr = Pointer::from(supertrait_alloc_id); - ScalarMaybeUninit::from_pointer(vptr, &tcx) + Scalar::from_pointer(vptr, &tcx) } }; vtable diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 02fe1f3a7..91db9698c 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> { } } +impl<'tcx> ty::Const<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker<'tcx> { + TypeWalker::new(self.into()) + } +} + /// We push `GenericArg`s on the stack in reverse order so as to /// maintain a pre-order traversal. As of the time of this /// writing, the fact that the traversal is pre-order is not @@ -152,7 +168,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Projection(data) => { stack.extend(data.substs.iter().rev()); } - ty::Dynamic(obj, lt) => { + ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); stack.extend(obj.iter().rev().flat_map(|predicate| { let (substs, opt_ty) = match predicate.skip_binder() { @@ -165,9 +181,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }; - substs.iter().rev().chain(opt_ty.map(|term| match term { - ty::Term::Ty(ty) => ty.into(), - ty::Term::Const(ct) => ct.into(), + substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(ct) => ct.into(), })) })); } |