diff options
Diffstat (limited to 'compiler/rustc_middle/src')
28 files changed, 262 insertions, 498 deletions
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8e1cb6a514f..e7d9dc04886 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -617,7 +617,7 @@ impl<'hir> Map<'hir> { Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) - | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. }) + | Node::Expr(Expr { kind: ExprKind::Closure(_), .. }) | Node::ImplItem(_) // The input node `id` must be enclosed in the method's body as opposed // to some other place such as its return type (fixes #114918). diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 2aaece1060a..9c0846e9fb1 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -34,6 +34,7 @@ #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(coroutines)] +#![feature(generic_nonzero)] #![feature(if_let_guard)] #![feature(inline_const)] #![feature(iter_from_coroutine)] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 6ffa0819f35..2a6f473cd32 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -207,6 +207,11 @@ pub fn explain_lint_level_source( err: &mut Diagnostic, ) { let name = lint.name_lower(); + if let Level::Allow = level { + // Do not point at `#[allow(compat_lint)]` as the reason for a compatibility lint + // triggering. (#121009) + return; + } match src { LintLevelSource::Default => { err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name)); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index afb6937b43b..2f624ab0527 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -21,7 +21,7 @@ use rustc_session::parse::feature_err_issue; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use std::num::NonZeroU32; +use std::num::NonZero; #[derive(PartialEq, Clone, Copy, Debug)] pub enum StabilityLevel { @@ -102,7 +102,7 @@ pub fn report_unstable( sess: &Session, feature: Symbol, reason: Option<Symbol>, - issue: Option<NonZeroU32>, + issue: Option<NonZero<u32>>, suggestion: Option<(Span, String, String, Applicability)>, is_soft: bool, span: Span, @@ -235,7 +235,7 @@ pub enum EvalResult { Deny { feature: Symbol, reason: Option<Symbol>, - issue: Option<NonZeroU32>, + issue: Option<NonZero<u32>>, suggestion: Option<(Span, String, String, Applicability)>, is_soft: bool, }, @@ -433,7 +433,7 @@ impl<'tcx> TyCtxt<'tcx> { // the `-Z force-unstable-if-unmarked` flag present (we're // compiling a compiler crate), then let this missing feature // annotation slide. - if feature == sym::rustc_private && issue == NonZeroU32::new(27812) { + if feature == sym::rustc_private && issue == NonZero::new(27812) { if self.sess.opts.unstable_opts.force_unstable_if_unmarked { return EvalResult::Allow; } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index a1cdc794749..125fac48df8 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, AllocRange, Pointer, Scalar}; +use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; @@ -12,6 +12,7 @@ use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; +use rustc_type_ir::Mutability; use std::borrow::Cow; use std::{any::Any, backtrace::Backtrace, fmt}; @@ -83,6 +84,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo { TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; +pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; /// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. /// This is needed in `thir::pattern::lower_inline_const`. @@ -366,7 +368,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { #[derive(Debug, Clone, Copy)] pub enum PointerKind { - Ref, + Ref(Mutability), Box, } @@ -374,7 +376,7 @@ impl IntoDiagnosticArg for PointerKind { fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str( match self { - Self::Ref => "ref", + Self::Ref(_) => "ref", Self::Box => "box", } .into(), @@ -407,7 +409,7 @@ impl From<PointerKind> for ExpectedKind { fn from(x: PointerKind) -> ExpectedKind { match x { PointerKind::Box => ExpectedKind::Box, - PointerKind::Ref => ExpectedKind::Reference, + PointerKind::Ref(_) => ExpectedKind::Reference, } } } @@ -418,7 +420,7 @@ pub enum ValidationErrorKind<'tcx> { PartialPointer, PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, PtrToStatic { ptr_kind: PointerKind }, - MutableRefInConst, + MutableRefInConstOrStatic, ConstRefToMutable, ConstRefToExtern, MutableRefToImmutable, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 0da3524e055..5be09b06d9e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -122,7 +122,7 @@ mod value; use std::fmt; use std::io; use std::io::{Read, Write}; -use std::num::{NonZeroU32, NonZeroU64}; +use std::num::NonZero; use std::sync::atomic::{AtomicU32, Ordering}; use rustc_ast::LitKind; @@ -142,11 +142,12 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, - EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, - ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, }; pub use self::value::Scalar; @@ -205,7 +206,7 @@ pub enum LitToConstError { } #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct AllocId(pub NonZeroU64); +pub struct AllocId(pub NonZero<u64>); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. @@ -260,7 +261,7 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>( } // Used to avoid infinite recursion when decoding cyclic allocations. -type DecodingSessionId = NonZeroU32; +type DecodingSessionId = NonZero<u32>; #[derive(Clone)] enum State { @@ -500,7 +501,7 @@ impl<'tcx> AllocMap<'tcx> { AllocMap { alloc_map: Default::default(), dedup: Default::default(), - next_id: AllocId(NonZeroU64::new(1).unwrap()), + next_id: AllocId(NonZero::new(1).unwrap()), } } fn reserve(&mut self) -> AllocId { diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index dabf6297aa9..e2767ee2989 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -3,7 +3,7 @@ use super::{AllocId, InterpResult}; use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; -use std::{fmt, num::NonZeroU64}; +use std::{fmt, num::NonZero}; //////////////////////////////////////////////////////////////////////////////// // Pointer arithmetic @@ -129,7 +129,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static { /// The type of provenance in the compile-time interpreter. /// This is a packed representation of an `AllocId` and an `immutable: bool`. #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct CtfeProvenance(NonZeroU64); +pub struct CtfeProvenance(NonZero<u64>); impl From<AllocId> for CtfeProvenance { fn from(value: AllocId) -> Self { @@ -155,7 +155,7 @@ impl CtfeProvenance { /// Returns the `AllocId` of this provenance. #[inline(always)] pub fn alloc_id(self) -> AllocId { - AllocId(NonZeroU64::new(self.0.get() & !IMMUTABLE_MASK).unwrap()) + AllocId(NonZero::new(self.0.get() & !IMMUTABLE_MASK).unwrap()) } /// Returns whether this provenance is immutable. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e8aca5f2e7d..643b61c1de3 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,7 +1,7 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; -use crate::query::{TyCtxtAt, TyCtxtEnsure}; +use crate::query::TyCtxtEnsure; use crate::ty::visit::TypeVisitableExt; use crate::ty::GenericArgs; use crate::ty::{self, TyCtxt}; @@ -173,44 +173,6 @@ impl<'tcx> TyCtxt<'tcx> { self.eval_to_valtree(inputs) } } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - #[inline(always)] - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - self.at(DUMMY_SP).eval_static_initializer(def_id) - } -} - -impl<'tcx> TyCtxtAt<'tcx> { - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.is_static(def_id)); - let instance = ty::Instance::mono(*self, def_id); - let gid = GlobalId { instance, promoted: None }; - self.eval_to_allocation(gid, ty::ParamEnv::reveal_all()) - } - - /// Evaluate anything constant-like, returning the allocation of the final memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - fn eval_to_allocation( - self, - gid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; - Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) - } } impl<'tcx> TyCtxtEnsure<'tcx> { @@ -232,15 +194,4 @@ impl<'tcx> TyCtxtEnsure<'tcx> { let inputs = self.tcx.erase_regions(param_env.and(cid)); self.eval_to_const_value_raw(inputs) } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - pub fn eval_static_initializer(self, def_id: DefId) { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.tcx.is_static(def_id)); - let instance = ty::Instance::mono(self.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - trace!("eval_to_allocation: Need to compute {:?}", gid); - self.eval_to_allocation_raw(param_env.and(gid)) - } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e22d5228628..3017f912ef0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2,7 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar}; +use crate::mir::interpret::{AllocRange, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3cd251caf5e..43e1318a75a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -4,6 +4,7 @@ use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; @@ -241,7 +242,7 @@ pub struct CodegenUnit<'tcx> { /// contain something unique to this crate (e.g., a module path) /// as well as the crate name and disambiguator. name: Symbol, - items: FxHashMap<MonoItem<'tcx>, MonoItemData>, + items: FxIndexMap<MonoItem<'tcx>, MonoItemData>, size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, @@ -316,13 +317,11 @@ impl<'tcx> CodegenUnit<'tcx> { self.primary = true; } - /// The order of these items is non-determinstic. - pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, MonoItemData> { + pub fn items(&self) -> &FxIndexMap<MonoItem<'tcx>, MonoItemData> { &self.items } - /// The order of these items is non-determinstic. - pub fn items_mut(&mut self) -> &mut FxHashMap<MonoItem<'tcx>, MonoItemData> { + pub fn items_mut(&mut self) -> &mut FxIndexMap<MonoItem<'tcx>, MonoItemData> { &mut self.items } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a011f6114de..5638b575b31 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -4,6 +4,8 @@ use std::fs; use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; +use crate::mir::interpret::ConstAllocation; + use super::graphviz::write_mir_fn_graphviz; use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 90b6df1dd1f..8bd872c1b19 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -86,7 +86,8 @@ rustc_index::newtype_index! { pub struct CoroutineSavedLocal {} } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CoroutineSavedTy<'tcx> { pub ty: Ty<'tcx>, /// Source info corresponding to the local in the original MIR body. @@ -96,7 +97,8 @@ pub struct CoroutineSavedTy<'tcx> { } /// The layout of coroutine state. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, PartialEq, Eq)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CoroutineLayout<'tcx> { /// The type of every local stored inside the coroutine. pub field_tys: IndexVec<CoroutineSavedLocal, CoroutineSavedTy<'tcx>>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 7039749b1b7..2cdcdcb1492 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -177,8 +177,8 @@ impl EraseType for Option<mir::DestructuredConstant<'_>> { type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()]; } -impl EraseType for Option<ty::EarlyBinder<ty::TraitRef<'_>>> { - type Result = [u8; size_of::<Option<ty::EarlyBinder<ty::TraitRef<'static>>>>()]; +impl EraseType for Option<ty::EarlyBinder<ty::ImplTraitHeader<'_>>> { + type Result = [u8; size_of::<Option<ty::EarlyBinder<ty::ImplTraitHeader<'static>>>>()]; } impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> { @@ -241,6 +241,7 @@ trivial! { Option<rustc_target::abi::FieldIdx>, Option<rustc_target::spec::PanicStrategy>, Option<usize>, + Option<rustc_span::Symbol>, Result<(), rustc_errors::ErrorGuaranteed>, Result<(), rustc_middle::traits::query::NoSolution>, Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>, @@ -337,6 +338,7 @@ tcx_lifetime! { rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::traits::query::type_op::AscribeUserType, rustc_middle::traits::query::type_op::Eq, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5a158edab72..5be45c33e11 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -20,7 +20,8 @@ use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; use crate::mir::interpret::{ - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, + EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, + EvalToValTreeResult, }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; @@ -846,17 +847,13 @@ rustc_queries! { cache_on_disk_if { true } } - /// Given an `impl_id`, return the trait it implements. + /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. - query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> { + query impl_trait_header(impl_id: DefId) -> Option<ty::EarlyBinder<ty::ImplTraitHeader<'tcx>>> { desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } cache_on_disk_if { impl_id.is_local() } separate_provide_extern } - query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } - separate_provide_extern - } query issue33140_self_ty(key: DefId) -> Option<ty::EarlyBinder<ty::Ty<'tcx>>> { desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } @@ -1065,7 +1062,7 @@ rustc_queries! { /// Evaluates a constant and returns the computed allocation. /// - /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead. query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| @@ -1075,6 +1072,16 @@ rustc_queries! { cache_on_disk_if { true } } + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. + query eval_static_initializer(key: DefId) -> EvalStaticInitializerRawResult<'tcx> { + desc { |tcx| + "evaluating initializer of static `{}`", + tcx.def_path_str(key) + } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + /// Evaluates const items or anonymous constants /// (such as enum variant explicit discriminants or array lengths) /// into a representation suitable for the type system and const generics. @@ -1753,8 +1760,8 @@ rustc_queries! { separate_provide_extern } /// Whether the function is an intrinsic - query is_intrinsic(def_id: DefId) -> bool { - desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) } + query intrinsic(def_id: DefId) -> Option<Symbol> { + desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) } separate_provide_extern } /// Returns the lang items defined in another crate by loading it from metadata. diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8e5f026b4c2..119e0a49acf 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -569,9 +569,8 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, pub scrut_span: Span, - pub scrut_hir_id: hir::HirId, pub source: hir::MatchSource, - pub prior_arms: Vec<Span>, + pub prior_non_diverging_arms: Vec<Span>, pub opt_suggest_box_span: Option<Span>, } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 23771073745..5e4d899f517 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -35,6 +35,16 @@ impl<'tcx> IntoKind for Const<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> { fn ty(self) -> Ty<'tcx> { self.ty() @@ -63,11 +73,13 @@ impl<'tcx> Const<'tcx> { self.0.kind } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn flags(self) -> TypeFlags { self.0.flags } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 515d564e81d..5d50510338c 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::Size; use std::fmt; -use std::num::NonZeroU8; +use std::num::NonZero; use crate::ty::TyCtxt; @@ -132,7 +132,7 @@ pub struct ScalarInt { /// The first `size` bytes of `data` are the value. /// Do not try to read less or more bytes than that. The remaining bytes must be 0. data: u128, - size: NonZeroU8, + size: NonZero<u8>, } // Cannot derive these, as the derives take references to the fields, and we @@ -161,14 +161,14 @@ impl<D: Decoder> Decodable<D> for ScalarInt { let mut data = [0u8; 16]; let size = d.read_u8(); data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize)); - ScalarInt { data: u128::from_le_bytes(data), size: NonZeroU8::new(size).unwrap() } + ScalarInt { data: u128::from_le_bytes(data), size: NonZero::new(size).unwrap() } } } impl ScalarInt { - pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() }; + pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() }; - pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() }; + pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() }; #[inline] pub fn size(self) -> Size { @@ -196,7 +196,7 @@ impl ScalarInt { #[inline] pub fn null(size: Size) -> Self { - Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() } + Self { data: 0, size: NonZero::new(size.bytes() as u8).unwrap() } } #[inline] @@ -208,7 +208,7 @@ impl ScalarInt { pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { let data = i.into(); if size.truncate(data) == data { - Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) + Some(Self { data, size: NonZero::new(size.bytes() as u8).unwrap() }) } else { None } @@ -220,7 +220,7 @@ impl ScalarInt { // `into` performed sign extension, we have to truncate let truncated = size.truncate(i as u128); if size.sign_extend(truncated) as i128 == i { - Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) + Some(Self { data: truncated, size: NonZero::new(size.bytes() as u8).unwrap() }) } else { None } @@ -388,7 +388,7 @@ macro_rules! from { fn from(u: $ty) -> Self { Self { data: u128::from(u), - size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(), + size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(), } } } @@ -427,7 +427,7 @@ impl TryFrom<ScalarInt> for bool { impl From<char> for ScalarInt { #[inline] fn from(c: char) -> Self { - Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() } + Self { data: c as u128, size: NonZero::new(std::mem::size_of::<char>() as u8).unwrap() } } } @@ -454,7 +454,7 @@ impl From<Single> for ScalarInt { #[inline] fn from(f: Single) -> Self { // We trust apfloat to give us properly truncated data. - Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() } + Self { data: f.to_bits(), size: NonZero::new((Single::BITS / 8) as u8).unwrap() } } } @@ -470,7 +470,7 @@ impl From<Double> for ScalarInt { #[inline] fn from(f: Double) -> Self { // We trust apfloat to give us properly truncated data. - Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() } + Self { data: f.to_bits(), size: NonZero::new((Double::BITS / 8) as u8).unwrap() } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9a0eea6592f..cc734e7157f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,7 +28,7 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - Visibility, + TypeVisitable, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -87,7 +87,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; - type Binder<T> = Binder<'tcx, T>; + type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; + type BoundVars = &'tcx List<ty::BoundVariableKind>; + type BoundVar = ty::BoundVariableKind; type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; @@ -151,6 +153,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::Const { Const::new_bound(self, debruijn, var, ty) } + + fn expect_error_or_delayed_bug() { + let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()); + assert!(has_errors.is_some()); + } } type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; @@ -1046,12 +1053,22 @@ impl<'tcx> TyCtxtAt<'tcx> { name: Symbol, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { - // This function modifies `self.definitions` using a side-effect. - // We need to ensure that these side effects are re-run by the incr. comp. engine. - // Depending on the forever-red node will tell the graph that the calling query - // needs to be re-evaluated. - self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); + let feed = self.tcx.create_def(parent, name, def_kind); + feed.def_span(self.span); + feed + } +} + +impl<'tcx> TyCtxt<'tcx> { + /// `tcx`-dependent operations performed for every created definition. + pub fn create_def( + self, + parent: LocalDefId, + name: Symbol, + def_kind: DefKind, + ) -> TyCtxtFeed<'tcx, LocalDefId> { + let data = def_kind.def_path_data(name); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to // decode the on-disk cache. @@ -1066,20 +1083,14 @@ impl<'tcx> TyCtxtAt<'tcx> { // This is fine because: // - those queries are `eval_always` so we won't miss their result changing; // - this write will have happened before these queries are called. - let def_id = self.tcx.create_def(parent, name, def_kind); - - let feed = self.tcx.feed_local_def_id(def_id); - feed.def_span(self.span); - feed - } -} - -impl<'tcx> TyCtxt<'tcx> { - /// `tcx`-dependent operations performed for every created definition. - pub fn create_def(self, parent: LocalDefId, name: Symbol, def_kind: DefKind) -> LocalDefId { - let data = def_kind.def_path_data(name); let def_id = self.untracked.definitions.write().create_def(parent, data); + // This function modifies `self.definitions` using a side-effect. + // We need to ensure that these side effects are re-run by the incr. comp. engine. + // Depending on the forever-red node will tell the graph that the calling query + // needs to be re-evaluated. + self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); + let feed = self.feed_local_def_id(def_id); feed.def_kind(def_kind); // Unique types created for closures participate in type privacy checking. @@ -1091,7 +1102,7 @@ impl<'tcx> TyCtxt<'tcx> { feed.visibility(ty::Visibility::Restricted(parent_mod)); } - def_id + feed } pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx { @@ -2316,6 +2327,20 @@ impl<'tcx> TyCtxt<'tcx> { pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] { self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]) } + + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + pub fn impl_trait_ref( + self, + def_id: impl IntoQueryParam<DefId>, + ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> { + Some(self.impl_trait_header(def_id)?.map_bound(|h| h.trait_ref)) + } + + pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity { + self.impl_trait_header(def_id) + .map_or(ty::ImplPolarity::Positive, |h| h.skip_binder().polarity) + } } /// Parameter attributes that can only be determined by examining the body of a function instead diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 84de12b23a0..813a7a64daf 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -18,7 +18,7 @@ use core::intrinsics; use std::cmp::Ordering; use std::marker::PhantomData; use std::mem; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::ops::{ControlFlow, Deref}; use std::ptr::NonNull; @@ -143,9 +143,8 @@ impl<'tcx> From<ty::Term<'tcx>> for GenericArg<'tcx> { impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { - let ptr = unsafe { - self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK)) - }; + let ptr = + unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) }; // 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. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8d8d06b7c0b..c1e33fe114f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -20,23 +20,11 @@ use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Targ use std::cmp; use std::fmt; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::ops::Bound; -pub trait IntegerExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; - fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer; - fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer; - fn repr_discr<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - repr: &ReprOptions, - min: i128, - max: i128, - ) -> (Integer, bool); -} - -impl IntegerExt for Integer { +#[extension(pub trait IntegerExt)] +impl Integer { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> { match (*self, signed) { @@ -123,12 +111,8 @@ impl IntegerExt for Integer { } } -pub trait PrimitiveExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - -impl PrimitiveExt for Primitive { +#[extension(pub trait PrimitiveExt)] +impl Primitive { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { @@ -761,7 +745,7 @@ where }; tcx.mk_layout(LayoutS { variants: Variants::Single { index: variant_index }, - fields: match NonZeroUsize::new(fields) { + fields: match NonZero::new(fields) { Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index af77ba02ad2..eea3624898c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -61,7 +61,7 @@ use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::ops::ControlFlow; use std::ptr::NonNull; use std::{fmt, str}; @@ -248,6 +248,13 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec<Predicate<'tcx>>, } +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, TyEncodable, TyDecodable, HashStable)] +pub struct ImplTraitHeader<'tcx> { + pub trait_ref: ty::TraitRef<'tcx>, + pub polarity: ImplPolarity, + pub unsafety: hir::Unsafety, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub enum ImplSubject<'tcx> { Trait(TraitRef<'tcx>), @@ -497,6 +504,16 @@ impl<'tcx> IntoKind for Ty<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Ty<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl EarlyParamRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). @@ -600,9 +617,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> { impl<'tcx> Term<'tcx> { #[inline] pub fn unpack(self) -> TermKind<'tcx> { - let ptr = unsafe { - self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK)) - }; + let ptr = + unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) }; // 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. @@ -1602,17 +1618,16 @@ impl<'tcx> TyCtxt<'tcx> { def_id1: DefId, def_id2: DefId, ) -> Option<ImplOverlapKind> { - let impl_trait_ref1 = self.impl_trait_ref(def_id1); - let impl_trait_ref2 = self.impl_trait_ref(def_id2); + let impl1 = self.impl_trait_header(def_id1).unwrap().instantiate_identity(); + let impl2 = self.impl_trait_header(def_id2).unwrap().instantiate_identity(); + // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if impl_trait_ref1.is_some_and(|tr| tr.instantiate_identity().references_error()) - || impl_trait_ref2.is_some_and(|tr| tr.instantiate_identity().references_error()) - { + if impl1.references_error() || impl2.references_error() { return Some(ImplOverlapKind::Permitted { marker: false }); } - match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { + match (impl1.polarity, impl2.polarity) { (ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => { // `#[rustc_reservation_impl]` impls don't overlap with anything return Some(ImplOverlapKind::Permitted { marker: false }); @@ -1627,10 +1642,9 @@ impl<'tcx> TyCtxt<'tcx> { }; let is_marker_overlap = { - let is_marker_impl = |trait_ref: Option<EarlyBinder<TraitRef<'_>>>| -> bool { - trait_ref.is_some_and(|tr| self.trait_def(tr.skip_binder().def_id).is_marker) - }; - is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) + let is_marker_impl = + |trait_ref: TraitRef<'_>| -> bool { self.trait_def(trait_ref.def_id).is_marker }; + is_marker_impl(impl1.trait_ref) && is_marker_impl(impl2.trait_ref) }; if is_marker_overlap { diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 47f9d9e61ad..22f0574d614 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -126,6 +126,7 @@ parameterized_over_tcx! { crate::middle::exported_symbols::ExportedSymbol, crate::mir::Body, crate::mir::CoroutineLayout, + crate::mir::interpret::ConstAllocation, ty::Ty, ty::FnSig, ty::GenericPredicates, @@ -134,4 +135,5 @@ parameterized_over_tcx! { ty::Predicate, ty::Clause, ty::ClauseKind, + ty::ImplTraitHeader } diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 200811940ed..b63f9c6dfa0 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -29,6 +29,16 @@ pub struct Predicate<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, ); +impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl<'tcx> Predicate<'tcx> { /// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`. #[inline] @@ -36,11 +46,13 @@ impl<'tcx> Predicate<'tcx> { self.0.internee } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn flags(self) -> TypeFlags { self.0.flags } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn outer_exclusive_binder(self) -> DebruijnIndex { self.0.outer_exclusive_binder diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5cf90e94907..92ec1a83bee 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3156,13 +3156,12 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // this is pub to be able to intra-doc-link it pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> { // Trimming paths is expensive and not optimized, since we expect it to only be used for error - // reporting. + // reporting. Record the fact that we did it, so we can abort if we later found it was + // unnecessary. // - // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` - // wrapper can be used to suppress this query, in exchange for full paths being formatted. - tcx.sess.good_path_delayed_bug( - "trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging", - ); + // The `rustc_middle::ty::print::with_no_trimmed_paths` wrapper can be used to suppress this + // checking, in exchange for full paths being formatted. + tcx.sess.record_trimmed_def_paths(); // Once constructed, unique namespace+symbol pairs will have a `Some(_)` entry, while // non-unique pairs will have a `None` entry. diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 1191d7fca32..b206727f051 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -26,6 +26,19 @@ impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> { } } +impl<'tcx> rustc_type_ir::visit::Flags for Region<'tcx> { + fn flags(&self) -> TypeFlags { + self.type_flags() + } + + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { + match **self { + ty::ReBound(debruijn, _) => debruijn.shifted_in(1), + _ => ty::INNERMOST, + } + } +} + impl<'tcx> Region<'tcx> { #[inline] pub fn new_early_param( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a3d5f1f1955..a5817125267 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -942,6 +942,16 @@ where } } +impl<'tcx, T> rustc_type_ir::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { + fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> { + self.bound_vars + } + + fn has_no_bound_vars(&self) -> bool { + self.bound_vars.is_empty() + } +} + impl<'tcx, T> Binder<'tcx, T> { /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about @@ -1808,6 +1818,7 @@ impl<'tcx> Ty<'tcx> { self.0.0 } + // FIXME(compiler-errors): Think about removing this. #[inline(always)] pub fn flags(self) -> TypeFlags { self.0.0.flags @@ -2352,16 +2363,44 @@ impl<'tcx> Ty<'tcx> { } /// When we create a closure, we record its kind (i.e., what trait - /// it implements) into its `ClosureArgs` using a type + /// it implements, constrained by how it uses its borrows) into its + /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type /// parameter. This is kind of a phantom type, except that the /// most convenient thing for us to are the integral types. This /// function converts such a special type into the closure - /// kind. To go the other way, use `closure_kind.to_ty(tcx)`. + /// kind. To go the other way, use [`Ty::from_closure_kind`]. /// /// 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_hir_analysis/src/check/upvar.rs`) - /// is complete, that type variable will be unified. + /// is complete, that type variable will be unified with one of + /// the integral types. + /// + /// ```rust,ignore (snippet of compiler code) + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } + /// ``` + /// + /// After upvar analysis, you should instead use [`ClosureArgs::kind()`] + /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` + /// has been constrained instead of manually calling this method. + /// + /// ```rust,ignore (snippet of compiler code) + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_closure().kind()); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_coroutine_closure().kind()); + /// } + /// ``` pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> { match self.kind() { Int(int_ty) => match int_ty { @@ -2381,7 +2420,8 @@ impl<'tcx> Ty<'tcx> { } } - /// Inverse of [`Ty::to_opt_closure_kind`]. + /// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method + /// for explanation of the relationship between `Ty` and [`ty::ClosureKind`]. pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { match kind { ty::ClosureKind::Fn => tcx.types.i8, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c674a868d9f..3f539945841 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_macros::HashStable; use rustc_session::Limit; -use rustc_span::sym; +use rustc_span::{sym, Symbol}; use rustc_target::abi::{Integer, IntegerType, Primitive, Size}; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; @@ -96,13 +96,8 @@ impl<'tcx> Discr<'tcx> { } } -pub trait IntTypeExt { - fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; - fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>; - fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>; -} - -impl IntTypeExt for IntegerType { +#[extension(pub trait IntTypeExt)] +impl IntegerType { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { IntegerType::Pointer(true) => tcx.types.isize, @@ -1320,6 +1315,7 @@ impl<'tcx> Ty<'tcx> { ty } + // FIXME(compiler-errors): Think about removing this. #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder @@ -1551,9 +1547,15 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { .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: LocalDefId) -> bool { - matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) +/// Determines whether an item is an intrinsic by Abi. or by whether it has a `rustc_intrinsic` attribute +pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Symbol> { + if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) + || tcx.has_attr(def_id, sym::rustc_intrinsic) + { + Some(tcx.item_name(def_id.into())) + } else { + None + } } pub fn provide(providers: &mut Providers) { @@ -1561,7 +1563,7 @@ pub fn provide(providers: &mut Providers) { reveal_opaque_types_in_bounds, is_doc_hidden, is_doc_notable_trait, - is_intrinsic, + intrinsic, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 7acdb931f1a..59292a281ed 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,140 +1,10 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_errors::ErrorGuaranteed; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use std::ops::ControlFlow; -pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; - -pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { - /// Returns `true` if `self` has any late-bound regions that are either - /// bound by `binder` or bound by some binder outside of `binder`. - /// If `binder` is `ty::INNERMOST`, this indicates whether - /// there are any late-bound regions that appear free. - fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() - } - - /// Returns `true` if this type has any regions that escape `binder` (and - /// hence are not bound by it). - fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { - self.has_vars_bound_at_or_above(binder.shifted_in(1)) - } - - /// Return `true` if this type has regions that are not a part of the type. - /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)` - /// would return `true`. The latter can occur when traversing through the - /// former. - /// - /// See [`HasEscapingVarsVisitor`] for more information. - fn has_escaping_bound_vars(&self) -> bool { - self.has_vars_bound_at_or_above(ty::INNERMOST) - } - - fn has_type_flags(&self, flags: TypeFlags) -> bool { - let res = - self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags); - trace!(?self, ?flags, ?res, "has_type_flags"); - res - } - fn has_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn has_inherent_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INHERENT) - } - fn has_opaque_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) - } - fn has_coroutines(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_COROUTINE) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_ERROR) - } - fn error_reported(&self) -> Result<(), ErrorGuaranteed> { - if self.references_error() { - // We must include lint errors and delayed bugs here. - if let Some(reported) = - ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()) - { - Err(reported) - } else { - bug!("expected some kind of error in `error_reported`"); - } - } else { - Ok(()) - } - } - fn has_non_region_param(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM) - } - fn has_infer_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_INFER) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn has_non_region_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER) - } - fn has_infer(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_INFER) - } - fn has_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PLACEHOLDER) - } - fn has_non_region_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER) - } - fn has_param(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAM) - } - /// "Free" regions in this context means that it has any region - /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - fn has_erased_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_ERASED) - } - - /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - /// Indicates whether this value references only 'global' - /// generic parameters that are the same regardless of what fn we are - /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) - } - - /// True if there are any late-bound regions - fn has_bound_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_BOUND) - } - /// True if there are any late-bound non-region variables - fn has_non_region_bound_vars(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND) - } - /// True if there are any bound variables - fn has_bound_vars(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_BOUND_VARS) - } - - /// Indicates whether this value still has parameters/placeholders/inference variables - /// which could be replaced later, in a way that would change the results of `impl` - /// specialization. - fn still_further_specializable(&self) -> bool { - self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) - } -} - -impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {} +pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; /////////////////////////////////////////////////////////////////////////// // Region folder @@ -370,185 +240,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundEscapingVars; - -/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a -/// bound region or a bound type. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping var" is often just called a "free var". However, -/// we already use the term "free var". It refers to the regions or types that we use to represent -/// bound regions or type params on a fn definition while we are type checking its body. -/// -/// To clarify, conceptually there is no particular difference between -/// an "escaping" var and a "free" var. However, there is a big -/// difference in practice. Basically, when "entering" a binding -/// level, one is generally required to do some sort of processing to -/// a bound var, such as replacing it with a fresh/placeholder -/// var, or making an entry in the environment to represent the -/// scope to which it is attached, etc. An escaping var represents -/// a bound var for which this processing has not yet been done. -struct HasEscapingVarsVisitor { - /// Anything bound by `outer_index` or "above" is escaping. - outer_index: ty::DebruijnIndex, -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor { - type BreakTy = FoundEscapingVars; - - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.outer_index.shift_in(1); - let result = t.super_visit_with(self); - self.outer_index.shift_out(1); - result - } - - #[inline] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `t` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - if t.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the region is bound by `outer_index` or anything outside - // of outer index, then it escapes the binders we have - // visited. - if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `ct` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - if ct.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - if predicate.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::Continue(()) - } - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundFlags; - -// FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, -} - -impl std::fmt::Debug for HasTypeFlagsVisitor { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.flags.fmt(fmt) - } -} - -// Note: this visitor traverses values down to the level of -// `Ty`/`Const`/`Predicate`, but not within those types. This is because the -// type flags at the outer layer are enough. So it's faster than it first -// looks, particular for `Ty`/`Predicate` where it's just a field access. -// -// N.B. The only case where this isn't totally true is binders, which also -// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that -// are present, regardless of whether those bound variables are used. This -// is important for anonymization of binders in `TyCtxt::erase_regions`. We -// specifically detect this case in `visit_binder`. -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor { - type BreakTy = FoundFlags; - - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - // If we're looking for the HAS_BINDER_VARS flag, check if the - // binder has vars. This won't be present in the binder's bound - // value, so we need to check here too. - if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() { - return ControlFlow::Break(FoundFlags); - } - - t.super_visit_with(self) - } - - #[inline] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - let flags = t.flags(); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call, as usual for `Region`. - let flags = r.type_flags(); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - if c.flags().intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } - - #[inline] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - // Note: no `super_visit_with` call. - if predicate.flags().intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::Continue(()) - } - } -} - /// Collects all the late-bound regions at the innermost binding level /// into a hash set. struct LateBoundRegionsCollector { |
