#![allow(rustc::usage_of_ty_tykind)]
use std::assert_matches::assert_matches;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::num::NonZero;
use std::ptr::NonNull;
use std::{fmt, mem, str};
pub use adt::*;
pub use assoc::*;
pub use generic_args::{GenericArgKind, TermKind, *};
pub use generics::*;
pub use intrinsic::IntrinsicDef;
use rustc_ast::expand::StrippedCfgItem;
use rustc_ast::node_id::NodeMap;
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
use rustc_hir::LangItem;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_index::IndexVec;
use rustc_macros::{
Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
extension,
};
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::{Decodable, Encodable};
use rustc_session::lint::LintBuffer;
pub use rustc_session::lint::RegisteredTools;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{ExpnId, ExpnKind, Span};
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::ConstKind::{
Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
Placeholder as PlaceholderCt, Unevaluated, Value,
};
pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::*;
use tracing::{debug, instrument};
pub use vtable::*;
use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
pub use self::IntVarValue::*;
pub use self::closure::{
BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo,
MinCaptureInformationMap, MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId,
UpvarPath, analyze_coroutine_closure_captures, is_ancestor_or_same_capture,
place_to_string_for_capture,
};
pub use self::consts::{
Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
TyCtxtFeed, tls,
};
pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams};
pub use self::list::{List, ListWithCachedTypeInfo};
pub use self::opaque_types::OpaqueTypeKey;
pub use self::parameterized::ParameterizedOverTcx;
pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{
AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef,
HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
TypeOutlivesPredicate,
};
pub use self::region::BoundRegionKind::*;
pub use self::region::{
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, Region, RegionKind, RegionVid,
};
pub use self::rvalue_scopes::RvalueScopes;
pub use self::sty::{
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
};
pub use self::trait_def::TraitDef;
pub use self::typeck_results::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
TypeckResults, UserType, UserTypeAnnotationIndex,
};
pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
use crate::metadata::ModChild;
use crate::middle::privacy::EffectiveVisibilities;
use crate::mir::{Body, CoroutineLayout};
use crate::query::Providers;
use crate::traits::{self, Reveal};
use crate::ty;
pub use crate::ty::diagnostics::*;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::util::Discr;
pub mod abstract_const;
pub mod adjustment;
pub mod cast;
pub mod codec;
pub mod error;
pub mod fast_reject;
pub mod flags;
pub mod fold;
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
pub mod pattern;
pub mod print;
pub mod relate;
pub mod trait_def;
pub mod util;
pub mod visit;
pub mod vtable;
pub mod walk;
mod adt;
mod assoc;
mod closure;
mod consts;
mod context;
mod diagnostics;
mod elaborate_impl;
mod erase_regions;
mod generic_args;
mod generics;
mod impls_ty;
mod instance;
mod intrinsic;
mod list;
mod opaque_types;
mod parameterized;
mod predicate;
mod region;
mod rvalue_scopes;
mod structural_impls;
#[allow(hidden_glob_reexports)]
mod sty;
mod typeck_results;
pub struct ResolverOutputs {
pub global_ctxt: ResolverGlobalCtxt,
pub ast_lowering: ResolverAstLowering,
}
#[derive(Debug)]
pub struct ResolverGlobalCtxt {
pub visibilities_for_hashing: Vec<(LocalDefId, Visibility)>,
pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub module_children: LocalDefIdMap<Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
pub main_def: Option<MainDefinition>,
pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
pub proc_macros: Vec<LocalDefId>,
pub confused_type_with_std_module: FxIndexMap<Span, Span>,
pub doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
pub doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
pub stripped_cfg_items: Steal<Vec<StrippedCfgItem>>,
}
#[derive(Debug)]
pub struct ResolverAstLowering {
pub legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
pub partial_res_map: NodeMap<hir::def::PartialRes>,
pub import_res_map: NodeMap<hir::def::PerNS<Option<Res<ast::NodeId>>>>,
pub label_res_map: NodeMap<ast::NodeId>,
pub lifetimes_res_map: NodeMap<LifetimeRes>,
pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
pub next_node_id: ast::NodeId,
pub node_id_to_def_id: NodeMap<LocalDefId>,
pub trait_map: NodeMap<Vec<hir::TraitCandidate>>,
pub lifetime_elision_allowed: FxHashSet<ast::NodeId>,
pub lint_buffer: Steal<LintBuffer>,
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
}
#[derive(Debug)]
pub struct DelegationFnSig {
pub header: ast::FnHeader,
pub param_count: usize,
pub has_self: bool,
pub c_variadic: bool,
}
#[derive(Clone, Copy, Debug)]
pub struct MainDefinition {
pub res: Res<ast::NodeId>,
pub is_import: bool,
pub span: Span,
}
impl MainDefinition {
pub fn opt_fn_def_id(self) -> Option<DefId> {
if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
}
}
#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct ImplHeader<'tcx> {
pub impl_def_id: DefId,
pub impl_args: ty::GenericArgsRef<'tcx>,
pub self_ty: Ty<'tcx>,
pub trait_ref: Option<TraitRef<'tcx>>,
pub predicates: Vec<Predicate<'tcx>>,
}
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct ImplTraitHeader<'tcx> {
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
pub polarity: ImplPolarity,
pub safety: hir::Safety,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
pub enum ImplSubject<'tcx> {
Trait(TraitRef<'tcx>),
Inherent(Ty<'tcx>),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum Asyncness {
Yes,
No,
}
impl Asyncness {
pub fn is_async(self) -> bool {
matches!(self, Asyncness::Yes)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
pub enum Visibility<Id = LocalDefId> {
Public,
Restricted(Id),
}
impl Visibility {
pub fn to_string(self, def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
match self {
ty::Visibility::Restricted(restricted_id) => {
if restricted_id.is_top_level_module() {
"pub(crate)".to_string()
} else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() {
"pub(self)".to_string()
} else {
format!("pub({})", tcx.item_name(restricted_id.to_def_id()))
}
}
ty::Visibility::Public => "pub".to_string(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ClosureSizeProfileData<'tcx> {
pub before_feature_tys: Ty<'tcx>,
pub after_feature_tys: Ty<'tcx>,
}
impl TyCtxt<'_> {
#[inline]
pub fn opt_parent(self, id: DefId) -> Option<DefId> {
self.def_key(id).parent.map(|index| DefId { index, ..id })
}
#[inline]
#[track_caller]
pub fn parent(self, id: DefId) -> DefId {
match self.opt_parent(id) {
Some(id) => id,
None => bug!("{id:?} doesn't have a parent"),
}
}
#[inline]
#[track_caller]
pub fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
self.opt_parent(id.to_def_id()).map(DefId::expect_local)
}
#[inline]
#[track_caller]
pub fn local_parent(self, id: impl Into<LocalDefId>) -> LocalDefId {
self.parent(id.into().to_def_id()).expect_local()
}
pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
if descendant.krate != ancestor.krate {
return false;
}
while descendant != ancestor {
match self.opt_parent(descendant) {
Some(parent) => descendant = parent,
None => return false,
}
}
true
}
}
impl<Id> Visibility<Id> {
pub fn is_public(self) -> bool {
matches!(self, Visibility::Public)
}
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)
}
pub fn is_accessible_from(self, module: impl Into<DefId>, tcx: TyCtxt<'_>) -> bool {
match self {
Visibility::Public => true,
Visibility::Restricted(id) => tcx.is_descendant_of(module.into(), id.into()),
}
}
pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tcx: TyCtxt<'_>) -> bool {
match vis {
Visibility::Public => self.is_public(),
Visibility::Restricted(id) => self.is_accessible_from(id, tcx),
}
}
}
impl Visibility<DefId> {
pub fn expect_local(self) -> Visibility {
self.map_id(|id| id.expect_local())
}
pub fn is_visible_locally(self) -> bool {
match self {
Visibility::Public => true,
Visibility::Restricted(def_id) => def_id.is_local(),
}
}
}
#[derive(HashStable, Debug)]
pub struct CrateVariancesMap<'tcx> {
pub variances: DefIdMap<&'tcx [ty::Variance]>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct CReaderCacheKey {
pub cnum: Option<CrateNum>,
pub pos: usize,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_diagnostic_item = "Ty"]
#[rustc_pass_by_value]
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
impl<'tcx> rustc_type_ir::inherent::IntoKind for Ty<'tcx> {
type Kind = TyKind<'tcx>;
fn kind(self) -> TyKind<'tcx> {
*self.kind()
}
}
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 {
pub fn has_name(&self) -> bool {
self.name != kw::UnderscoreLifetime && self.name != kw::Empty
}
}
#[derive(HashStable, Debug)]
pub struct CratePredicatesMap<'tcx> {
pub predicates: DefIdMap<&'tcx [(Clause<'tcx>, Span)]>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Term<'tcx> {
ptr: NonNull<()>,
marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
}
impl<'tcx> rustc_type_ir::inherent::Term<TyCtxt<'tcx>> for Term<'tcx> {}
impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
type Kind = TermKind<'tcx>;
fn kind(self) -> Self::Kind {
self.unpack()
}
}
#[cfg(parallel_compiler)]
unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where
&'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend
{
}
#[cfg(parallel_compiler)]
unsafe impl<'tcx> rustc_data_structures::sync::DynSync for Term<'tcx> where
&'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSync
{
}
unsafe impl<'tcx> Send for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Send {}
unsafe impl<'tcx> Sync for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Sync {}
impl Debug for Term<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.unpack() {
TermKind::Ty(ty) => write!(f, "Term::Ty({ty:?})"),
TermKind::Const(ct) => write!(f, "Term::Const({ct:?})"),
}
}
}
impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
fn from(ty: Ty<'tcx>) -> Self {
TermKind::Ty(ty).pack()
}
}
impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
fn from(c: Const<'tcx>) -> Self {
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<TyCtxt<'tcx>> for Term<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
match self.unpack() {
ty::TermKind::Ty(ty) => ty.try_fold_with(folder).map(Into::into),
ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
}
}
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
match self.unpack() {
ty::TermKind::Ty(ty) => ty.visit_with(visitor),
ty::TermKind::Const(ct) => ct.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 =
unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) };
unsafe {
match self.ptr.addr().get() & TAG_MASK {
TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
))),
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(),
))),
_ => core::intrinsics::unreachable(),
}
}
}
pub fn as_type(&self) -> Option<Ty<'tcx>> {
if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None }
}
pub fn expect_type(&self) -> Ty<'tcx> {
self.as_type().expect("expected a type, but found a const")
}
pub fn as_const(&self) -> Option<Const<'tcx>> {
if let TermKind::Const(c) = self.unpack() { Some(c) } else { None }
}
pub fn expect_const(&self) -> Const<'tcx> {
self.as_const().expect("expected a const, but found a type")
}
pub fn into_arg(self) -> GenericArg<'tcx> {
match self.unpack() {
TermKind::Ty(ty) => ty.into(),
TermKind::Const(c) => c.into(),
}
}
pub fn to_alias_term(self) -> Option<AliasTerm<'tcx>> {
match self.unpack() {
TermKind::Ty(ty) => match *ty.kind() {
ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
_ => None,
},
TermKind::Const(ct) => match ct.kind() {
ConstKind::Unevaluated(uv) => Some(uv.into()),
_ => None,
},
}
}
pub fn is_infer(&self) -> bool {
match self.unpack() {
TermKind::Ty(ty) => ty.is_ty_var(),
TermKind::Const(ct) => ct.is_ct_infer(),
}
}
}
const TAG_MASK: usize = 0b11;
const TYPE_TAG: usize = 0b00;
const CONST_TAG: usize = 0b01;
#[extension(pub trait TermKindPackExt<'tcx>)]
impl<'tcx> TermKind<'tcx> {
#[inline]
fn pack(self) -> Term<'tcx> {
let (tag, ptr) = match self {
TermKind::Ty(ty) => {
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
(TYPE_TAG, NonNull::from(ty.0.0).cast())
}
TermKind::Const(ct) => {
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
(CONST_TAG, NonNull::from(ct.0.0).cast())
}
};
Term { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData }
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ParamTerm {
Ty(ParamTy),
Const(ParamConst),
}
impl ParamTerm {
pub fn index(self) -> usize {
match self {
ParamTerm::Ty(ty) => ty.index as usize,
ParamTerm::Const(ct) => ct.index as usize,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum TermVid {
Ty(ty::TyVid),
Const(ty::ConstVid),
}
impl From<ty::TyVid> for TermVid {
fn from(value: ty::TyVid) -> Self {
TermVid::Ty(value)
}
}
impl From<ty::ConstVid> for TermVid {
fn from(value: ty::ConstVid) -> Self {
TermVid::Const(value)
}
}
#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct InstantiatedPredicates<'tcx> {
pub predicates: Vec<Clause<'tcx>>,
pub spans: Vec<Span>,
}
impl<'tcx> InstantiatedPredicates<'tcx> {
pub fn empty() -> InstantiatedPredicates<'tcx> {
InstantiatedPredicates { predicates: vec![], spans: vec![] }
}
pub fn is_empty(&self) -> bool {
self.predicates.is_empty()
}
pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
self.into_iter()
}
}
impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
type Item = (Clause<'tcx>, Span);
type IntoIter = std::iter::Zip<std::vec::IntoIter<Clause<'tcx>>, std::vec::IntoIter<Span>>;
fn into_iter(self) -> Self::IntoIter {
debug_assert_eq!(self.predicates.len(), self.spans.len());
std::iter::zip(self.predicates, self.spans)
}
}
impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
type Item = (Clause<'tcx>, Span);
type IntoIter = std::iter::Zip<
std::iter::Copied<std::slice::Iter<'a, Clause<'tcx>>>,
std::iter::Copied<std::slice::Iter<'a, Span>>,
>;
fn into_iter(self) -> Self::IntoIter {
debug_assert_eq!(self.predicates.len(), self.spans.len());
std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied())
}
}
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
pub struct OpaqueHiddenType<'tcx> {
pub span: Span,
pub ty: Ty<'tcx>,
}
impl<'tcx> OpaqueHiddenType<'tcx> {
pub fn build_mismatch_error(
&self,
other: &Self,
opaque_def_id: LocalDefId,
tcx: TyCtxt<'tcx>,
) -> Result<Diag<'tcx>, ErrorGuaranteed> {
tcx.sess.dcx().try_steal_modify_and_emit_err(
tcx.def_span(opaque_def_id),
StashKey::OpaqueHiddenTypeMismatch,
|_err| {},
);
(self.ty, other.ty).error_reported()?;
let sub_diag = if self.span == other.span {
TypeMismatchReason::ConflictType { span: self.span }
} else {
TypeMismatchReason::PreviousUse { span: self.span }
};
Ok(tcx.dcx().create_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>,
ignore_errors: bool,
) -> Self {
let OpaqueTypeKey { def_id, args } = opaque_type_key;
let id_args = GenericArgs::identity_for_item(tcx, def_id);
debug!(?id_args);
let map = args.iter().zip(id_args).collect();
debug!("map = {:#?}", map);
self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(HashStable, TyEncodable, TyDecodable)]
pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
impl Placeholder<BoundVar> {
pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
match clause.kind().skip_binder() {
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
match placeholder_ct.kind() {
ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => {
Some(ty)
}
_ => None,
}
}
_ => None,
}
});
let ty = candidates.next().unwrap();
assert!(candidates.next().is_none());
ty
}
}
pub type PlaceholderRegion = Placeholder<BoundRegion>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(self) -> BoundVar {
self.bound.var
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::BrAnon } }
}
}
pub type PlaceholderType = Placeholder<BoundTy>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(self) -> BoundVar {
self.bound.var
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
#[derive(TyEncodable, TyDecodable)]
pub struct BoundConst<'tcx> {
pub var: BoundVar,
pub ty: Ty<'tcx>,
}
pub type PlaceholderConst = Placeholder<BoundVar>;
impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(self) -> BoundVar {
self.bound
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: var }
}
}
pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo<Clause<'tcx>>;
impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> {
fn flags(&self) -> TypeFlags {
(**self).flags()
}
fn outer_exclusive_binder(&self) -> DebruijnIndex {
(**self).outer_exclusive_binder()
}
}
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ParamEnv<'tcx> {
packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>,
}
impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> {
fn reveal(self) -> Reveal {
self.reveal()
}
fn caller_bounds(self) -> impl IntoIterator<Item = ty::Clause<'tcx>> {
self.caller_bounds()
}
}
#[derive(Copy, Clone)]
struct ParamTag {
reveal: traits::Reveal,
}
rustc_data_structures::impl_tag! {
impl Tag for ParamTag;
ParamTag { reveal: traits::Reveal::UserFacing },
ParamTag { reveal: traits::Reveal::All },
}
impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ParamEnv")
.field("caller_bounds", &self.caller_bounds())
.field("reveal", &self.reveal())
.finish()
}
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.caller_bounds().hash_stable(hcx, hasher);
self.reveal().hash_stable(hcx, hasher);
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
fn try_fold_with<F: ty::fold::FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(ParamEnv::new(
self.caller_bounds().try_fold_with(folder)?,
self.reveal().try_fold_with(folder)?,
))
}
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
try_visit!(self.caller_bounds().visit_with(visitor));
self.reveal().visit_with(visitor)
}
}
impl<'tcx> ParamEnv<'tcx> {
#[inline]
pub fn empty() -> Self {
Self::new(ListWithCachedTypeInfo::empty(), Reveal::UserFacing)
}
#[inline]
pub fn caller_bounds(self) -> Clauses<'tcx> {
self.packed.pointer()
}
#[inline]
pub fn reveal(self) -> traits::Reveal {
self.packed.tag().reveal
}
#[inline]
pub fn reveal_all() -> Self {
Self::new(ListWithCachedTypeInfo::empty(), Reveal::All)
}
#[inline]
pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self {
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
}
pub fn with_user_facing(mut self) -> Self {
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
self
}
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
if self.packed.tag().reveal == traits::Reveal::All {
return self;
}
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All)
}
#[inline]
pub fn without_caller_bounds(self) -> Self {
Self::new(ListWithCachedTypeInfo::empty(), self.reveal())
}
pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
ParamEnvAnd { param_env: self, value }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
#[derive(HashStable)]
pub struct ParamEnvAnd<'tcx, T> {
pub param_env: ParamEnv<'tcx>,
pub value: T,
}
impl<'tcx, T> ParamEnvAnd<'tcx, T> {
pub fn into_parts(self) -> (ParamEnv<'tcx>, T) {
(self.param_env, self.value)
}
}
#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
pub struct Destructor {
pub did: DefId,
pub constness: hir::Constness,
}
#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
pub struct AsyncDestructor {
pub ctor: DefId,
pub future: DefId,
}
#[derive(Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub struct VariantFlags(u8);
bitflags::bitflags! {
impl VariantFlags: u8 {
const NO_VARIANT_FLAGS = 0;
const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
}
}
rustc_data_structures::external_bitflags_debug! { VariantFlags }
#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
pub struct VariantDef {
pub def_id: DefId,
pub ctor: Option<(CtorKind, DefId)>,
pub name: Symbol,
pub discr: VariantDiscr,
pub fields: IndexVec<FieldIdx, FieldDef>,
tainted: Option<ErrorGuaranteed>,
flags: VariantFlags,
}
impl VariantDef {
pub fn new(
name: Symbol,
variant_did: Option<DefId>,
ctor: Option<(CtorKind, DefId)>,
discr: VariantDiscr,
fields: IndexVec<FieldIdx, FieldDef>,
adt_kind: AdtKind,
parent_did: DefId,
recover_tainted: Option<ErrorGuaranteed>,
is_field_list_non_exhaustive: bool,
) -> Self {
debug!(
"VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
fields = {:?}, adt_kind = {:?}, parent_did = {:?})",
name, variant_did, ctor, discr, fields, adt_kind, parent_did,
);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
if is_field_list_non_exhaustive {
flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
}
VariantDef {
def_id: variant_did.unwrap_or(parent_did),
ctor,
name,
discr,
fields,
flags,
tainted: recover_tainted,
}
}
#[inline]
pub fn is_field_list_non_exhaustive(&self) -> bool {
self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
}
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
}
#[inline]
pub fn has_errors(&self) -> Result<(), ErrorGuaranteed> {
self.tainted.map_or(Ok(()), Err)
}
#[inline]
pub fn ctor_kind(&self) -> Option<CtorKind> {
self.ctor.map(|(kind, _)| kind)
}
#[inline]
pub fn ctor_def_id(&self) -> Option<DefId> {
self.ctor.map(|(_, def_id)| def_id)
}
#[inline]
pub fn single_field(&self) -> &FieldDef {
assert!(self.fields.len() == 1);
&self.fields[FieldIdx::ZERO]
}
#[inline]
pub fn tail_opt(&self) -> Option<&FieldDef> {
self.fields.raw.last()
}
#[inline]
pub fn tail(&self) -> &FieldDef {
self.tail_opt().expect("expected unsized ADT to have a tail field")
}
}
impl PartialEq for VariantDef {
#[inline]
fn eq(&self, other: &Self) -> bool {
let Self {
def_id: lhs_def_id,
ctor: _,
name: _,
discr: _,
fields: _,
flags: _,
tainted: _,
} = &self;
let Self {
def_id: rhs_def_id,
ctor: _,
name: _,
discr: _,
fields: _,
flags: _,
tainted: _,
} = other;
let res = lhs_def_id == rhs_def_id;
if cfg!(debug_assertions) && res {
let deep = self.ctor == other.ctor
&& self.name == other.name
&& self.discr == other.discr
&& self.fields == other.fields
&& self.flags == other.flags;
assert!(deep, "VariantDef for the same def-id has differing data");
}
res
}
}
impl Eq for VariantDef {}
impl Hash for VariantDef {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
let Self { def_id, ctor: _, name: _, discr: _, fields: _, flags: _, tainted: _ } = &self;
def_id.hash(s)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub enum VariantDiscr {
Explicit(DefId),
Relative(u32),
}
#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
pub struct FieldDef {
pub did: DefId,
pub name: Symbol,
pub vis: Visibility<DefId>,
}
impl PartialEq for FieldDef {
#[inline]
fn eq(&self, other: &Self) -> bool {
let Self { did: lhs_did, name: _, vis: _ } = &self;
let Self { did: rhs_did, name: _, vis: _ } = other;
let res = lhs_did == rhs_did;
if cfg!(debug_assertions) && res {
let deep = self.name == other.name && self.vis == other.vis;
assert!(deep, "FieldDef for the same def-id has differing data");
}
res
}
}
impl Eq for FieldDef {}
impl Hash for FieldDef {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
let Self { did, name: _, vis: _ } = &self;
did.hash(s)
}
}
impl<'tcx> FieldDef {
pub fn ty(&self, tcx: TyCtxt<'tcx>, arg: GenericArgsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).instantiate(tcx, arg)
}
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ImplOverlapKind {
Permitted {
marker: bool,
},
FutureCompatOrderDepTraitObjects,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable)]
pub enum ImplTraitInTraitData {
Trait { fn_def_id: DefId, opaque_def_id: DefId },
Impl { fn_def_id: DefId },
}
impl<'tcx> TyCtxt<'tcx> {
pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
self.typeck(self.hir().body_owner_def_id(body))
}
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
self.associated_items(id)
.in_definition_order()
.filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
}
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
let mut flags = ReprFlags::empty();
let mut size = None;
let mut max_align: Option<Align> = None;
let mut min_pack: Option<Align> = None;
let mut field_shuffle_seed =
self.def_path_hash(did.to_def_id()).0.to_smaller_hash().as_u64();
if let Some(user_seed) = self.sess.opts.unstable_opts.layout_seed {
field_shuffle_seed ^= user_seed;
}
for attr in self.get_attrs(did, sym::repr) {
for r in attr::parse_repr_attr(self.sess, attr) {
flags.insert(match r {
attr::ReprRust => ReprFlags::empty(),
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked(pack) => {
min_pack = Some(if let Some(min_pack) = min_pack {
min_pack.min(pack)
} else {
pack
});
ReprFlags::empty()
}
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
attr::ReprSimd => ReprFlags::IS_SIMD,
attr::ReprInt(i) => {
size = Some(match i {
attr::IntType::SignedInt(x) => match x {
ast::IntTy::Isize => IntegerType::Pointer(true),
ast::IntTy::I8 => IntegerType::Fixed(Integer::I8, true),
ast::IntTy::I16 => IntegerType::Fixed(Integer::I16, true),
ast::IntTy::I32 => IntegerType::Fixed(Integer::I32, true),
ast::IntTy::I64 => IntegerType::Fixed(Integer::I64, true),
ast::IntTy::I128 => IntegerType::Fixed(Integer::I128, true),
},
attr::IntType::UnsignedInt(x) => match x {
ast::UintTy::Usize => IntegerType::Pointer(false),
ast::UintTy::U8 => IntegerType::Fixed(Integer::I8, false),
ast::UintTy::U16 => IntegerType::Fixed(Integer::I16, false),
ast::UintTy::U32 => IntegerType::Fixed(Integer::I32, false),
ast::UintTy::U64 => IntegerType::Fixed(Integer::I64, false),
ast::UintTy::U128 => IntegerType::Fixed(Integer::I128, false),
},
});
ReprFlags::empty()
}
attr::ReprAlign(align) => {
max_align = max_align.max(Some(align));
ReprFlags::empty()
}
});
}
}
if self.sess.opts.unstable_opts.randomize_layout {
flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
}
let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox);
if is_box
|| !self
.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did)))
{
flags.insert(ReprFlags::IS_LINEAR);
}
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
}
pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
if let Some(cnum) = def_id.as_crate_root() {
Some(self.crate_name(cnum))
} else {
let def_key = self.def_key(def_id);
match def_key.disambiguated_data.data {
rustc_hir::definitions::DefPathData::Ctor => self
.opt_item_name(DefId { krate: def_id.krate, index: def_key.parent.unwrap() }),
_ => def_key.get_opt_name(),
}
}
}
pub fn item_name(self, id: DefId) -> Symbol {
self.opt_item_name(id).unwrap_or_else(|| {
bug!("item_name: no name for {:?}", self.def_path(id));
})
}
pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> {
let def = self.opt_item_name(def_id)?;
let span = self
.def_ident_span(def_id)
.unwrap_or_else(|| bug!("missing ident span for {def_id:?}"));
Some(Ident::new(def, span))
}
pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> {
if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
Some(self.associated_item(def_id))
} else {
None
}
}
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
if let DefKind::AssocTy = self.def_kind(def_id) {
self.associated_item(def_id).opt_rpitit_info
} else {
None
}
}
pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool {
if let DefKind::AssocTy = self.def_kind(def_id) {
self.associated_item(def_id).is_effects_desugaring
} else {
false
}
}
pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> {
variant.fields.iter_enumerated().find_map(|(i, field)| {
self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i)
})
}
#[instrument(level = "debug", skip(self), ret)]
pub fn impls_are_allowed_to_overlap(
self,
def_id1: DefId,
def_id2: DefId,
) -> Option<ImplOverlapKind> {
let impl1 = self.impl_trait_header(def_id1).unwrap();
let impl2 = self.impl_trait_header(def_id2).unwrap();
let trait_ref1 = impl1.trait_ref.skip_binder();
let trait_ref2 = impl2.trait_ref.skip_binder();
if trait_ref1.references_error() || trait_ref2.references_error() {
return Some(ImplOverlapKind::Permitted { marker: false });
}
match (impl1.polarity, impl2.polarity) {
(ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => {
return Some(ImplOverlapKind::Permitted { marker: false });
}
(ImplPolarity::Positive, ImplPolarity::Negative)
| (ImplPolarity::Negative, ImplPolarity::Positive) => {
return None;
}
(ImplPolarity::Positive, ImplPolarity::Positive)
| (ImplPolarity::Negative, ImplPolarity::Negative) => {}
};
let is_marker_impl = |trait_ref: TraitRef<'_>| self.trait_def(trait_ref.def_id).is_marker;
let is_marker_overlap = is_marker_impl(trait_ref1) && is_marker_impl(trait_ref2);
if is_marker_overlap {
return Some(ImplOverlapKind::Permitted { marker: true });
}
if let Some(self_ty1) =
self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id1)
&& let Some(self_ty2) =
self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id2)
{
if self_ty1 == self_ty2 {
return Some(ImplOverlapKind::FutureCompatOrderDepTraitObjects);
} else {
debug!("found {self_ty1:?} != {self_ty2:?}");
}
}
None
}
pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
match res {
Res::Def(DefKind::Variant, did) => {
let enum_did = self.parent(did);
self.adt_def(enum_did).variant_with_id(did)
}
Res::Def(DefKind::Struct | DefKind::Union, did) => self.adt_def(did).non_enum_variant(),
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => {
let variant_did = self.parent(variant_ctor_did);
let enum_did = self.parent(variant_did);
self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did)
}
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), ctor_did) => {
let struct_did = self.parent(ctor_did);
self.adt_def(struct_did).non_enum_variant()
}
_ => bug!("expect_variant_res used with unexpected res {:?}", res),
}
}
#[instrument(skip(self), level = "debug")]
pub fn instance_mir(self, instance: ty::InstanceKind<'tcx>) -> &'tcx Body<'tcx> {
match instance {
ty::InstanceKind::Item(def) => {
debug!("calling def_kind on def: {:?}", def);
let def_kind = self.def_kind(def);
debug!("returned from def_kind: {:?}", def_kind);
match def_kind {
DefKind::Const
| DefKind::Static { .. }
| DefKind::AssocConst
| DefKind::Ctor(..)
| DefKind::AnonConst
| DefKind::InlineConst => self.mir_for_ctfe(def),
_ => self.optimized_mir(def),
}
}
ty::InstanceKind::VTableShim(..)
| ty::InstanceKind::ReifyShim(..)
| ty::InstanceKind::Intrinsic(..)
| ty::InstanceKind::FnPtrShim(..)
| ty::InstanceKind::Virtual(..)
| ty::InstanceKind::ClosureOnceShim { .. }
| ty::InstanceKind::ConstructCoroutineInClosureShim { .. }
| ty::InstanceKind::DropGlue(..)
| ty::InstanceKind::CloneShim(..)
| ty::InstanceKind::ThreadLocalShim(..)
| ty::InstanceKind::FnPtrAddrShim(..)
| ty::InstanceKind::AsyncDropGlueCtorShim(..) => self.mir_shims(instance),
}
}
pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] {
if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did))
} else {
self.item_attrs(did)
}
}
pub fn get_attrs(
self,
did: impl Into<DefId>,
attr: Symbol,
) -> impl Iterator<Item = &'tcx ast::Attribute> {
let did: DefId = did.into();
let filter_fn = move |a: &&ast::Attribute| a.has_name(attr);
if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else {
debug_assert!(rustc_feature::encode_cross_crate(attr));
self.item_attrs(did).iter().filter(filter_fn)
}
}
pub fn get_diagnostic_attr(
self,
did: impl Into<DefId>,
attr: Symbol,
) -> Option<&'tcx ast::Attribute> {
let did: DefId = did.into();
if did.as_local().is_some() {
if rustc_feature::is_stable_diagnostic_attribute(attr, self.features()) {
self.get_attrs_by_path(did, &[sym::diagnostic, sym::do_not_recommend]).next()
} else {
None
}
} else {
debug_assert!(rustc_feature::encode_cross_crate(attr));
self.item_attrs(did)
.iter()
.find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr))
}
}
pub fn get_attrs_by_path<'attr>(
self,
did: DefId,
attr: &'attr [Symbol],
) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr
where
'tcx: 'attr,
{
let filter_fn = move |a: &&ast::Attribute| a.path_matches(attr);
if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else {
self.item_attrs(did).iter().filter(filter_fn)
}
}
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
let did: DefId = did.into();
bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
} else {
self.get_attrs(did, attr).next()
}
}
pub fn has_attr(self, did: impl Into<DefId>, attr: Symbol) -> bool {
self.get_attrs(did, attr).next().is_some()
}
pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
self.get_attrs_by_path(did.into(), attrs).next().is_some()
}
pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
self.trait_def(trait_def_id).has_auto_impl
}
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
self.trait_def(trait_def_id).is_coinductive
}
pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
self.def_kind(trait_def_id) == DefKind::TraitAlias
}
pub fn coroutine_layout(
self,
def_id: DefId,
coroutine_kind_ty: Ty<'tcx>,
) -> Option<&'tcx CoroutineLayout<'tcx>> {
let mir = self.optimized_mir(def_id);
if coroutine_kind_ty.is_unit() {
mir.coroutine_layout_raw()
} else {
let ty::Coroutine(_, identity_args) =
*self.type_of(def_id).instantiate_identity().kind()
else {
unreachable!();
};
let identity_kind_ty = identity_args.as_coroutine().kind_ty();
if identity_kind_ty == coroutine_kind_ty {
mir.coroutine_layout_raw()
} else {
assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce));
assert_matches!(
identity_kind_ty.to_opt_closure_kind(),
Some(ClosureKind::Fn | ClosureKind::FnMut)
);
self.optimized_mir(self.coroutine_by_move_body_def_id(def_id))
.coroutine_layout_raw()
}
}
}
pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
let parent = self.parent(def_id);
if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
return Some(parent);
}
}
None
}
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
let parent = self.parent(def_id);
if let DefKind::Impl { .. } = self.def_kind(parent) {
return Some(parent);
}
}
None
}
pub fn is_builtin_derived(self, def_id: DefId) -> bool {
if self.is_automatically_derived(def_id)
&& let Some(def_id) = def_id.as_local()
&& let outer = self.def_span(def_id).ctxt().outer_expn_data()
&& matches!(outer.kind, ExpnKind::Macro(MacroKind::Derive, _))
&& self.has_attr(outer.macro_def_id.unwrap(), sym::rustc_builtin_macro)
{
true
} else {
false
}
}
pub fn is_automatically_derived(self, def_id: DefId) -> bool {
self.has_attr(def_id, sym::automatically_derived)
}
pub fn span_of_impl(self, impl_def_id: DefId) -> Result<Span, Symbol> {
if let Some(impl_def_id) = impl_def_id.as_local() {
Ok(self.def_span(impl_def_id))
} else {
Err(self.crate_name(impl_def_id.krate))
}
}
pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool {
use_name.name == def_name.name
&& use_name
.span
.ctxt()
.hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id))
}
pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
ident
}
pub fn adjust_ident_and_get_scope(
self,
mut ident: Ident,
scope: DefId,
block: hir::HirId,
) -> (Ident, DefId) {
let scope = ident
.span
.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope))
.and_then(|actual_expansion| actual_expansion.expn_data().parent_module)
.unwrap_or_else(|| self.parent_module(block).to_def_id());
(ident, scope)
}
#[inline]
pub fn is_const_fn(self, def_id: DefId) -> bool {
matches!(
self.def_kind(def_id),
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure
) && self.constness(def_id) == hir::Constness::Const
}
pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
let def_id: DefId = def_id.into();
match self.def_kind(def_id) {
DefKind::Impl { of_trait: true } => {
self.constness(def_id) == hir::Constness::Const
&& self.is_const_trait(
self.trait_id_of_impl(def_id)
.expect("expected trait for trait implementation"),
)
}
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
self.constness(def_id) == hir::Constness::Const
}
DefKind::Trait => self.is_const_trait(def_id),
DefKind::AssocTy | DefKind::AssocFn => {
let parent_def_id = self.parent(def_id);
match self.def_kind(parent_def_id) {
DefKind::Impl { of_trait: false } => {
self.constness(def_id) == hir::Constness::Const
}
DefKind::Impl { of_trait: true } | DefKind::Trait => {
self.is_conditionally_const(parent_def_id)
}
_ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
}
}
DefKind::Closure | DefKind::OpaqueTy => {
false
}
DefKind::Ctor(_, CtorKind::Const)
| DefKind::Impl { of_trait: false }
| DefKind::Mod
| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::TyParam
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static { .. }
| DefKind::AssocConst
| DefKind::Macro(_)
| DefKind::ExternCrate
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::SyntheticCoroutineBody => false,
}
}
#[inline]
pub fn is_const_trait(self, def_id: DefId) -> bool {
self.trait_def(def_id).constness == hir::Constness::Const
}
#[inline]
pub fn is_const_default_method(self, def_id: DefId) -> bool {
matches!(self.trait_of_item(def_id), Some(trait_id) if self.is_const_trait(trait_id))
}
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
if self.def_kind(def_id) != DefKind::AssocFn {
return false;
}
let Some(item) = self.opt_associated_item(def_id) else {
return false;
};
if item.container != ty::AssocItemContainer::ImplContainer {
return false;
}
let Some(trait_item_def_id) = item.trait_item_def_id else {
return false;
};
return !self
.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
.is_empty();
}
}
pub fn int_ty(ity: ast::IntTy) -> IntTy {
match ity {
ast::IntTy::Isize => IntTy::Isize,
ast::IntTy::I8 => IntTy::I8,
ast::IntTy::I16 => IntTy::I16,
ast::IntTy::I32 => IntTy::I32,
ast::IntTy::I64 => IntTy::I64,
ast::IntTy::I128 => IntTy::I128,
}
}
pub fn uint_ty(uty: ast::UintTy) -> UintTy {
match uty {
ast::UintTy::Usize => UintTy::Usize,
ast::UintTy::U8 => UintTy::U8,
ast::UintTy::U16 => UintTy::U16,
ast::UintTy::U32 => UintTy::U32,
ast::UintTy::U64 => UintTy::U64,
ast::UintTy::U128 => UintTy::U128,
}
}
pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
match fty {
ast::FloatTy::F16 => FloatTy::F16,
ast::FloatTy::F32 => FloatTy::F32,
ast::FloatTy::F64 => FloatTy::F64,
ast::FloatTy::F128 => FloatTy::F128,
}
}
pub fn ast_int_ty(ity: IntTy) -> ast::IntTy {
match ity {
IntTy::Isize => ast::IntTy::Isize,
IntTy::I8 => ast::IntTy::I8,
IntTy::I16 => ast::IntTy::I16,
IntTy::I32 => ast::IntTy::I32,
IntTy::I64 => ast::IntTy::I64,
IntTy::I128 => ast::IntTy::I128,
}
}
pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy {
match uty {
UintTy::Usize => ast::UintTy::Usize,
UintTy::U8 => ast::UintTy::U8,
UintTy::U16 => ast::UintTy::U16,
UintTy::U32 => ast::UintTy::U32,
UintTy::U64 => ast::UintTy::U64,
UintTy::U128 => ast::UintTy::U128,
}
}
pub fn provide(providers: &mut Providers) {
closure::provide(providers);
context::provide(providers);
erase_regions::provide(providers);
inhabitedness::provide(providers);
util::provide(providers);
print::provide(providers);
super::util::bug::provide(providers);
super::middle::provide(providers);
*providers = Providers {
trait_impls_of: trait_def::trait_impls_of_provider,
incoherent_impls: trait_def::incoherent_impls_provider,
trait_impls_in_crate: trait_def::trait_impls_in_crate_provider,
traits: trait_def::traits_provider,
const_param_default: consts::const_param_default,
vtable_allocation: vtable::vtable_allocation_provider,
..*providers
};
}
#[derive(Clone, Debug, Default, HashStable)]
pub struct CrateInherentImpls {
pub inherent_impls: FxIndexMap<LocalDefId, Vec<DefId>>,
pub incoherent_impls: FxIndexMap<SimplifiedType, Vec<LocalDefId>>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
pub struct SymbolName<'tcx> {
pub name: &'tcx str,
}
impl<'tcx> SymbolName<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> {
SymbolName { name: tcx.arena.alloc_str(name) }
}
}
impl<'tcx> fmt::Display for SymbolName<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.name, fmt)
}
}
impl<'tcx> fmt::Debug for SymbolName<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.name, fmt)
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct InferVarInfo {
pub self_in_trait: bool,
pub output: bool,
}
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ty::Const<'tcx>],
}
#[cfg(target_pointer_width = "64")]
mod size_asserts {
use rustc_data_structures::static_assert_size;
use super::*;
static_assert_size!(PredicateKind<'_>, 32);
static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 48);
}