From 153419b78fcf12e4644f78a377b12ba6f74b758c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 15 Dec 2022 20:40:10 +0100 Subject: [PATCH 1/2] Small cleanup in parameterized --- compiler/rustc_middle/src/ty/parameterized.rs | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index c7d6c6abd1c22..e83ea8cb1e014 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -2,14 +2,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{DefId, DefIndex}; use rustc_index::vec::{Idx, IndexVec}; -use crate::middle::exported_symbols::ExportedSymbol; -use crate::mir::Body; -use crate::ty::{ - self, Clause, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty, -}; +use crate::ty; pub trait ParameterizedOverTcx: 'static { - #[allow(unused_lifetimes)] type Value<'tcx>; } @@ -100,29 +95,28 @@ trivially_parameterized_over_tcx! { rustc_type_ir::Variance, } -// HACK(compiler-errors): This macro rule can only take an ident, -// not a path, due to parsing ambiguity reasons. That means we gotta -// import all of these types above. +// HACK(compiler-errors): This macro rule can only take a fake path, +// not a real, due to parsing ambiguity reasons. #[macro_export] macro_rules! parameterized_over_tcx { - ($($ident:ident),+ $(,)?) => { + ($($($fake_path:ident)::+),+ $(,)?) => { $( - impl $crate::ty::ParameterizedOverTcx for $ident<'static> { - type Value<'tcx> = $ident<'tcx>; + impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> { + type Value<'tcx> = $($fake_path)::+<'tcx>; } )* } } parameterized_over_tcx! { - Ty, - FnSig, - GenericPredicates, - TraitRef, - Const, - Predicate, - Clause, - GeneratorDiagnosticData, - Body, - ExportedSymbol, + crate::middle::exported_symbols::ExportedSymbol, + crate::mir::Body, + ty::Ty, + ty::FnSig, + ty::GenericPredicates, + ty::TraitRef, + ty::Const, + ty::Predicate, + ty::Clause, + ty::GeneratorDiagnosticData, } From 651e41c14c9c27e7073b042f7e7cfcdcab666143 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 15 Dec 2022 20:40:16 +0100 Subject: [PATCH 2/2] Move `TypeckResults` to seperate module --- compiler/rustc_middle/src/ty/context.rs | 691 +----------------- compiler/rustc_middle/src/ty/mod.rs | 12 +- .../rustc_middle/src/ty/typeck_results.rs | 689 +++++++++++++++++ 3 files changed, 708 insertions(+), 684 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/typeck_results.rs diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 70ac5acb40ead..173c5ed4feef0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,8 +4,7 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; -use crate::hir::place::Place as HirPlace; -use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; +use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::struct_lint_level; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; @@ -18,13 +17,13 @@ use crate::thir::Thir; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, - ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid, - GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, - TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstS, DefIdTree, FloatTy, FloatVar, + FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, + ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, + ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, + Visibility, }; -use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts}; +use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -35,25 +34,20 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, WorkerLocal}; -use rustc_data_structures::unord::UnordSet; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::{ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LOCAL_CRATE}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; -use rustc_hir::hir_id::OwnerId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - Constness, ExprKind, HirId, ImplItemKind, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, - Node, TraitCandidate, TraitItemKind, + Constness, ExprKind, HirId, ImplItemKind, ItemKind, Node, TraitCandidate, TraitItemKind, }; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::IndexVec; use rustc_macros::HashStable; -use rustc_middle::mir::FakeReadCause; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -75,7 +69,6 @@ use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlag use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; -use std::collections::hash_map::{self, Entry}; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter; @@ -83,8 +76,6 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::{ImplPolarity, RvalueScopes}; - pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self @@ -284,666 +275,6 @@ pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, } -pub struct LocalTableInContext<'a, V> { - hir_owner: OwnerId, - data: &'a ItemLocalMap, -} - -/// Validate that the given HirId (respectively its `local_id` part) can be -/// safely used as a key in the maps of a TypeckResults. For that to be -/// the case, the HirId must have the same `owner` as all the other IDs in -/// this table (signified by `hir_owner`). Otherwise the HirId -/// would be in a different frame of reference and using its `local_id` -/// would result in lookup errors, or worse, in silently wrong data being -/// stored/returned. -#[inline] -fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { - if hir_id.owner != hir_owner { - invalid_hir_id_for_typeck_results(hir_owner, hir_id); - } -} - -#[cold] -#[inline(never)] -fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { - ty::tls::with(|tcx| { - bug!( - "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}", - tcx.hir().node_to_string(hir_id), - hir_id.owner, - hir_owner - ) - }); -} - -impl<'a, V> LocalTableInContext<'a, V> { - pub fn contains_key(&self, id: hir::HirId) -> bool { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.contains_key(&id.local_id) - } - - pub fn get(&self, id: hir::HirId) -> Option<&V> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.get(&id.local_id) - } - - pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> { - self.data.iter() - } -} - -impl<'a, V> ::std::ops::Index for LocalTableInContext<'a, V> { - type Output = V; - - fn index(&self, key: hir::HirId) -> &V { - self.get(key).expect("LocalTableInContext: key not found") - } -} - -pub struct LocalTableInContextMut<'a, V> { - hir_owner: OwnerId, - data: &'a mut ItemLocalMap, -} - -impl<'a, V> LocalTableInContextMut<'a, V> { - pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.get_mut(&id.local_id) - } - - pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.entry(id.local_id) - } - - pub fn insert(&mut self, id: hir::HirId, val: V) -> Option { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.insert(id.local_id, val) - } - - pub fn remove(&mut self, id: hir::HirId) -> Option { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.data.remove(&id.local_id) - } -} - -/// Whenever a value may be live across a generator yield, the type of that value winds up in the -/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such -/// captured types that can be useful for diagnostics. In particular, it stores the span that -/// caused a given type to be recorded, along with the scope that enclosed the value (which can -/// be used to find the await that the value is live across). -/// -/// For example: -/// -/// ```ignore (pseudo-Rust) -/// async move { -/// let x: T = expr; -/// foo.await -/// ... -/// } -/// ``` -/// -/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for -/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. -#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct GeneratorInteriorTypeCause<'tcx> { - /// Type of the captured binding. - pub ty: Ty<'tcx>, - /// Span of the binding that was captured. - pub span: Span, - /// Span of the scope of the captured binding. - pub scope_span: Option, - /// Span of `.await` or `yield` expression. - pub yield_span: Span, - /// Expr which the type evaluated from. - pub expr: Option, -} - -// This type holds diagnostic information on generators and async functions across crate boundaries -// and is used to provide better error messages -#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)] -pub struct GeneratorDiagnosticData<'tcx> { - pub generator_interior_types: ty::Binder<'tcx, Vec>>, - pub hir_owner: DefId, - pub nodes_types: ItemLocalMap>, - pub adjustments: ItemLocalMap>>, -} - -#[derive(TyEncodable, TyDecodable, Debug, HashStable)] -pub struct TypeckResults<'tcx> { - /// The `HirId::owner` all `ItemLocalId`s in this table are relative to. - pub hir_owner: OwnerId, - - /// Resolved definitions for `::X` associated paths and - /// method calls, including those of overloaded operators. - type_dependent_defs: ItemLocalMap>, - - /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) - /// or patterns (`S { field }`). The index is often useful by itself, but to learn more - /// about the field you also need definition of the variant to which the field - /// belongs, but it may not exist if it's a tuple field (`tuple.0`). - field_indices: ItemLocalMap, - - /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated outside inference. See - /// typeck::check::fn_ctxt for details. - node_types: ItemLocalMap>, - - /// Stores the type parameters which were substituted to obtain the type - /// of this node. This only applies to nodes that refer to entities - /// parameterized by type parameters, such as generic fns, types, or - /// other items. - node_substs: ItemLocalMap>, - - /// This will either store the canonicalized types provided by the user - /// or the substitutions that the user explicitly gave (if any) attached - /// to `id`. These will not include any inferred values. The canonical form - /// is used to capture things like `_` or other unspecified values. - /// - /// For example, if the user wrote `foo.collect::>()`, then the - /// canonical substitutions would include only `for { Vec }`. - /// - /// See also `AscribeUserType` statement in MIR. - user_provided_types: ItemLocalMap>, - - /// Stores the canonicalized types provided by the user. See also - /// `AscribeUserType` statement in MIR. - pub user_provided_sigs: LocalDefIdMap>, - - adjustments: ItemLocalMap>>, - - /// Stores the actual binding mode for all instances of hir::BindingAnnotation. - pat_binding_modes: ItemLocalMap, - - /// Stores the types which were implicitly dereferenced in pattern binding modes - /// for later usage in THIR lowering. For example, - /// - /// ``` - /// match &&Some(5i32) { - /// Some(n) => {}, - /// _ => {}, - /// } - /// ``` - /// leads to a `vec![&&Option, &Option]`. Empty vectors are not stored. - /// - /// See: - /// - pat_adjustments: ItemLocalMap>>, - - /// Records the reasons that we picked the kind of each closure; - /// not all closures are present in the map. - closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, - - /// For each fn, records the "liberated" types of its arguments - /// and return type. Liberated means that all bound regions - /// (including late-bound regions) are replaced with free - /// equivalents. This table is not used in codegen (since regions - /// are erased there) and hence is not serialized to metadata. - /// - /// This table also contains the "revealed" values for any `impl Trait` - /// that appear in the signature and whose values are being inferred - /// by this function. - /// - /// # Example - /// - /// ```rust - /// # use std::fmt::Debug; - /// fn foo(x: &u32) -> impl Debug { *x } - /// ``` - /// - /// The function signature here would be: - /// - /// ```ignore (illustrative) - /// for<'a> fn(&'a u32) -> Foo - /// ``` - /// - /// where `Foo` is an opaque type created for this function. - /// - /// - /// The *liberated* form of this would be - /// - /// ```ignore (illustrative) - /// fn(&'a u32) -> u32 - /// ``` - /// - /// Note that `'a` is not bound (it would be an `ReFree`) and - /// that the `Foo` opaque type is replaced by its hidden type. - liberated_fn_sigs: ItemLocalMap>, - - /// For each FRU expression, record the normalized types of the fields - /// of the struct - this is needed because it is non-trivial to - /// normalize while preserving regions. This table is used only in - /// MIR construction and hence is not serialized to metadata. - fru_field_types: ItemLocalMap>>, - - /// For every coercion cast we add the HIR node ID of the cast - /// expression to this set. - coercion_casts: ItemLocalSet, - - /// Set of trait imports actually used in the method resolution. - /// This is used for warning unused imports. During type - /// checking, this `Lrc` should not be cloned: it must have a ref-count - /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc>, - - /// If any errors occurred while type-checking this body, - /// this field will be set to `Some(ErrorGuaranteed)`. - pub tainted_by_errors: Option, - - /// All the opaque types that have hidden types set - /// by this function. We also store the - /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, - /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap>, - - /// Tracks the minimum captures required for a closure; - /// see `MinCaptureInformationMap` for more details. - pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, - - /// Tracks the fake reads required for a closure and the reason for the fake read. - /// When performing pattern matching for closures, there are times we don't end up - /// reading places that are mentioned in a closure (because of _ patterns). However, - /// to ensure the places are initialized, we introduce fake reads. - /// Consider these two examples: - /// ``` (discriminant matching with only wildcard arm) - /// let x: u8; - /// let c = || match x { _ => () }; - /// ``` - /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't - /// want to capture it. However, we do still want an error here, because `x` should have - /// to be initialized at the point where c is created. Therefore, we add a "fake read" - /// instead. - /// ``` (destructured assignments) - /// let c = || { - /// let (t1, t2) = t; - /// } - /// ``` - /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but - /// we never capture `t`. This becomes an issue when we build MIR as we require - /// information on `t` in order to create place `t.0` and `t.1`. We can solve this - /// issue by fake reading `t`. - pub closure_fake_reads: FxHashMap, FakeReadCause, hir::HirId)>>, - - /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions - /// by applying extended parameter rules. - /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. - pub rvalue_scopes: RvalueScopes, - - /// Stores the type, expression, span and optional scope span of all types - /// that are live across the yield of this generator (if a generator). - pub generator_interior_types: ty::Binder<'tcx, Vec>>, - - /// We sometimes treat byte string literals (which are of type `&[u8; N]`) - /// as `&[u8]`, depending on the pattern in which they are used. - /// This hashset records all instances where we behave - /// like this to allow `const_to_pat` to reliably handle this situation. - pub treat_byte_string_as_slice: ItemLocalSet, - - /// Contains the data for evaluating the effect of feature `capture_disjoint_fields` - /// on closure size. - pub closure_size_eval: FxHashMap>, -} - -impl<'tcx> TypeckResults<'tcx> { - pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> { - TypeckResults { - hir_owner, - type_dependent_defs: Default::default(), - field_indices: Default::default(), - user_provided_types: Default::default(), - user_provided_sigs: Default::default(), - node_types: Default::default(), - node_substs: Default::default(), - adjustments: Default::default(), - pat_binding_modes: Default::default(), - pat_adjustments: Default::default(), - closure_kind_origins: Default::default(), - liberated_fn_sigs: Default::default(), - fru_field_types: Default::default(), - coercion_casts: Default::default(), - used_trait_imports: Lrc::new(Default::default()), - tainted_by_errors: None, - concrete_opaque_types: Default::default(), - closure_min_captures: Default::default(), - closure_fake_reads: Default::default(), - rvalue_scopes: Default::default(), - generator_interior_types: ty::Binder::dummy(Default::default()), - treat_byte_string_as_slice: Default::default(), - closure_size_eval: Default::default(), - } - } - - /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node. - pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { - match *qpath { - hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self - .type_dependent_def(id) - .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), - } - } - - pub fn type_dependent_defs( - &self, - ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs } - } - - pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok()) - } - - pub fn type_dependent_def_id(&self, id: HirId) -> Option { - self.type_dependent_def(id).map(|(_, def_id)| def_id) - } - - pub fn type_dependent_defs_mut( - &mut self, - ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs } - } - - pub fn field_indices(&self) -> LocalTableInContext<'_, usize> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices } - } - - pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices } - } - - pub fn field_index(&self, id: hir::HirId) -> usize { - self.field_indices().get(id).cloned().expect("no index for a field") - } - - pub fn opt_field_index(&self, id: hir::HirId) -> Option { - self.field_indices().get(id).cloned() - } - - pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types } - } - - pub fn user_provided_types_mut( - &mut self, - ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types } - } - - pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types } - } - - pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types } - } - - pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> { - let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| { - vec.iter() - .map(|item| { - GeneratorInteriorTypeCause { - ty: item.ty, - span: item.span, - scope_span: item.scope_span, - yield_span: item.yield_span, - expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment - } - }) - .collect::>() - }); - GeneratorDiagnosticData { - generator_interior_types: generator_interior_type, - hir_owner: self.hir_owner.to_def_id(), - nodes_types: self.node_types.clone(), - adjustments: self.adjustments.clone(), - } - } - - pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { - self.node_type_opt(id).unwrap_or_else(|| { - bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id))) - }) - } - - pub fn node_type_opt(&self, id: hir::HirId) -> Option> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.node_types.get(&id.local_id).cloned() - } - - pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs } - } - - pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty()) - } - - pub fn node_substs_opt(&self, id: hir::HirId) -> Option> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.node_substs.get(&id.local_id).cloned() - } - - /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function - /// doesn't provide type parameter substitutions. - /// - /// [`expr_ty`]: TypeckResults::expr_ty - pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> { - self.node_type(pat.hir_id) - } - - /// Returns the type of an expression as a monotype. - /// - /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - /// some cases, we insert `Adjustment` annotations such as auto-deref or - /// auto-ref. The type returned by this function does not consider such - /// adjustments. See `expr_ty_adjusted()` instead. - /// - /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you - /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize` - /// instead of `fn(ty) -> T with T = isize`. - pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { - self.node_type(expr.hir_id) - } - - pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option> { - self.node_type_opt(expr.hir_id) - } - - pub fn adjustments(&self) -> LocalTableInContext<'_, Vec>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments } - } - - pub fn adjustments_mut( - &mut self, - ) -> LocalTableInContextMut<'_, Vec>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments } - } - - pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] { - validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id); - self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) - } - - /// Returns the type of `expr`, considering any `Adjustment` - /// entry recorded for that expression. - pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { - self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target) - } - - pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option> { - self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) - } - - pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool { - // Only paths and method calls/overloaded operators have - // entries in type_dependent_defs, ignore the former here. - if let hir::ExprKind::Path(_) = expr.kind { - return false; - } - - matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _)))) - } - - pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { - self.pat_binding_modes().get(id).copied().or_else(|| { - s.delay_span_bug(sp, "missing binding mode"); - None - }) - } - - pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes } - } - - pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } - } - - pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments } - } - - pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } - } - - /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured - /// by the closure. - pub fn closure_min_captures_flattened( - &self, - closure_def_id: LocalDefId, - ) -> impl Iterator> { - self.closure_min_captures - .get(&closure_def_id) - .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter())) - .into_iter() - .flatten() - } - - pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins } - } - - pub fn closure_kind_origins_mut( - &mut self, - ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins } - } - - pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs } - } - - pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs } - } - - pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec>> { - LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types } - } - - pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec>> { - LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types } - } - - pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool { - validate_hir_id_for_typeck_results(self.hir_owner, hir_id); - self.coercion_casts.contains(&hir_id.local_id) - } - - pub fn set_coercion_cast(&mut self, id: ItemLocalId) { - self.coercion_casts.insert(id); - } - - pub fn coercion_casts(&self) -> &ItemLocalSet { - &self.coercion_casts - } -} - -rustc_index::newtype_index! { - pub struct UserTypeAnnotationIndex { - derive [HashStable] - DEBUG_FORMAT = "UserType({})", - const START_INDEX = 0, - } -} - -/// Mapping of type annotation indices to canonical user type annotations. -pub type CanonicalUserTypeAnnotations<'tcx> = - IndexVec>; - -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct CanonicalUserTypeAnnotation<'tcx> { - pub user_ty: Box>, - pub span: Span, - pub inferred_ty: Ty<'tcx>, -} - -/// Canonicalized user type annotation. -pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>; - -impl<'tcx> CanonicalUserType<'tcx> { - /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, - /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - match self.value { - UserType::Ty(_) => false, - UserType::TypeOf(_, user_substs) => { - if user_substs.user_self_ty.is_some() { - return false; - } - - iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| { - match kind.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debruijn, ty::INNERMOST); - cvar == b.var - } - _ => false, - }, - - GenericArgKind::Lifetime(r) => match *r { - ty::ReLateBound(debruijn, br) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - cvar == br.var - } - _ => false, - }, - - GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - cvar == b - } - _ => false, - }, - } - }) - } - } - } -} - -/// A user-given type annotation attached to a constant. These arise -/// from constants that are named via paths, like `Foo::::new` and -/// so forth. -#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum UserType<'tcx> { - Ty(Ty<'tcx>), - - /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. - TypeOf(DefId, UserSubsts<'tcx>), -} - impl<'tcx> CommonTypes<'tcx> { fn new( interners: &CtxtInterners<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5232c1e1cc0f8..7290f0ae7c035 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -83,10 +83,8 @@ pub use self::consts::{ Const, ConstInt, ConstKind, ConstS, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, - CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData, - GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults, - UserType, UserTypeAnnotationIndex, + tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt, + TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance}; pub use self::list::List; @@ -103,6 +101,11 @@ pub use self::sty::{ Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; +pub use self::typeck_results::{ + CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType, + UserTypeAnnotationIndex, +}; pub mod _match; pub mod abstract_const; @@ -143,6 +146,7 @@ mod parameterized; mod rvalue_scopes; mod structural_impls; mod sty; +mod typeck_results; // Data types diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs new file mode 100644 index 0000000000000..4fe85d4366f3e --- /dev/null +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -0,0 +1,689 @@ +use crate::{ + hir::place::Place as HirPlace, + infer::canonical::Canonical, + ty::{ + self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, + GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, + }, +}; +use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap}; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; +use rustc_hir::{ + def::{DefKind, Res}, + def_id::{DefId, LocalDefId, LocalDefIdMap}, + hir_id::OwnerId, + HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, +}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_macros::HashStable; +use rustc_middle::mir::FakeReadCause; +use rustc_session::Session; +use rustc_span::Span; +use std::{ + collections::hash_map::{self, Entry}, + hash::Hash, + iter, +}; + +use super::RvalueScopes; + +#[derive(TyEncodable, TyDecodable, Debug, HashStable)] +pub struct TypeckResults<'tcx> { + /// The `HirId::owner` all `ItemLocalId`s in this table are relative to. + pub hir_owner: OwnerId, + + /// Resolved definitions for `::X` associated paths and + /// method calls, including those of overloaded operators. + type_dependent_defs: ItemLocalMap>, + + /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) + /// or patterns (`S { field }`). The index is often useful by itself, but to learn more + /// about the field you also need definition of the variant to which the field + /// belongs, but it may not exist if it's a tuple field (`tuple.0`). + field_indices: ItemLocalMap, + + /// Stores the types for various nodes in the AST. Note that this table + /// is not guaranteed to be populated outside inference. See + /// typeck::check::fn_ctxt for details. + node_types: ItemLocalMap>, + + /// Stores the type parameters which were substituted to obtain the type + /// of this node. This only applies to nodes that refer to entities + /// parameterized by type parameters, such as generic fns, types, or + /// other items. + node_substs: ItemLocalMap>, + + /// This will either store the canonicalized types provided by the user + /// or the substitutions that the user explicitly gave (if any) attached + /// to `id`. These will not include any inferred values. The canonical form + /// is used to capture things like `_` or other unspecified values. + /// + /// For example, if the user wrote `foo.collect::>()`, then the + /// canonical substitutions would include only `for { Vec }`. + /// + /// See also `AscribeUserType` statement in MIR. + user_provided_types: ItemLocalMap>, + + /// Stores the canonicalized types provided by the user. See also + /// `AscribeUserType` statement in MIR. + pub user_provided_sigs: LocalDefIdMap>, + + adjustments: ItemLocalMap>>, + + /// Stores the actual binding mode for all instances of hir::BindingAnnotation. + pat_binding_modes: ItemLocalMap, + + /// Stores the types which were implicitly dereferenced in pattern binding modes + /// for later usage in THIR lowering. For example, + /// + /// ``` + /// match &&Some(5i32) { + /// Some(n) => {}, + /// _ => {}, + /// } + /// ``` + /// leads to a `vec![&&Option, &Option]`. Empty vectors are not stored. + /// + /// See: + /// + pat_adjustments: ItemLocalMap>>, + + /// Records the reasons that we picked the kind of each closure; + /// not all closures are present in the map. + closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, + + /// For each fn, records the "liberated" types of its arguments + /// and return type. Liberated means that all bound regions + /// (including late-bound regions) are replaced with free + /// equivalents. This table is not used in codegen (since regions + /// are erased there) and hence is not serialized to metadata. + /// + /// This table also contains the "revealed" values for any `impl Trait` + /// that appear in the signature and whose values are being inferred + /// by this function. + /// + /// # Example + /// + /// ```rust + /// # use std::fmt::Debug; + /// fn foo(x: &u32) -> impl Debug { *x } + /// ``` + /// + /// The function signature here would be: + /// + /// ```ignore (illustrative) + /// for<'a> fn(&'a u32) -> Foo + /// ``` + /// + /// where `Foo` is an opaque type created for this function. + /// + /// + /// The *liberated* form of this would be + /// + /// ```ignore (illustrative) + /// fn(&'a u32) -> u32 + /// ``` + /// + /// Note that `'a` is not bound (it would be an `ReFree`) and + /// that the `Foo` opaque type is replaced by its hidden type. + liberated_fn_sigs: ItemLocalMap>, + + /// For each FRU expression, record the normalized types of the fields + /// of the struct - this is needed because it is non-trivial to + /// normalize while preserving regions. This table is used only in + /// MIR construction and hence is not serialized to metadata. + fru_field_types: ItemLocalMap>>, + + /// For every coercion cast we add the HIR node ID of the cast + /// expression to this set. + coercion_casts: ItemLocalSet, + + /// Set of trait imports actually used in the method resolution. + /// This is used for warning unused imports. During type + /// checking, this `Lrc` should not be cloned: it must have a ref-count + /// of 1 so that we can insert things into the set mutably. + pub used_trait_imports: Lrc>, + + /// If any errors occurred while type-checking this body, + /// this field will be set to `Some(ErrorGuaranteed)`. + pub tainted_by_errors: Option, + + /// All the opaque types that have hidden types set + /// by this function. We also store the + /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, + /// even if they are only set in dead code (which doesn't show up in MIR). + pub concrete_opaque_types: VecMap>, + + /// Tracks the minimum captures required for a closure; + /// see `MinCaptureInformationMap` for more details. + pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, + + /// Tracks the fake reads required for a closure and the reason for the fake read. + /// When performing pattern matching for closures, there are times we don't end up + /// reading places that are mentioned in a closure (because of _ patterns). However, + /// to ensure the places are initialized, we introduce fake reads. + /// Consider these two examples: + /// ``` (discriminant matching with only wildcard arm) + /// let x: u8; + /// let c = || match x { _ => () }; + /// ``` + /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't + /// want to capture it. However, we do still want an error here, because `x` should have + /// to be initialized at the point where c is created. Therefore, we add a "fake read" + /// instead. + /// ``` (destructured assignments) + /// let c = || { + /// let (t1, t2) = t; + /// } + /// ``` + /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but + /// we never capture `t`. This becomes an issue when we build MIR as we require + /// information on `t` in order to create place `t.0` and `t.1`. We can solve this + /// issue by fake reading `t`. + pub closure_fake_reads: FxHashMap, FakeReadCause, hir::HirId)>>, + + /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions + /// by applying extended parameter rules. + /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. + pub rvalue_scopes: RvalueScopes, + + /// Stores the type, expression, span and optional scope span of all types + /// that are live across the yield of this generator (if a generator). + pub generator_interior_types: ty::Binder<'tcx, Vec>>, + + /// We sometimes treat byte string literals (which are of type `&[u8; N]`) + /// as `&[u8]`, depending on the pattern in which they are used. + /// This hashset records all instances where we behave + /// like this to allow `const_to_pat` to reliably handle this situation. + pub treat_byte_string_as_slice: ItemLocalSet, + + /// Contains the data for evaluating the effect of feature `capture_disjoint_fields` + /// on closure size. + pub closure_size_eval: FxHashMap>, +} + +/// Whenever a value may be live across a generator yield, the type of that value winds up in the +/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such +/// captured types that can be useful for diagnostics. In particular, it stores the span that +/// caused a given type to be recorded, along with the scope that enclosed the value (which can +/// be used to find the await that the value is live across). +/// +/// For example: +/// +/// ```ignore (pseudo-Rust) +/// async move { +/// let x: T = expr; +/// foo.await +/// ... +/// } +/// ``` +/// +/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for +/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. +#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct GeneratorInteriorTypeCause<'tcx> { + /// Type of the captured binding. + pub ty: Ty<'tcx>, + /// Span of the binding that was captured. + pub span: Span, + /// Span of the scope of the captured binding. + pub scope_span: Option, + /// Span of `.await` or `yield` expression. + pub yield_span: Span, + /// Expr which the type evaluated from. + pub expr: Option, +} + +// This type holds diagnostic information on generators and async functions across crate boundaries +// and is used to provide better error messages +#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)] +pub struct GeneratorDiagnosticData<'tcx> { + pub generator_interior_types: ty::Binder<'tcx, Vec>>, + pub hir_owner: DefId, + pub nodes_types: ItemLocalMap>, + pub adjustments: ItemLocalMap>>, +} + +impl<'tcx> TypeckResults<'tcx> { + pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> { + TypeckResults { + hir_owner, + type_dependent_defs: Default::default(), + field_indices: Default::default(), + user_provided_types: Default::default(), + user_provided_sigs: Default::default(), + node_types: Default::default(), + node_substs: Default::default(), + adjustments: Default::default(), + pat_binding_modes: Default::default(), + pat_adjustments: Default::default(), + closure_kind_origins: Default::default(), + liberated_fn_sigs: Default::default(), + fru_field_types: Default::default(), + coercion_casts: Default::default(), + used_trait_imports: Lrc::new(Default::default()), + tainted_by_errors: None, + concrete_opaque_types: Default::default(), + closure_min_captures: Default::default(), + closure_fake_reads: Default::default(), + rvalue_scopes: Default::default(), + generator_interior_types: ty::Binder::dummy(Default::default()), + treat_byte_string_as_slice: Default::default(), + closure_size_eval: Default::default(), + } + } + + /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node. + pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { + match *qpath { + hir::QPath::Resolved(_, ref path) => path.res, + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self + .type_dependent_def(id) + .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), + } + } + + pub fn type_dependent_defs( + &self, + ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs } + } + + pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok()) + } + + pub fn type_dependent_def_id(&self, id: HirId) -> Option { + self.type_dependent_def(id).map(|(_, def_id)| def_id) + } + + pub fn type_dependent_defs_mut( + &mut self, + ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs } + } + + pub fn field_indices(&self) -> LocalTableInContext<'_, usize> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices } + } + + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices } + } + + pub fn field_index(&self, id: hir::HirId) -> usize { + self.field_indices().get(id).cloned().expect("no index for a field") + } + + pub fn opt_field_index(&self, id: hir::HirId) -> Option { + self.field_indices().get(id).cloned() + } + + pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types } + } + + pub fn user_provided_types_mut( + &mut self, + ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types } + } + + pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types } + } + + pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types } + } + + pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> { + let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| { + vec.iter() + .map(|item| { + GeneratorInteriorTypeCause { + ty: item.ty, + span: item.span, + scope_span: item.scope_span, + yield_span: item.yield_span, + expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment + } + }) + .collect::>() + }); + GeneratorDiagnosticData { + generator_interior_types: generator_interior_type, + hir_owner: self.hir_owner.to_def_id(), + nodes_types: self.node_types.clone(), + adjustments: self.adjustments.clone(), + } + } + + pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> { + self.node_type_opt(id).unwrap_or_else(|| { + bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id))) + }) + } + + pub fn node_type_opt(&self, id: hir::HirId) -> Option> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.node_types.get(&id.local_id).cloned() + } + + pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs } + } + + pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty()) + } + + pub fn node_substs_opt(&self, id: hir::HirId) -> Option> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.node_substs.get(&id.local_id).cloned() + } + + /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function + /// doesn't provide type parameter substitutions. + /// + /// [`expr_ty`]: TypeckResults::expr_ty + pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> { + self.node_type(pat.hir_id) + } + + /// Returns the type of an expression as a monotype. + /// + /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + /// some cases, we insert `Adjustment` annotations such as auto-deref or + /// auto-ref. The type returned by this function does not consider such + /// adjustments. See `expr_ty_adjusted()` instead. + /// + /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you + /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize` + /// instead of `fn(ty) -> T with T = isize`. + pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { + self.node_type(expr.hir_id) + } + + pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option> { + self.node_type_opt(expr.hir_id) + } + + pub fn adjustments(&self) -> LocalTableInContext<'_, Vec>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments } + } + + pub fn adjustments_mut( + &mut self, + ) -> LocalTableInContextMut<'_, Vec>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments } + } + + pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] { + validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id); + self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) + } + + /// Returns the type of `expr`, considering any `Adjustment` + /// entry recorded for that expression. + pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { + self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target) + } + + pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option> { + self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) + } + + pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool { + // Only paths and method calls/overloaded operators have + // entries in type_dependent_defs, ignore the former here. + if let hir::ExprKind::Path(_) = expr.kind { + return false; + } + + matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _)))) + } + + pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { + self.pat_binding_modes().get(id).copied().or_else(|| { + s.delay_span_bug(sp, "missing binding mode"); + None + }) + } + + pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes } + } + + pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } + } + + pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments } + } + + pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } + } + + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured + /// by the closure. + pub fn closure_min_captures_flattened( + &self, + closure_def_id: LocalDefId, + ) -> impl Iterator> { + self.closure_min_captures + .get(&closure_def_id) + .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter())) + .into_iter() + .flatten() + } + + pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins } + } + + pub fn closure_kind_origins_mut( + &mut self, + ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins } + } + + pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs } + } + + pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs } + } + + pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types } + } + + pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types } + } + + pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, hir_id); + self.coercion_casts.contains(&hir_id.local_id) + } + + pub fn set_coercion_cast(&mut self, id: ItemLocalId) { + self.coercion_casts.insert(id); + } + + pub fn coercion_casts(&self) -> &ItemLocalSet { + &self.coercion_casts + } +} + +/// Validate that the given HirId (respectively its `local_id` part) can be +/// safely used as a key in the maps of a TypeckResults. For that to be +/// the case, the HirId must have the same `owner` as all the other IDs in +/// this table (signified by `hir_owner`). Otherwise the HirId +/// would be in a different frame of reference and using its `local_id` +/// would result in lookup errors, or worse, in silently wrong data being +/// stored/returned. +#[inline] +fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { + if hir_id.owner != hir_owner { + invalid_hir_id_for_typeck_results(hir_owner, hir_id); + } +} + +#[cold] +#[inline(never)] +fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) { + ty::tls::with(|tcx| { + bug!( + "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}", + tcx.hir().node_to_string(hir_id), + hir_id.owner, + hir_owner + ) + }); +} + +pub struct LocalTableInContext<'a, V> { + hir_owner: OwnerId, + data: &'a ItemLocalMap, +} + +impl<'a, V> LocalTableInContext<'a, V> { + pub fn contains_key(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains_key(&id.local_id) + } + + pub fn get(&self, id: hir::HirId) -> Option<&V> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.get(&id.local_id) + } + + pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> { + self.data.iter() + } +} + +impl<'a, V> ::std::ops::Index for LocalTableInContext<'a, V> { + type Output = V; + + fn index(&self, key: hir::HirId) -> &V { + self.get(key).expect("LocalTableInContext: key not found") + } +} + +pub struct LocalTableInContextMut<'a, V> { + hir_owner: OwnerId, + data: &'a mut ItemLocalMap, +} + +impl<'a, V> LocalTableInContextMut<'a, V> { + pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.get_mut(&id.local_id) + } + + pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.entry(id.local_id) + } + + pub fn insert(&mut self, id: hir::HirId, val: V) -> Option { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.insert(id.local_id, val) + } + + pub fn remove(&mut self, id: hir::HirId) -> Option { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.remove(&id.local_id) + } +} + +rustc_index::newtype_index! { + pub struct UserTypeAnnotationIndex { + derive [HashStable] + DEBUG_FORMAT = "UserType({})", + const START_INDEX = 0, + } +} + +/// Mapping of type annotation indices to canonical user type annotations. +pub type CanonicalUserTypeAnnotations<'tcx> = + IndexVec>; + +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct CanonicalUserTypeAnnotation<'tcx> { + pub user_ty: Box>, + pub span: Span, + pub inferred_ty: Ty<'tcx>, +} + +/// Canonicalized user type annotation. +pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>; + +impl<'tcx> CanonicalUserType<'tcx> { + /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, + /// i.e., each thing is mapped to a canonical variable with the same index. + pub fn is_identity(&self) -> bool { + match self.value { + UserType::Ty(_) => false, + UserType::TypeOf(_, user_substs) => { + if user_substs.user_self_ty.is_some() { + return false; + } + + iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| { + match kind.unpack() { + GenericArgKind::Type(ty) => match ty.kind() { + ty::Bound(debruijn, b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*debruijn, ty::INNERMOST); + cvar == b.var + } + _ => false, + }, + + GenericArgKind::Lifetime(r) => match *r { + ty::ReLateBound(debruijn, br) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(debruijn, ty::INNERMOST); + cvar == br.var + } + _ => false, + }, + + GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Bound(debruijn, b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(debruijn, ty::INNERMOST); + cvar == b + } + _ => false, + }, + } + }) + } + } + } +} + +/// A user-given type annotation attached to a constant. These arise +/// from constants that are named via paths, like `Foo::::new` and +/// so forth. +#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +pub enum UserType<'tcx> { + Ty(Ty<'tcx>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, UserSubsts<'tcx>), +}