2773 lines
102 KiB
Rust
2773 lines
102 KiB
Rust
//! This crate is responsible for the part of name resolution that doesn't require type checker.
|
||
//!
|
||
//! Module structure of the crate is built here.
|
||
//! Paths in macros, imports, expressions, types, patterns are resolved here.
|
||
//! Label and lifetime names are resolved here as well.
|
||
//!
|
||
//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
|
||
|
||
// tidy-alphabetical-start
|
||
#![allow(internal_features)]
|
||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||
#![cfg_attr(bootstrap, feature(ptr_as_ref_unchecked))]
|
||
#![feature(arbitrary_self_types)]
|
||
#![feature(box_patterns)]
|
||
#![feature(const_default)]
|
||
#![feature(const_trait_impl)]
|
||
#![feature(control_flow_into_value)]
|
||
#![feature(decl_macro)]
|
||
#![feature(default_field_values)]
|
||
#![feature(if_let_guard)]
|
||
#![feature(iter_intersperse)]
|
||
#![feature(rustc_attrs)]
|
||
#![feature(trim_prefix_suffix)]
|
||
#![recursion_limit = "256"]
|
||
// tidy-alphabetical-end
|
||
|
||
use std::cell::Ref;
|
||
use std::collections::BTreeSet;
|
||
use std::fmt::{self};
|
||
use std::ops::ControlFlow;
|
||
use std::sync::Arc;
|
||
|
||
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
|
||
use effective_visibilities::EffectiveVisibilitiesVisitor;
|
||
use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
|
||
use hygiene::Macros20NormalizedSyntaxContext;
|
||
use imports::{Import, ImportData, ImportKind, NameResolution, PendingDecl};
|
||
use late::{
|
||
ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource,
|
||
UnnecessaryQualification,
|
||
};
|
||
use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
|
||
use rustc_arena::{DroplessArena, TypedArena};
|
||
use rustc_ast::node_id::NodeMap;
|
||
use rustc_ast::{
|
||
self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs,
|
||
NodeId, Path, attr,
|
||
};
|
||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default};
|
||
use rustc_data_structures::intern::Interned;
|
||
use rustc_data_structures::steal::Steal;
|
||
use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
|
||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer};
|
||
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
|
||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||
use rustc_hir::attrs::{AttributeKind, StrippedCfgItem};
|
||
use rustc_hir::def::Namespace::{self, *};
|
||
use rustc_hir::def::{
|
||
self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes,
|
||
PerNS,
|
||
};
|
||
use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
|
||
use rustc_hir::definitions::DisambiguatorState;
|
||
use rustc_hir::{PrimTy, TraitCandidate, find_attr};
|
||
use rustc_index::bit_set::DenseBitSet;
|
||
use rustc_metadata::creader::CStore;
|
||
use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport};
|
||
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
||
use rustc_middle::query::Providers;
|
||
use rustc_middle::ty::{
|
||
self, DelegationFnSig, DelegationInfo, Feed, MainDefinition, RegisteredTools,
|
||
ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility,
|
||
};
|
||
use rustc_session::config::CrateType;
|
||
use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
|
||
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
|
||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||
use smallvec::{SmallVec, smallvec};
|
||
use tracing::debug;
|
||
|
||
type Res = def::Res<NodeId>;
|
||
|
||
mod build_reduced_graph;
|
||
mod check_unused;
|
||
mod def_collector;
|
||
mod diagnostics;
|
||
mod effective_visibilities;
|
||
mod errors;
|
||
mod ident;
|
||
mod imports;
|
||
mod late;
|
||
mod macros;
|
||
pub mod rustdoc;
|
||
|
||
pub use macros::registered_tools_ast;
|
||
|
||
use crate::ref_mut::{CmCell, CmRefCell};
|
||
|
||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||
enum Determinacy {
|
||
Determined,
|
||
Undetermined,
|
||
}
|
||
|
||
impl Determinacy {
|
||
fn determined(determined: bool) -> Determinacy {
|
||
if determined { Determinacy::Determined } else { Determinacy::Undetermined }
|
||
}
|
||
}
|
||
|
||
/// A specific scope in which a name can be looked up.
|
||
#[derive(Clone, Copy, Debug)]
|
||
enum Scope<'ra> {
|
||
/// Inert attributes registered by derive macros.
|
||
DeriveHelpers(LocalExpnId),
|
||
/// Inert attributes registered by derive macros, but used before they are actually declared.
|
||
/// This scope will exist until the compatibility lint `LEGACY_DERIVE_HELPERS`
|
||
/// is turned into a hard error.
|
||
DeriveHelpersCompat,
|
||
/// Textual `let`-like scopes introduced by `macro_rules!` items.
|
||
MacroRules(MacroRulesScopeRef<'ra>),
|
||
/// Non-glob names declared in the given module.
|
||
/// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
|
||
/// lint if it should be reported.
|
||
ModuleNonGlobs(Module<'ra>, Option<NodeId>),
|
||
/// Glob names declared in the given module.
|
||
/// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
|
||
/// lint if it should be reported.
|
||
ModuleGlobs(Module<'ra>, Option<NodeId>),
|
||
/// Names introduced by `#[macro_use]` attributes on `extern crate` items.
|
||
MacroUsePrelude,
|
||
/// Built-in attributes.
|
||
BuiltinAttrs,
|
||
/// Extern prelude names introduced by `extern crate` items.
|
||
ExternPreludeItems,
|
||
/// Extern prelude names introduced by `--extern` flags.
|
||
ExternPreludeFlags,
|
||
/// Tool modules introduced with `#![register_tool]`.
|
||
ToolPrelude,
|
||
/// Standard library prelude introduced with an internal `#[prelude_import]` import.
|
||
StdLibPrelude,
|
||
/// Built-in types.
|
||
BuiltinTypes,
|
||
}
|
||
|
||
/// Names from different contexts may want to visit different subsets of all specific scopes
|
||
/// with different restrictions when looking up the resolution.
|
||
#[derive(Clone, Copy, Debug)]
|
||
enum ScopeSet<'ra> {
|
||
/// All scopes with the given namespace.
|
||
All(Namespace),
|
||
/// Two scopes inside a module, for non-glob and glob bindings.
|
||
Module(Namespace, Module<'ra>),
|
||
/// A module, then extern prelude (used for mixed 2015-2018 mode in macros).
|
||
ModuleAndExternPrelude(Namespace, Module<'ra>),
|
||
/// Just two extern prelude scopes.
|
||
ExternPrelude,
|
||
/// Same as `All(MacroNS)`, but with the given macro kind restriction.
|
||
Macro(MacroKind),
|
||
}
|
||
|
||
/// Everything you need to know about a name's location to resolve it.
|
||
/// Serves as a starting point for the scope visitor.
|
||
/// This struct is currently used only for early resolution (imports and macros),
|
||
/// but not for late resolution yet.
|
||
#[derive(Clone, Copy, Debug)]
|
||
struct ParentScope<'ra> {
|
||
module: Module<'ra>,
|
||
expansion: LocalExpnId,
|
||
macro_rules: MacroRulesScopeRef<'ra>,
|
||
derives: &'ra [ast::Path],
|
||
}
|
||
|
||
impl<'ra> ParentScope<'ra> {
|
||
/// Creates a parent scope with the passed argument used as the module scope component,
|
||
/// and other scope components set to default empty values.
|
||
fn module(module: Module<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> {
|
||
ParentScope {
|
||
module,
|
||
expansion: LocalExpnId::ROOT,
|
||
macro_rules: arenas.alloc_macro_rules_scope(MacroRulesScope::Empty),
|
||
derives: &[],
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Debug, Clone)]
|
||
struct InvocationParent {
|
||
parent_def: LocalDefId,
|
||
impl_trait_context: ImplTraitContext,
|
||
in_attr: bool,
|
||
const_arg_context: ConstArgContext,
|
||
}
|
||
|
||
impl InvocationParent {
|
||
const ROOT: Self = Self {
|
||
parent_def: CRATE_DEF_ID,
|
||
impl_trait_context: ImplTraitContext::Existential,
|
||
in_attr: false,
|
||
const_arg_context: ConstArgContext::NonDirect,
|
||
};
|
||
}
|
||
|
||
#[derive(Copy, Debug, Clone)]
|
||
enum ImplTraitContext {
|
||
Existential,
|
||
Universal,
|
||
InBinding,
|
||
}
|
||
|
||
#[derive(Copy, Clone, Debug)]
|
||
enum ConstArgContext {
|
||
Direct,
|
||
/// Either inside of an `AnonConst` or not inside a const argument at all.
|
||
NonDirect,
|
||
}
|
||
|
||
/// Used for tracking import use types which will be used for redundant import checking.
|
||
///
|
||
/// ### Used::Scope Example
|
||
///
|
||
/// ```rust,compile_fail
|
||
/// #![deny(redundant_imports)]
|
||
/// use std::mem::drop;
|
||
/// fn main() {
|
||
/// let s = Box::new(32);
|
||
/// drop(s);
|
||
/// }
|
||
/// ```
|
||
///
|
||
/// Used::Other is for other situations like module-relative uses.
|
||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||
enum Used {
|
||
Scope,
|
||
Other,
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
struct BindingError {
|
||
name: Ident,
|
||
origin: Vec<(Span, ast::Pat)>,
|
||
target: Vec<ast::Pat>,
|
||
could_be_path: bool,
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
enum ResolutionError<'ra> {
|
||
/// Error E0401: can't use type or const parameters from outer item.
|
||
GenericParamsFromOuterItem {
|
||
outer_res: Res,
|
||
has_generic_params: HasGenericParams,
|
||
def_kind: DefKind,
|
||
inner_item: Option<(Span, ast::ItemKind)>,
|
||
current_self_ty: Option<String>,
|
||
},
|
||
/// Error E0403: the name is already used for a type or const parameter in this generic
|
||
/// parameter list.
|
||
NameAlreadyUsedInParameterList(Ident, Span),
|
||
/// Error E0407: method is not a member of trait.
|
||
MethodNotMemberOfTrait(Ident, String, Option<Symbol>),
|
||
/// Error E0437: type is not a member of trait.
|
||
TypeNotMemberOfTrait(Ident, String, Option<Symbol>),
|
||
/// Error E0438: const is not a member of trait.
|
||
ConstNotMemberOfTrait(Ident, String, Option<Symbol>),
|
||
/// Error E0408: variable `{}` is not bound in all patterns.
|
||
VariableNotBoundInPattern(BindingError, ParentScope<'ra>),
|
||
/// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
|
||
VariableBoundWithDifferentMode(Ident, Span),
|
||
/// Error E0415: identifier is bound more than once in this parameter list.
|
||
IdentifierBoundMoreThanOnceInParameterList(Ident),
|
||
/// Error E0416: identifier is bound more than once in the same pattern.
|
||
IdentifierBoundMoreThanOnceInSamePattern(Ident),
|
||
/// Error E0426: use of undeclared label.
|
||
UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
|
||
/// Error E0429: `self` imports are only allowed within a `{ }` list.
|
||
SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span },
|
||
/// Error E0430: `self` import can only appear once in the list.
|
||
SelfImportCanOnlyAppearOnceInTheList,
|
||
/// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
|
||
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
||
/// Error E0433: failed to resolve.
|
||
FailedToResolve {
|
||
segment: Option<Symbol>,
|
||
label: String,
|
||
suggestion: Option<Suggestion>,
|
||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||
},
|
||
/// Error E0434: can't capture dynamic environment in a fn item.
|
||
CannotCaptureDynamicEnvironmentInFnItem,
|
||
/// Error E0435: attempt to use a non-constant value in a constant.
|
||
AttemptToUseNonConstantValueInConstant {
|
||
ident: Ident,
|
||
suggestion: &'static str,
|
||
current: &'static str,
|
||
type_span: Option<Span>,
|
||
},
|
||
/// Error E0530: `X` bindings cannot shadow `Y`s.
|
||
BindingShadowsSomethingUnacceptable {
|
||
shadowing_binding: PatternSource,
|
||
name: Symbol,
|
||
participle: &'static str,
|
||
article: &'static str,
|
||
shadowed_binding: Res,
|
||
shadowed_binding_span: Span,
|
||
},
|
||
/// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
|
||
ForwardDeclaredGenericParam(Symbol, ForwardGenericParamBanReason),
|
||
// FIXME(generic_const_parameter_types): This should give custom output specifying it's only
|
||
// problematic to use *forward declared* parameters when the feature is enabled.
|
||
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
|
||
ParamInTyOfConstParam { name: Symbol },
|
||
/// generic parameters must not be used inside const evaluations.
|
||
///
|
||
/// This error is only emitted when using `min_const_generics`.
|
||
ParamInNonTrivialAnonConst { name: Symbol, param_kind: ParamKindInNonTrivialAnonConst },
|
||
/// generic parameters must not be used inside enum discriminants.
|
||
///
|
||
/// This error is emitted even with `generic_const_exprs`.
|
||
ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant },
|
||
/// Error E0735: generic parameters with a default cannot use `Self`
|
||
ForwardDeclaredSelf(ForwardGenericParamBanReason),
|
||
/// Error E0767: use of unreachable label
|
||
UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
|
||
/// Error E0323, E0324, E0325: mismatch between trait item and impl item.
|
||
TraitImplMismatch {
|
||
name: Ident,
|
||
kind: &'static str,
|
||
trait_path: String,
|
||
trait_item_span: Span,
|
||
code: ErrCode,
|
||
},
|
||
/// Error E0201: multiple impl items for the same trait item.
|
||
TraitImplDuplicate { name: Ident, trait_item_span: Span, old_span: Span },
|
||
/// Inline asm `sym` operand must refer to a `fn` or `static`.
|
||
InvalidAsmSym,
|
||
/// `self` used instead of `Self` in a generic parameter
|
||
LowercaseSelf,
|
||
/// A never pattern has a binding.
|
||
BindingInNeverPattern,
|
||
}
|
||
|
||
enum VisResolutionError<'a> {
|
||
Relative2018(Span, &'a ast::Path),
|
||
AncestorOnly(Span),
|
||
FailedToResolve(Span, String, Option<Suggestion>),
|
||
ExpectedFound(Span, String, Res),
|
||
Indeterminate(Span),
|
||
ModuleOnly(Span),
|
||
}
|
||
|
||
/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path
|
||
/// segments' which don't have the rest of an AST or HIR `PathSegment`.
|
||
#[derive(Clone, Copy, Debug)]
|
||
struct Segment {
|
||
ident: Ident,
|
||
id: Option<NodeId>,
|
||
/// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
|
||
/// nonsensical suggestions.
|
||
has_generic_args: bool,
|
||
/// Signals whether this `PathSegment` has lifetime arguments.
|
||
has_lifetime_args: bool,
|
||
args_span: Span,
|
||
}
|
||
|
||
impl Segment {
|
||
fn from_path(path: &Path) -> Vec<Segment> {
|
||
path.segments.iter().map(|s| s.into()).collect()
|
||
}
|
||
|
||
fn from_ident(ident: Ident) -> Segment {
|
||
Segment {
|
||
ident,
|
||
id: None,
|
||
has_generic_args: false,
|
||
has_lifetime_args: false,
|
||
args_span: DUMMY_SP,
|
||
}
|
||
}
|
||
|
||
fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment {
|
||
Segment {
|
||
ident,
|
||
id: Some(id),
|
||
has_generic_args: false,
|
||
has_lifetime_args: false,
|
||
args_span: DUMMY_SP,
|
||
}
|
||
}
|
||
|
||
fn names_to_string(segments: &[Segment]) -> String {
|
||
names_to_string(segments.iter().map(|seg| seg.ident.name))
|
||
}
|
||
}
|
||
|
||
impl<'a> From<&'a ast::PathSegment> for Segment {
|
||
fn from(seg: &'a ast::PathSegment) -> Segment {
|
||
let has_generic_args = seg.args.is_some();
|
||
let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() {
|
||
match args {
|
||
GenericArgs::AngleBracketed(args) => {
|
||
let found_lifetimes = args
|
||
.args
|
||
.iter()
|
||
.any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_))));
|
||
(args.span, found_lifetimes)
|
||
}
|
||
GenericArgs::Parenthesized(args) => (args.span, true),
|
||
GenericArgs::ParenthesizedElided(span) => (*span, true),
|
||
}
|
||
} else {
|
||
(DUMMY_SP, false)
|
||
};
|
||
Segment {
|
||
ident: seg.ident,
|
||
id: Some(seg.id),
|
||
has_generic_args,
|
||
has_lifetime_args,
|
||
args_span,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Name declaration used during late resolution.
|
||
#[derive(Debug, Copy, Clone)]
|
||
enum LateDecl<'ra> {
|
||
/// A regular name declaration.
|
||
Decl(Decl<'ra>),
|
||
/// A name definition from a rib, e.g. a local variable.
|
||
/// Omits most of the data from regular `Decl` for performance reasons.
|
||
RibDef(Res),
|
||
}
|
||
|
||
impl<'ra> LateDecl<'ra> {
|
||
fn res(self) -> Res {
|
||
match self {
|
||
LateDecl::Decl(binding) => binding.res(),
|
||
LateDecl::RibDef(res) => res,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||
enum ModuleOrUniformRoot<'ra> {
|
||
/// Regular module.
|
||
Module(Module<'ra>),
|
||
|
||
/// Virtual module that denotes resolution in a module with fallback to extern prelude.
|
||
/// Used for paths starting with `::` coming from 2015 edition macros
|
||
/// used in 2018+ edition crates.
|
||
ModuleAndExternPrelude(Module<'ra>),
|
||
|
||
/// Virtual module that denotes resolution in extern prelude.
|
||
/// Used for paths starting with `::` on 2018 edition.
|
||
ExternPrelude,
|
||
|
||
/// Virtual module that denotes resolution in current scope.
|
||
/// Used only for resolving single-segment imports. The reason it exists is that import paths
|
||
/// are always split into two parts, the first of which should be some kind of module.
|
||
CurrentScope,
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
enum PathResult<'ra> {
|
||
Module(ModuleOrUniformRoot<'ra>),
|
||
NonModule(PartialRes),
|
||
Indeterminate,
|
||
Failed {
|
||
span: Span,
|
||
label: String,
|
||
suggestion: Option<Suggestion>,
|
||
is_error_from_last_segment: bool,
|
||
/// The final module being resolved, for instance:
|
||
///
|
||
/// ```compile_fail
|
||
/// mod a {
|
||
/// mod b {
|
||
/// mod c {}
|
||
/// }
|
||
/// }
|
||
///
|
||
/// use a::not_exist::c;
|
||
/// ```
|
||
///
|
||
/// In this case, `module` will point to `a`.
|
||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||
/// The segment name of target
|
||
segment_name: Symbol,
|
||
error_implied_by_parse_error: bool,
|
||
},
|
||
}
|
||
|
||
impl<'ra> PathResult<'ra> {
|
||
fn failed(
|
||
ident: Ident,
|
||
is_error_from_last_segment: bool,
|
||
finalize: bool,
|
||
error_implied_by_parse_error: bool,
|
||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||
) -> PathResult<'ra> {
|
||
let (label, suggestion) =
|
||
if finalize { label_and_suggestion() } else { (String::new(), None) };
|
||
PathResult::Failed {
|
||
span: ident.span,
|
||
segment_name: ident.name,
|
||
label,
|
||
suggestion,
|
||
is_error_from_last_segment,
|
||
module,
|
||
error_implied_by_parse_error,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
enum ModuleKind {
|
||
/// An anonymous module; e.g., just a block.
|
||
///
|
||
/// ```
|
||
/// fn main() {
|
||
/// fn f() {} // (1)
|
||
/// { // This is an anonymous module
|
||
/// f(); // This resolves to (2) as we are inside the block.
|
||
/// fn f() {} // (2)
|
||
/// }
|
||
/// f(); // Resolves to (1)
|
||
/// }
|
||
/// ```
|
||
Block,
|
||
/// Any module with a name.
|
||
///
|
||
/// This could be:
|
||
///
|
||
/// * A normal module – either `mod from_file;` or `mod from_block { }` –
|
||
/// or the crate root (which is conceptually a top-level module).
|
||
/// The crate root will have `None` for the symbol.
|
||
/// * A trait or an enum (it implicitly contains associated types, methods and variant
|
||
/// constructors).
|
||
Def(DefKind, DefId, Option<Symbol>),
|
||
}
|
||
|
||
impl ModuleKind {
|
||
/// Get name of the module.
|
||
fn name(&self) -> Option<Symbol> {
|
||
match *self {
|
||
ModuleKind::Block => None,
|
||
ModuleKind::Def(.., name) => name,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Combination of a symbol and its macros 2.0 normalized hygiene context.
|
||
/// Used as a key in various kinds of name containers, including modules (as a part of slightly
|
||
/// larger `BindingKey`) and preludes.
|
||
///
|
||
/// Often passed around together with `orig_ident_span: Span`, which is an unnormalized span
|
||
/// of the original `Ident` from which `IdentKey` was obtained. This span is not used in map keys,
|
||
/// but used in a number of other scenarios - diagnostics, edition checks, `allow_unstable` checks
|
||
/// and similar. This is required because macros 2.0 normalization is lossy and the normalized
|
||
/// spans / syntax contexts no longer contain parts of macro backtraces, while the original span
|
||
/// contains everything.
|
||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||
struct IdentKey {
|
||
name: Symbol,
|
||
ctxt: Macros20NormalizedSyntaxContext,
|
||
}
|
||
|
||
impl IdentKey {
|
||
#[inline]
|
||
fn new(ident: Ident) -> IdentKey {
|
||
IdentKey { name: ident.name, ctxt: Macros20NormalizedSyntaxContext::new(ident.span.ctxt()) }
|
||
}
|
||
|
||
#[inline]
|
||
fn new_adjusted(ident: Ident, expn_id: ExpnId) -> (IdentKey, Option<ExpnId>) {
|
||
let (ctxt, def) = Macros20NormalizedSyntaxContext::new_adjusted(ident.span.ctxt(), expn_id);
|
||
(IdentKey { name: ident.name, ctxt }, def)
|
||
}
|
||
|
||
#[inline]
|
||
fn with_root_ctxt(name: Symbol) -> Self {
|
||
let ctxt = Macros20NormalizedSyntaxContext::new_unchecked(SyntaxContext::root());
|
||
IdentKey { name, ctxt }
|
||
}
|
||
|
||
#[inline]
|
||
fn orig(self, orig_ident_span: Span) -> Ident {
|
||
Ident::new(self.name, orig_ident_span)
|
||
}
|
||
}
|
||
|
||
/// A key that identifies a binding in a given `Module`.
|
||
///
|
||
/// Multiple bindings in the same module can have the same key (in a valid
|
||
/// program) if all but one of them come from glob imports.
|
||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||
struct BindingKey {
|
||
/// The identifier for the binding, always the `normalize_to_macros_2_0` version of the
|
||
/// identifier.
|
||
ident: IdentKey,
|
||
ns: Namespace,
|
||
/// When we add an underscore binding (with ident `_`) to some module, this field has
|
||
/// a non-zero value that uniquely identifies this binding in that module.
|
||
/// For non-underscore bindings this field is zero.
|
||
/// When a key is constructed for name lookup (as opposed to name definition), this field is
|
||
/// also zero, even for underscore names, so for underscores the lookup will never succeed.
|
||
disambiguator: u32,
|
||
}
|
||
|
||
impl BindingKey {
|
||
fn new(ident: IdentKey, ns: Namespace) -> Self {
|
||
BindingKey { ident, ns, disambiguator: 0 }
|
||
}
|
||
|
||
fn new_disambiguated(
|
||
ident: IdentKey,
|
||
ns: Namespace,
|
||
disambiguator: impl FnOnce() -> u32,
|
||
) -> BindingKey {
|
||
let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 };
|
||
BindingKey { ident, ns, disambiguator }
|
||
}
|
||
}
|
||
|
||
type Resolutions<'ra> = CmRefCell<FxIndexMap<BindingKey, &'ra CmRefCell<NameResolution<'ra>>>>;
|
||
|
||
/// One node in the tree of modules.
|
||
///
|
||
/// Note that a "module" in resolve is broader than a `mod` that you declare in Rust code. It may be one of these:
|
||
///
|
||
/// * `mod`
|
||
/// * crate root (aka, top-level anonymous module)
|
||
/// * `enum`
|
||
/// * `trait`
|
||
/// * curly-braced block with statements
|
||
///
|
||
/// You can use [`ModuleData::kind`] to determine the kind of module this is.
|
||
struct ModuleData<'ra> {
|
||
/// The direct parent module (it may not be a `mod`, however).
|
||
parent: Option<Module<'ra>>,
|
||
/// What kind of module this is, because this may not be a `mod`.
|
||
kind: ModuleKind,
|
||
|
||
/// Mapping between names and their (possibly in-progress) resolutions in this module.
|
||
/// Resolutions in modules from other crates are not populated until accessed.
|
||
lazy_resolutions: Resolutions<'ra>,
|
||
/// True if this is a module from other crate that needs to be populated on access.
|
||
populate_on_access: CacheCell<bool>,
|
||
/// Used to disambiguate underscore items (`const _: T = ...`) in the module.
|
||
underscore_disambiguator: CmCell<u32>,
|
||
|
||
/// Macro invocations that can expand into items in this module.
|
||
unexpanded_invocations: CmRefCell<FxHashSet<LocalExpnId>>,
|
||
|
||
/// Whether `#[no_implicit_prelude]` is active.
|
||
no_implicit_prelude: bool,
|
||
|
||
glob_importers: CmRefCell<Vec<Import<'ra>>>,
|
||
globs: CmRefCell<Vec<Import<'ra>>>,
|
||
|
||
/// Used to memoize the traits in this module for faster searches through all traits in scope.
|
||
traits: CmRefCell<
|
||
Option<Box<[(Symbol, Decl<'ra>, Option<Module<'ra>>, bool /* lint ambiguous */)]>>,
|
||
>,
|
||
|
||
/// Span of the module itself. Used for error reporting.
|
||
span: Span,
|
||
|
||
expansion: ExpnId,
|
||
|
||
/// Declaration for implicitly declared names that come with a module,
|
||
/// like `self` (not yet used), or `crate`/`$crate` (for root modules).
|
||
self_decl: Option<Decl<'ra>>,
|
||
}
|
||
|
||
/// All modules are unique and allocated on a same arena,
|
||
/// so we can use referential equality to compare them.
|
||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||
#[rustc_pass_by_value]
|
||
struct Module<'ra>(Interned<'ra, ModuleData<'ra>>);
|
||
|
||
// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the
|
||
// contained data.
|
||
// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees
|
||
// are upheld.
|
||
impl std::hash::Hash for ModuleData<'_> {
|
||
fn hash<H>(&self, _: &mut H)
|
||
where
|
||
H: std::hash::Hasher,
|
||
{
|
||
unreachable!()
|
||
}
|
||
}
|
||
|
||
impl<'ra> ModuleData<'ra> {
|
||
fn new(
|
||
parent: Option<Module<'ra>>,
|
||
kind: ModuleKind,
|
||
expansion: ExpnId,
|
||
span: Span,
|
||
no_implicit_prelude: bool,
|
||
self_decl: Option<Decl<'ra>>,
|
||
) -> Self {
|
||
let is_foreign = match kind {
|
||
ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
|
||
ModuleKind::Block => false,
|
||
};
|
||
ModuleData {
|
||
parent,
|
||
kind,
|
||
lazy_resolutions: Default::default(),
|
||
populate_on_access: CacheCell::new(is_foreign),
|
||
underscore_disambiguator: CmCell::new(0),
|
||
unexpanded_invocations: Default::default(),
|
||
no_implicit_prelude,
|
||
glob_importers: CmRefCell::new(Vec::new()),
|
||
globs: CmRefCell::new(Vec::new()),
|
||
traits: CmRefCell::new(None),
|
||
span,
|
||
expansion,
|
||
self_decl,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl<'ra> Module<'ra> {
|
||
fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>(
|
||
self,
|
||
resolver: &R,
|
||
mut f: impl FnMut(&R, IdentKey, Span, Namespace, Decl<'ra>),
|
||
) {
|
||
for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() {
|
||
let name_resolution = name_resolution.borrow();
|
||
if let Some(decl) = name_resolution.best_decl() {
|
||
f(resolver, key.ident, name_resolution.orig_ident_span, key.ns, decl);
|
||
}
|
||
}
|
||
}
|
||
|
||
fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>(
|
||
self,
|
||
resolver: &mut R,
|
||
mut f: impl FnMut(&mut R, IdentKey, Span, Namespace, Decl<'ra>),
|
||
) {
|
||
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
|
||
let name_resolution = name_resolution.borrow();
|
||
if let Some(decl) = name_resolution.best_decl() {
|
||
f(resolver, key.ident, name_resolution.orig_ident_span, key.ns, decl);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// This modifies `self` in place. The traits will be stored in `self.traits`.
|
||
fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) {
|
||
let mut traits = self.traits.borrow_mut(resolver.as_ref());
|
||
if traits.is_none() {
|
||
let mut collected_traits = Vec::new();
|
||
self.for_each_child(resolver, |r, ident, _, ns, binding| {
|
||
if ns != TypeNS {
|
||
return;
|
||
}
|
||
if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() {
|
||
collected_traits.push((
|
||
ident.name,
|
||
binding,
|
||
r.as_ref().get_module(def_id),
|
||
binding.is_ambiguity_recursive(),
|
||
));
|
||
}
|
||
});
|
||
*traits = Some(collected_traits.into_boxed_slice());
|
||
}
|
||
}
|
||
|
||
fn res(self) -> Option<Res> {
|
||
match self.kind {
|
||
ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)),
|
||
_ => None,
|
||
}
|
||
}
|
||
|
||
fn def_id(self) -> DefId {
|
||
self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
|
||
}
|
||
|
||
fn opt_def_id(self) -> Option<DefId> {
|
||
match self.kind {
|
||
ModuleKind::Def(_, def_id, _) => Some(def_id),
|
||
_ => None,
|
||
}
|
||
}
|
||
|
||
// `self` resolves to the first module ancestor that `is_normal`.
|
||
fn is_normal(self) -> bool {
|
||
matches!(self.kind, ModuleKind::Def(DefKind::Mod, _, _))
|
||
}
|
||
|
||
fn is_trait(self) -> bool {
|
||
matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _))
|
||
}
|
||
|
||
fn nearest_item_scope(self) -> Module<'ra> {
|
||
match self.kind {
|
||
ModuleKind::Def(DefKind::Enum | DefKind::Trait, ..) => {
|
||
self.parent.expect("enum or trait module without a parent")
|
||
}
|
||
_ => self,
|
||
}
|
||
}
|
||
|
||
/// The [`DefId`] of the nearest `mod` item ancestor (which may be this module).
|
||
/// This may be the crate root.
|
||
fn nearest_parent_mod(self) -> DefId {
|
||
match self.kind {
|
||
ModuleKind::Def(DefKind::Mod, def_id, _) => def_id,
|
||
_ => self.parent.expect("non-root module without parent").nearest_parent_mod(),
|
||
}
|
||
}
|
||
|
||
fn is_ancestor_of(self, mut other: Self) -> bool {
|
||
while self != other {
|
||
if let Some(parent) = other.parent {
|
||
other = parent;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
true
|
||
}
|
||
}
|
||
|
||
impl<'ra> std::ops::Deref for Module<'ra> {
|
||
type Target = ModuleData<'ra>;
|
||
|
||
fn deref(&self) -> &Self::Target {
|
||
&self.0
|
||
}
|
||
}
|
||
|
||
impl<'ra> fmt::Debug for Module<'ra> {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
match self.kind {
|
||
ModuleKind::Block => write!(f, "block"),
|
||
ModuleKind::Def(..) => write!(f, "{:?}", self.res()),
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Data associated with any name declaration.
|
||
#[derive(Clone, Debug)]
|
||
struct DeclData<'ra> {
|
||
kind: DeclKind<'ra>,
|
||
ambiguity: CmCell<Option<Decl<'ra>>>,
|
||
/// Produce a warning instead of an error when reporting ambiguities inside this binding.
|
||
/// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required.
|
||
warn_ambiguity: CmCell<bool>,
|
||
expansion: LocalExpnId,
|
||
span: Span,
|
||
vis: CmCell<Visibility<DefId>>,
|
||
parent_module: Option<Module<'ra>>,
|
||
}
|
||
|
||
/// All name declarations are unique and allocated on a same arena,
|
||
/// so we can use referential equality to compare them.
|
||
type Decl<'ra> = Interned<'ra, DeclData<'ra>>;
|
||
|
||
// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the
|
||
// contained data.
|
||
// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees
|
||
// are upheld.
|
||
impl std::hash::Hash for DeclData<'_> {
|
||
fn hash<H>(&self, _: &mut H)
|
||
where
|
||
H: std::hash::Hasher,
|
||
{
|
||
unreachable!()
|
||
}
|
||
}
|
||
|
||
/// Name declaration kind.
|
||
#[derive(Clone, Copy, Debug)]
|
||
enum DeclKind<'ra> {
|
||
/// The name declaration is a definition (possibly without a `DefId`),
|
||
/// can be provided by source code or built into the language.
|
||
Def(Res),
|
||
/// The name declaration is a link to another name declaration.
|
||
Import { source_decl: Decl<'ra>, import: Import<'ra> },
|
||
}
|
||
|
||
impl<'ra> DeclKind<'ra> {
|
||
/// Is this an import declaration?
|
||
fn is_import(&self) -> bool {
|
||
matches!(*self, DeclKind::Import { .. })
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
struct PrivacyError<'ra> {
|
||
ident: Ident,
|
||
decl: Decl<'ra>,
|
||
dedup_span: Span,
|
||
outermost_res: Option<(Res, Ident)>,
|
||
parent_scope: ParentScope<'ra>,
|
||
/// Is the format `use a::{b,c}`?
|
||
single_nested: bool,
|
||
source: Option<ast::Expr>,
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
struct UseError<'a> {
|
||
err: Diag<'a>,
|
||
/// Candidates which user could `use` to access the missing type.
|
||
candidates: Vec<ImportSuggestion>,
|
||
/// The `DefId` of the module to place the use-statements in.
|
||
def_id: DefId,
|
||
/// Whether the diagnostic should say "instead" (as in `consider importing ... instead`).
|
||
instead: bool,
|
||
/// Extra free-form suggestion.
|
||
suggestion: Option<(Span, &'static str, String, Applicability)>,
|
||
/// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
|
||
/// the user to import the item directly.
|
||
path: Vec<Segment>,
|
||
/// Whether the expected source is a call
|
||
is_call: bool,
|
||
}
|
||
|
||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||
enum AmbiguityKind {
|
||
BuiltinAttr,
|
||
DeriveHelper,
|
||
MacroRulesVsModularized,
|
||
GlobVsOuter,
|
||
GlobVsGlob,
|
||
GlobVsExpanded,
|
||
MoreExpandedVsOuter,
|
||
}
|
||
|
||
impl AmbiguityKind {
|
||
fn descr(self) -> &'static str {
|
||
match self {
|
||
AmbiguityKind::BuiltinAttr => "a name conflict with a builtin attribute",
|
||
AmbiguityKind::DeriveHelper => "a name conflict with a derive helper attribute",
|
||
AmbiguityKind::MacroRulesVsModularized => {
|
||
"a conflict between a `macro_rules` name and a non-`macro_rules` name from another module"
|
||
}
|
||
AmbiguityKind::GlobVsOuter => {
|
||
"a conflict between a name from a glob import and an outer scope during import or macro resolution"
|
||
}
|
||
AmbiguityKind::GlobVsGlob => "multiple glob imports of a name in the same module",
|
||
AmbiguityKind::GlobVsExpanded => {
|
||
"a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution"
|
||
}
|
||
AmbiguityKind::MoreExpandedVsOuter => {
|
||
"a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Clone, Copy, PartialEq)]
|
||
enum AmbiguityWarning {
|
||
GlobImport,
|
||
PanicImport,
|
||
}
|
||
|
||
struct AmbiguityError<'ra> {
|
||
kind: AmbiguityKind,
|
||
ambig_vis: Option<(Visibility, Visibility)>,
|
||
ident: Ident,
|
||
b1: Decl<'ra>,
|
||
b2: Decl<'ra>,
|
||
scope1: Scope<'ra>,
|
||
scope2: Scope<'ra>,
|
||
warning: Option<AmbiguityWarning>,
|
||
}
|
||
|
||
impl<'ra> DeclData<'ra> {
|
||
fn vis(&self) -> Visibility<DefId> {
|
||
self.vis.get()
|
||
}
|
||
|
||
fn res(&self) -> Res {
|
||
match self.kind {
|
||
DeclKind::Def(res) => res,
|
||
DeclKind::Import { source_decl, .. } => source_decl.res(),
|
||
}
|
||
}
|
||
|
||
fn import_source(&self) -> Decl<'ra> {
|
||
match self.kind {
|
||
DeclKind::Import { source_decl, .. } => source_decl,
|
||
_ => unreachable!(),
|
||
}
|
||
}
|
||
|
||
fn descent_to_ambiguity(self: Decl<'ra>) -> Option<(Decl<'ra>, Decl<'ra>)> {
|
||
match self.ambiguity.get() {
|
||
Some(ambig_binding) => Some((self, ambig_binding)),
|
||
None => match self.kind {
|
||
DeclKind::Import { source_decl, .. } => source_decl.descent_to_ambiguity(),
|
||
_ => None,
|
||
},
|
||
}
|
||
}
|
||
|
||
fn is_ambiguity_recursive(&self) -> bool {
|
||
self.ambiguity.get().is_some()
|
||
|| match self.kind {
|
||
DeclKind::Import { source_decl, .. } => source_decl.is_ambiguity_recursive(),
|
||
_ => false,
|
||
}
|
||
}
|
||
|
||
fn warn_ambiguity_recursive(&self) -> bool {
|
||
self.warn_ambiguity.get()
|
||
|| match self.kind {
|
||
DeclKind::Import { source_decl, .. } => source_decl.warn_ambiguity_recursive(),
|
||
_ => false,
|
||
}
|
||
}
|
||
|
||
fn is_possibly_imported_variant(&self) -> bool {
|
||
match self.kind {
|
||
DeclKind::Import { source_decl, .. } => source_decl.is_possibly_imported_variant(),
|
||
DeclKind::Def(Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _)) => {
|
||
true
|
||
}
|
||
DeclKind::Def(..) => false,
|
||
}
|
||
}
|
||
|
||
fn is_extern_crate(&self) -> bool {
|
||
match self.kind {
|
||
DeclKind::Import { import, .. } => {
|
||
matches!(import.kind, ImportKind::ExternCrate { .. })
|
||
}
|
||
DeclKind::Def(Res::Def(_, def_id)) => def_id.is_crate_root(),
|
||
_ => false,
|
||
}
|
||
}
|
||
|
||
fn is_import(&self) -> bool {
|
||
matches!(self.kind, DeclKind::Import { .. })
|
||
}
|
||
|
||
/// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might
|
||
/// not be perceived as such by users, so treat it as a non-import in some diagnostics.
|
||
fn is_import_user_facing(&self) -> bool {
|
||
matches!(self.kind, DeclKind::Import { import, .. }
|
||
if !matches!(import.kind, ImportKind::MacroExport))
|
||
}
|
||
|
||
fn is_glob_import(&self) -> bool {
|
||
match self.kind {
|
||
DeclKind::Import { import, .. } => import.is_glob(),
|
||
_ => false,
|
||
}
|
||
}
|
||
|
||
fn is_assoc_item(&self) -> bool {
|
||
matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _))
|
||
}
|
||
|
||
fn macro_kinds(&self) -> Option<MacroKinds> {
|
||
self.res().macro_kinds()
|
||
}
|
||
|
||
fn reexport_chain(self: Decl<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> {
|
||
let mut reexport_chain = SmallVec::new();
|
||
let mut next_binding = self;
|
||
while let DeclKind::Import { source_decl, import, .. } = next_binding.kind {
|
||
reexport_chain.push(import.simplify(r));
|
||
next_binding = source_decl;
|
||
}
|
||
reexport_chain
|
||
}
|
||
|
||
// Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
|
||
// at some expansion round `max(invoc, binding)` when they both emerged from macros.
|
||
// Then this function returns `true` if `self` may emerge from a macro *after* that
|
||
// in some later round and screw up our previously found resolution.
|
||
// See more detailed explanation in
|
||
// https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049
|
||
fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, decl: Decl<'_>) -> bool {
|
||
// self > max(invoc, decl) => !(self <= invoc || self <= decl)
|
||
// Expansions are partially ordered, so "may appear after" is an inversion of
|
||
// "certainly appears before or simultaneously" and includes unordered cases.
|
||
let self_parent_expansion = self.expansion;
|
||
let other_parent_expansion = decl.expansion;
|
||
let certainly_before_other_or_simultaneously =
|
||
other_parent_expansion.is_descendant_of(self_parent_expansion);
|
||
let certainly_before_invoc_or_simultaneously =
|
||
invoc_parent_expansion.is_descendant_of(self_parent_expansion);
|
||
!(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
|
||
}
|
||
|
||
// Its purpose is to postpone the determination of a single binding because
|
||
// we can't predict whether it will be overwritten by recently expanded macros.
|
||
// FIXME: How can we integrate it with the `update_resolution`?
|
||
fn determined(&self) -> bool {
|
||
match &self.kind {
|
||
DeclKind::Import { source_decl, import, .. } if import.is_glob() => {
|
||
import.parent_scope.module.unexpanded_invocations.borrow().is_empty()
|
||
&& source_decl.determined()
|
||
}
|
||
_ => true,
|
||
}
|
||
}
|
||
}
|
||
|
||
struct ExternPreludeEntry<'ra> {
|
||
/// Name declaration from an `extern crate` item.
|
||
/// The boolean flag is true is `item_decl` is non-redundant, happens either when
|
||
/// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming.
|
||
item_decl: Option<(Decl<'ra>, Span, /* introduced by item */ bool)>,
|
||
/// Name declaration from an `--extern` flag, lazily populated on first use.
|
||
flag_decl: Option<CacheCell<(PendingDecl<'ra>, /* finalized */ bool)>>,
|
||
}
|
||
|
||
impl ExternPreludeEntry<'_> {
|
||
fn introduced_by_item(&self) -> bool {
|
||
matches!(self.item_decl, Some((.., true)))
|
||
}
|
||
|
||
fn flag() -> Self {
|
||
ExternPreludeEntry {
|
||
item_decl: None,
|
||
flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))),
|
||
}
|
||
}
|
||
|
||
fn span(&self) -> Span {
|
||
match self.item_decl {
|
||
Some((_, span, _)) => span,
|
||
None => DUMMY_SP,
|
||
}
|
||
}
|
||
}
|
||
|
||
struct DeriveData {
|
||
resolutions: Vec<DeriveResolution>,
|
||
helper_attrs: Vec<(usize, IdentKey, Span)>,
|
||
has_derive_copy: bool,
|
||
}
|
||
|
||
struct MacroData {
|
||
ext: Arc<SyntaxExtension>,
|
||
nrules: usize,
|
||
macro_rules: bool,
|
||
}
|
||
|
||
impl MacroData {
|
||
fn new(ext: Arc<SyntaxExtension>) -> MacroData {
|
||
MacroData { ext, nrules: 0, macro_rules: false }
|
||
}
|
||
}
|
||
|
||
pub struct ResolverOutputs {
|
||
pub global_ctxt: ResolverGlobalCtxt,
|
||
pub ast_lowering: ResolverAstLowering,
|
||
}
|
||
|
||
/// The main resolver class.
|
||
///
|
||
/// This is the visitor that walks the whole crate.
|
||
pub struct Resolver<'ra, 'tcx> {
|
||
tcx: TyCtxt<'tcx>,
|
||
|
||
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
|
||
expn_that_defined: UnordMap<LocalDefId, ExpnId> = Default::default(),
|
||
|
||
graph_root: Module<'ra>,
|
||
|
||
/// Assert that we are in speculative resolution mode.
|
||
assert_speculative: bool,
|
||
|
||
prelude: Option<Module<'ra>> = None,
|
||
extern_prelude: FxIndexMap<IdentKey, ExternPreludeEntry<'ra>>,
|
||
|
||
/// N.B., this is used only for better diagnostics, not name resolution itself.
|
||
field_names: LocalDefIdMap<Vec<Ident>> = Default::default(),
|
||
field_defaults: LocalDefIdMap<Vec<Symbol>> = Default::default(),
|
||
|
||
/// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax.
|
||
/// Used for hints during error reporting.
|
||
field_visibility_spans: FxHashMap<DefId, Vec<Span>> = default::fx_hash_map(),
|
||
|
||
/// All imports known to succeed or fail.
|
||
determined_imports: Vec<Import<'ra>> = Vec::new(),
|
||
|
||
/// All non-determined imports.
|
||
indeterminate_imports: Vec<Import<'ra>> = Vec::new(),
|
||
|
||
// Spans for local variables found during pattern resolution.
|
||
// Used for suggestions during error reporting.
|
||
pat_span_map: NodeMap<Span> = Default::default(),
|
||
|
||
/// Resolutions for nodes that have a single resolution.
|
||
partial_res_map: NodeMap<PartialRes> = Default::default(),
|
||
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
|
||
import_res_map: NodeMap<PerNS<Option<Res>>> = Default::default(),
|
||
/// An import will be inserted into this map if it has been used.
|
||
import_use_map: FxHashMap<Import<'ra>, Used> = default::fx_hash_map(),
|
||
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
|
||
label_res_map: NodeMap<NodeId> = Default::default(),
|
||
/// Resolutions for lifetimes.
|
||
lifetimes_res_map: NodeMap<LifetimeRes> = Default::default(),
|
||
/// Lifetime parameters that lowering will have to introduce.
|
||
extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>> = Default::default(),
|
||
|
||
/// `CrateNum` resolutions of `extern crate` items.
|
||
extern_crate_map: UnordMap<LocalDefId, CrateNum> = Default::default(),
|
||
module_children: LocalDefIdMap<Vec<ModChild>> = Default::default(),
|
||
ambig_module_children: LocalDefIdMap<Vec<AmbigModChild>> = Default::default(),
|
||
trait_map: NodeMap<Vec<TraitCandidate>> = Default::default(),
|
||
|
||
/// A map from nodes to anonymous modules.
|
||
/// Anonymous modules are pseudo-modules that are implicitly created around items
|
||
/// contained within blocks.
|
||
///
|
||
/// For example, if we have this:
|
||
///
|
||
/// fn f() {
|
||
/// fn g() {
|
||
/// ...
|
||
/// }
|
||
/// }
|
||
///
|
||
/// There will be an anonymous module created around `g` with the ID of the
|
||
/// entry block for `f`.
|
||
block_map: NodeMap<Module<'ra>> = Default::default(),
|
||
/// A fake module that contains no definition and no prelude. Used so that
|
||
/// some AST passes can generate identifiers that only resolve to local or
|
||
/// lang items.
|
||
empty_module: Module<'ra>,
|
||
/// All local modules, including blocks.
|
||
local_modules: Vec<Module<'ra>>,
|
||
/// Eagerly populated map of all local non-block modules.
|
||
local_module_map: FxIndexMap<LocalDefId, Module<'ra>>,
|
||
/// Lazily populated cache of modules loaded from external crates.
|
||
extern_module_map: CacheRefCell<FxIndexMap<DefId, Module<'ra>>>,
|
||
|
||
/// Maps glob imports to the names of items actually imported.
|
||
glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>,
|
||
glob_error: Option<ErrorGuaranteed> = None,
|
||
visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(),
|
||
used_imports: FxHashSet<NodeId> = default::fx_hash_set(),
|
||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||
|
||
/// Privacy errors are delayed until the end in order to deduplicate them.
|
||
privacy_errors: Vec<PrivacyError<'ra>> = Vec::new(),
|
||
/// Ambiguity errors are delayed for deduplication.
|
||
ambiguity_errors: Vec<AmbiguityError<'ra>> = Vec::new(),
|
||
issue_145575_hack_applied: bool = false,
|
||
/// `use` injections are delayed for better placement and deduplication.
|
||
use_injections: Vec<UseError<'tcx>> = Vec::new(),
|
||
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
|
||
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
|
||
|
||
/// When a type is re-exported that has an inaccessible constructor because it has fields that
|
||
/// are inaccessible from the import's scope, we mark that as the type won't be able to be built
|
||
/// through the re-export. We use this information to extend the existing diagnostic.
|
||
inaccessible_ctor_reexport: FxHashMap<Span, Span> = default::fx_hash_map(),
|
||
|
||
arenas: &'ra ResolverArenas<'ra>,
|
||
dummy_decl: Decl<'ra>,
|
||
builtin_type_decls: FxHashMap<Symbol, Decl<'ra>>,
|
||
builtin_attr_decls: FxHashMap<Symbol, Decl<'ra>>,
|
||
registered_tool_decls: FxHashMap<IdentKey, Decl<'ra>>,
|
||
macro_names: FxHashSet<IdentKey> = default::fx_hash_set(),
|
||
builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind> = default::fx_hash_map(),
|
||
registered_tools: &'tcx RegisteredTools,
|
||
macro_use_prelude: FxIndexMap<Symbol, Decl<'ra>>,
|
||
/// Eagerly populated map of all local macro definitions.
|
||
local_macro_map: FxHashMap<LocalDefId, &'ra MacroData> = default::fx_hash_map(),
|
||
/// Lazily populated cache of macro definitions loaded from external crates.
|
||
extern_macro_map: CacheRefCell<FxHashMap<DefId, &'ra MacroData>>,
|
||
dummy_ext_bang: Arc<SyntaxExtension>,
|
||
dummy_ext_derive: Arc<SyntaxExtension>,
|
||
non_macro_attr: &'ra MacroData,
|
||
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'ra>> = default::fx_hash_map(),
|
||
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'ra>> = default::fx_hash_map(),
|
||
unused_macros: FxIndexMap<LocalDefId, (NodeId, Ident)>,
|
||
/// A map from the macro to all its potentially unused arms.
|
||
unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>,
|
||
proc_macro_stubs: FxHashSet<LocalDefId> = default::fx_hash_set(),
|
||
/// Traces collected during macro resolution and validated when it's complete.
|
||
single_segment_macro_resolutions:
|
||
CmRefCell<Vec<(Ident, MacroKind, ParentScope<'ra>, Option<Decl<'ra>>, Option<Span>)>>,
|
||
multi_segment_macro_resolutions:
|
||
CmRefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>,
|
||
builtin_attrs: Vec<(Ident, ParentScope<'ra>)> = Vec::new(),
|
||
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
|
||
/// Derive macros cannot modify the item themselves and have to store the markers in the global
|
||
/// context, so they attach the markers to derive container IDs using this resolver table.
|
||
containers_deriving_copy: FxHashSet<LocalExpnId> = default::fx_hash_set(),
|
||
/// Parent scopes in which the macros were invoked.
|
||
/// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere.
|
||
invocation_parent_scopes: FxHashMap<LocalExpnId, ParentScope<'ra>> = default::fx_hash_map(),
|
||
/// `macro_rules` scopes *produced* by expanding the macro invocations,
|
||
/// include all the `macro_rules` items and other invocations generated by them.
|
||
output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'ra>> = default::fx_hash_map(),
|
||
/// `macro_rules` scopes produced by `macro_rules` item definitions.
|
||
macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'ra>> = default::fx_hash_map(),
|
||
/// Helper attributes that are in scope for the given expansion.
|
||
helper_attrs: FxHashMap<LocalExpnId, Vec<(IdentKey, Span, Decl<'ra>)>> = default::fx_hash_map(),
|
||
/// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute
|
||
/// with the given `ExpnId`.
|
||
derive_data: FxHashMap<LocalExpnId, DeriveData> = default::fx_hash_map(),
|
||
|
||
/// Avoid duplicated errors for "name already defined".
|
||
name_already_seen: FxHashMap<Symbol, Span> = default::fx_hash_map(),
|
||
|
||
potentially_unused_imports: Vec<Import<'ra>> = Vec::new(),
|
||
|
||
potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>> = Vec::new(),
|
||
|
||
/// Table for mapping struct IDs into struct constructor IDs,
|
||
/// it's not used during normal resolution, only for better error reporting.
|
||
/// Also includes of list of each fields visibility
|
||
struct_constructors: LocalDefIdMap<(Res, Visibility<DefId>, Vec<Visibility<DefId>>)> = Default::default(),
|
||
|
||
lint_buffer: LintBuffer,
|
||
|
||
next_node_id: NodeId = CRATE_NODE_ID,
|
||
|
||
node_id_to_def_id: NodeMap<Feed<'tcx, LocalDefId>>,
|
||
|
||
disambiguator: DisambiguatorState = DisambiguatorState::new(),
|
||
|
||
/// Indices of unnamed struct or variant fields with unresolved attributes.
|
||
placeholder_field_indices: FxHashMap<NodeId, usize> = default::fx_hash_map(),
|
||
/// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
|
||
/// we know what parent node that fragment should be attached to thanks to this table,
|
||
/// and how the `impl Trait` fragments were introduced.
|
||
invocation_parents: FxHashMap<LocalExpnId, InvocationParent>,
|
||
|
||
/// Amount of lifetime parameters for each item in the crate.
|
||
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize> = default::fx_hash_map(),
|
||
delegation_fn_sigs: LocalDefIdMap<DelegationFnSig> = Default::default(),
|
||
delegation_infos: LocalDefIdMap<DelegationInfo> = Default::default(),
|
||
|
||
main_def: Option<MainDefinition> = None,
|
||
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
|
||
/// A list of proc macro LocalDefIds, written out in the order in which
|
||
/// they are declared in the static array generated by proc_macro_harness.
|
||
proc_macros: Vec<LocalDefId> = Vec::new(),
|
||
confused_type_with_std_module: FxIndexMap<Span, Span>,
|
||
/// Whether lifetime elision was successful.
|
||
lifetime_elision_allowed: FxHashSet<NodeId> = default::fx_hash_set(),
|
||
|
||
/// Names of items that were stripped out via cfg with their corresponding cfg meta item.
|
||
stripped_cfg_items: Vec<StrippedCfgItem<NodeId>> = Vec::new(),
|
||
|
||
effective_visibilities: EffectiveVisibilities,
|
||
doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
|
||
doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
|
||
all_macro_rules: UnordSet<Symbol> = Default::default(),
|
||
|
||
/// Invocation ids of all glob delegations.
|
||
glob_delegation_invoc_ids: FxHashSet<LocalExpnId> = default::fx_hash_set(),
|
||
/// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations.
|
||
/// Needed because glob delegations wait for all other neighboring macros to expand.
|
||
impl_unexpanded_invocations: FxHashMap<LocalDefId, FxHashSet<LocalExpnId>> = default::fx_hash_map(),
|
||
/// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations.
|
||
/// Needed because glob delegations exclude explicitly defined names.
|
||
impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>> = default::fx_hash_map(),
|
||
|
||
/// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo`
|
||
/// could be a crate that wasn't imported. For diagnostics use only.
|
||
current_crate_outer_attr_insert_span: Span,
|
||
|
||
mods_with_parse_errors: FxHashSet<DefId> = default::fx_hash_set(),
|
||
|
||
/// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we
|
||
/// don't need to run it more than once.
|
||
all_crate_macros_already_registered: bool = false,
|
||
|
||
// Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types
|
||
// that were encountered during resolution. These names are used to generate item names
|
||
// for APITs, so we don't want to leak details of resolution into these names.
|
||
impl_trait_names: FxHashMap<NodeId, Symbol> = default::fx_hash_map(),
|
||
}
|
||
|
||
/// This provides memory for the rest of the crate. The `'ra` lifetime that is
|
||
/// used by many types in this crate is an abbreviation of `ResolverArenas`.
|
||
#[derive(Default)]
|
||
pub struct ResolverArenas<'ra> {
|
||
modules: TypedArena<ModuleData<'ra>>,
|
||
imports: TypedArena<ImportData<'ra>>,
|
||
name_resolutions: TypedArena<CmRefCell<NameResolution<'ra>>>,
|
||
ast_paths: TypedArena<ast::Path>,
|
||
macros: TypedArena<MacroData>,
|
||
dropless: DroplessArena,
|
||
}
|
||
|
||
impl<'ra> ResolverArenas<'ra> {
|
||
fn new_def_decl(
|
||
&'ra self,
|
||
res: Res,
|
||
vis: Visibility<DefId>,
|
||
span: Span,
|
||
expansion: LocalExpnId,
|
||
parent_module: Option<Module<'ra>>,
|
||
) -> Decl<'ra> {
|
||
self.alloc_decl(DeclData {
|
||
kind: DeclKind::Def(res),
|
||
ambiguity: CmCell::new(None),
|
||
warn_ambiguity: CmCell::new(false),
|
||
vis: CmCell::new(vis),
|
||
span,
|
||
expansion,
|
||
parent_module,
|
||
})
|
||
}
|
||
|
||
fn new_pub_def_decl(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> {
|
||
self.new_def_decl(res, Visibility::Public, span, expn_id, None)
|
||
}
|
||
|
||
fn new_module(
|
||
&'ra self,
|
||
parent: Option<Module<'ra>>,
|
||
kind: ModuleKind,
|
||
expn_id: ExpnId,
|
||
span: Span,
|
||
no_implicit_prelude: bool,
|
||
) -> Module<'ra> {
|
||
let self_decl = match kind {
|
||
ModuleKind::Def(def_kind, def_id, _) => {
|
||
Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT))
|
||
}
|
||
ModuleKind::Block => None,
|
||
};
|
||
Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
|
||
parent,
|
||
kind,
|
||
expn_id,
|
||
span,
|
||
no_implicit_prelude,
|
||
self_decl,
|
||
))))
|
||
}
|
||
fn alloc_decl(&'ra self, data: DeclData<'ra>) -> Decl<'ra> {
|
||
Interned::new_unchecked(self.dropless.alloc(data))
|
||
}
|
||
fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> {
|
||
Interned::new_unchecked(self.imports.alloc(import))
|
||
}
|
||
fn alloc_name_resolution(
|
||
&'ra self,
|
||
orig_ident_span: Span,
|
||
) -> &'ra CmRefCell<NameResolution<'ra>> {
|
||
self.name_resolutions.alloc(CmRefCell::new(NameResolution::new(orig_ident_span)))
|
||
}
|
||
fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> {
|
||
self.dropless.alloc(CacheCell::new(scope))
|
||
}
|
||
fn alloc_macro_rules_decl(&'ra self, decl: MacroRulesDecl<'ra>) -> &'ra MacroRulesDecl<'ra> {
|
||
self.dropless.alloc(decl)
|
||
}
|
||
fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] {
|
||
self.ast_paths.alloc_from_iter(paths.iter().cloned())
|
||
}
|
||
fn alloc_macro(&'ra self, macro_data: MacroData) -> &'ra MacroData {
|
||
self.macros.alloc(macro_data)
|
||
}
|
||
fn alloc_pattern_spans(&'ra self, spans: impl Iterator<Item = Span>) -> &'ra [Span] {
|
||
self.dropless.alloc_from_iter(spans)
|
||
}
|
||
}
|
||
|
||
impl<'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> {
|
||
fn as_mut(&mut self) -> &mut Resolver<'ra, 'tcx> {
|
||
self
|
||
}
|
||
}
|
||
|
||
impl<'ra, 'tcx> AsRef<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> {
|
||
fn as_ref(&self) -> &Resolver<'ra, 'tcx> {
|
||
self
|
||
}
|
||
}
|
||
|
||
impl<'tcx> Resolver<'_, 'tcx> {
|
||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||
self.opt_feed(node).map(|f| f.key())
|
||
}
|
||
|
||
fn local_def_id(&self, node: NodeId) -> LocalDefId {
|
||
self.feed(node).key()
|
||
}
|
||
|
||
fn opt_feed(&self, node: NodeId) -> Option<Feed<'tcx, LocalDefId>> {
|
||
self.node_id_to_def_id.get(&node).copied()
|
||
}
|
||
|
||
fn feed(&self, node: NodeId) -> Feed<'tcx, LocalDefId> {
|
||
self.opt_feed(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
|
||
}
|
||
|
||
fn local_def_kind(&self, node: NodeId) -> DefKind {
|
||
self.tcx.def_kind(self.local_def_id(node))
|
||
}
|
||
|
||
/// Adds a definition with a parent definition.
|
||
fn create_def(
|
||
&mut self,
|
||
parent: LocalDefId,
|
||
node_id: ast::NodeId,
|
||
name: Option<Symbol>,
|
||
def_kind: DefKind,
|
||
expn_id: ExpnId,
|
||
span: Span,
|
||
) -> TyCtxtFeed<'tcx, LocalDefId> {
|
||
assert!(
|
||
!self.node_id_to_def_id.contains_key(&node_id),
|
||
"adding a def for node-id {:?}, name {:?}, data {:?} but a previous def exists: {:?}",
|
||
node_id,
|
||
name,
|
||
def_kind,
|
||
self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id].key()),
|
||
);
|
||
|
||
// FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()`
|
||
let feed = self.tcx.create_def(parent, name, def_kind, None, &mut self.disambiguator);
|
||
let def_id = feed.def_id();
|
||
|
||
// Create the definition.
|
||
if expn_id != ExpnId::root() {
|
||
self.expn_that_defined.insert(def_id, expn_id);
|
||
}
|
||
|
||
// A relative span's parent must be an absolute span.
|
||
debug_assert_eq!(span.data_untracked().parent, None);
|
||
let _id = self.tcx.untracked().source_span.push(span);
|
||
debug_assert_eq!(_id, def_id);
|
||
|
||
// Some things for which we allocate `LocalDefId`s don't correspond to
|
||
// anything in the AST, so they don't have a `NodeId`. For these cases
|
||
// we don't need a mapping from `NodeId` to `LocalDefId`.
|
||
if node_id != ast::DUMMY_NODE_ID {
|
||
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
|
||
self.node_id_to_def_id.insert(node_id, feed.downgrade());
|
||
}
|
||
|
||
feed
|
||
}
|
||
|
||
fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
|
||
if let Some(def_id) = def_id.as_local() {
|
||
self.item_generics_num_lifetimes[&def_id]
|
||
} else {
|
||
self.tcx.generics_of(def_id).own_counts().lifetimes
|
||
}
|
||
}
|
||
|
||
pub fn tcx(&self) -> TyCtxt<'tcx> {
|
||
self.tcx
|
||
}
|
||
|
||
/// This function is very slow, as it iterates over the entire
|
||
/// [Resolver::node_id_to_def_id] map just to find the [NodeId]
|
||
/// that corresponds to the given [LocalDefId]. Only use this in
|
||
/// diagnostics code paths.
|
||
fn def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId {
|
||
self.node_id_to_def_id
|
||
.items()
|
||
.filter(|(_, v)| v.key() == def_id)
|
||
.map(|(k, _)| *k)
|
||
.get_only()
|
||
.unwrap()
|
||
}
|
||
}
|
||
|
||
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||
pub fn new(
|
||
tcx: TyCtxt<'tcx>,
|
||
attrs: &[ast::Attribute],
|
||
crate_span: Span,
|
||
current_crate_outer_attr_insert_span: Span,
|
||
arenas: &'ra ResolverArenas<'ra>,
|
||
) -> Resolver<'ra, 'tcx> {
|
||
let root_def_id = CRATE_DEF_ID.to_def_id();
|
||
let graph_root = arenas.new_module(
|
||
None,
|
||
ModuleKind::Def(DefKind::Mod, root_def_id, None),
|
||
ExpnId::root(),
|
||
crate_span,
|
||
attr::contains_name(attrs, sym::no_implicit_prelude),
|
||
);
|
||
let local_modules = vec![graph_root];
|
||
let local_module_map = FxIndexMap::from_iter([(CRATE_DEF_ID, graph_root)]);
|
||
let empty_module = arenas.new_module(
|
||
None,
|
||
ModuleKind::Def(DefKind::Mod, root_def_id, None),
|
||
ExpnId::root(),
|
||
DUMMY_SP,
|
||
true,
|
||
);
|
||
|
||
let mut node_id_to_def_id = NodeMap::default();
|
||
let crate_feed = tcx.create_local_crate_def_id(crate_span);
|
||
|
||
crate_feed.def_kind(DefKind::Mod);
|
||
let crate_feed = crate_feed.downgrade();
|
||
node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed);
|
||
|
||
let mut invocation_parents = FxHashMap::default();
|
||
invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);
|
||
|
||
let mut extern_prelude: FxIndexMap<_, _> = tcx
|
||
.sess
|
||
.opts
|
||
.externs
|
||
.iter()
|
||
.filter_map(|(name, entry)| {
|
||
// Make sure `self`, `super`, `_` etc do not get into extern prelude.
|
||
// FIXME: reject `--extern self` and similar in option parsing instead.
|
||
if entry.add_prelude
|
||
&& let name = Symbol::intern(name)
|
||
&& name.can_be_raw()
|
||
{
|
||
let ident = IdentKey::with_root_ctxt(name);
|
||
Some((ident, ExternPreludeEntry::flag()))
|
||
} else {
|
||
None
|
||
}
|
||
})
|
||
.collect();
|
||
|
||
if !attr::contains_name(attrs, sym::no_core) {
|
||
let ident = IdentKey::with_root_ctxt(sym::core);
|
||
extern_prelude.insert(ident, ExternPreludeEntry::flag());
|
||
if !attr::contains_name(attrs, sym::no_std) {
|
||
let ident = IdentKey::with_root_ctxt(sym::std);
|
||
extern_prelude.insert(ident, ExternPreludeEntry::flag());
|
||
}
|
||
}
|
||
|
||
let registered_tools = tcx.registered_tools(());
|
||
let edition = tcx.sess.edition();
|
||
|
||
let mut resolver = Resolver {
|
||
tcx,
|
||
|
||
// The outermost module has def ID 0; this is not reflected in the
|
||
// AST.
|
||
graph_root,
|
||
assert_speculative: false, // Only set/cleared in Resolver::resolve_imports for now
|
||
extern_prelude,
|
||
|
||
empty_module,
|
||
local_modules,
|
||
local_module_map,
|
||
extern_module_map: Default::default(),
|
||
|
||
glob_map: Default::default(),
|
||
maybe_unused_trait_imports: Default::default(),
|
||
|
||
arenas,
|
||
dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT),
|
||
builtin_type_decls: PrimTy::ALL
|
||
.iter()
|
||
.map(|prim_ty| {
|
||
let res = Res::PrimTy(*prim_ty);
|
||
let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT);
|
||
(prim_ty.name(), decl)
|
||
})
|
||
.collect(),
|
||
builtin_attr_decls: BUILTIN_ATTRIBUTES
|
||
.iter()
|
||
.map(|builtin_attr| {
|
||
let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name));
|
||
let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT);
|
||
(builtin_attr.name, decl)
|
||
})
|
||
.collect(),
|
||
registered_tool_decls: registered_tools
|
||
.iter()
|
||
.map(|&ident| {
|
||
let res = Res::ToolMod;
|
||
let decl = arenas.new_pub_def_decl(res, ident.span, LocalExpnId::ROOT);
|
||
(IdentKey::new(ident), decl)
|
||
})
|
||
.collect(),
|
||
registered_tools,
|
||
macro_use_prelude: Default::default(),
|
||
extern_macro_map: Default::default(),
|
||
dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)),
|
||
dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)),
|
||
non_macro_attr: arenas
|
||
.alloc_macro(MacroData::new(Arc::new(SyntaxExtension::non_macro_attr(edition)))),
|
||
unused_macros: Default::default(),
|
||
unused_macro_rules: Default::default(),
|
||
single_segment_macro_resolutions: Default::default(),
|
||
multi_segment_macro_resolutions: Default::default(),
|
||
lint_buffer: LintBuffer::default(),
|
||
node_id_to_def_id,
|
||
invocation_parents,
|
||
trait_impls: Default::default(),
|
||
confused_type_with_std_module: Default::default(),
|
||
stripped_cfg_items: Default::default(),
|
||
effective_visibilities: Default::default(),
|
||
doc_link_resolutions: Default::default(),
|
||
doc_link_traits_in_scope: Default::default(),
|
||
current_crate_outer_attr_insert_span,
|
||
..
|
||
};
|
||
|
||
let root_parent_scope = ParentScope::module(graph_root, resolver.arenas);
|
||
resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope);
|
||
resolver.feed_visibility(crate_feed, Visibility::Public);
|
||
|
||
resolver
|
||
}
|
||
|
||
fn new_local_module(
|
||
&mut self,
|
||
parent: Option<Module<'ra>>,
|
||
kind: ModuleKind,
|
||
expn_id: ExpnId,
|
||
span: Span,
|
||
no_implicit_prelude: bool,
|
||
) -> Module<'ra> {
|
||
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
|
||
self.local_modules.push(module);
|
||
if let Some(def_id) = module.opt_def_id() {
|
||
self.local_module_map.insert(def_id.expect_local(), module);
|
||
}
|
||
module
|
||
}
|
||
|
||
fn new_extern_module(
|
||
&self,
|
||
parent: Option<Module<'ra>>,
|
||
kind: ModuleKind,
|
||
expn_id: ExpnId,
|
||
span: Span,
|
||
no_implicit_prelude: bool,
|
||
) -> Module<'ra> {
|
||
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
|
||
self.extern_module_map.borrow_mut().insert(module.def_id(), module);
|
||
module
|
||
}
|
||
|
||
fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData {
|
||
let mac = self.arenas.alloc_macro(macro_data);
|
||
self.local_macro_map.insert(def_id, mac);
|
||
mac
|
||
}
|
||
|
||
fn next_node_id(&mut self) -> NodeId {
|
||
let start = self.next_node_id;
|
||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||
self.next_node_id = ast::NodeId::from_u32(next);
|
||
start
|
||
}
|
||
|
||
fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
|
||
let start = self.next_node_id;
|
||
let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
|
||
self.next_node_id = ast::NodeId::from_usize(end);
|
||
start..self.next_node_id
|
||
}
|
||
|
||
pub fn lint_buffer(&mut self) -> &mut LintBuffer {
|
||
&mut self.lint_buffer
|
||
}
|
||
|
||
pub fn arenas() -> ResolverArenas<'ra> {
|
||
Default::default()
|
||
}
|
||
|
||
fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) {
|
||
let feed = feed.upgrade(self.tcx);
|
||
feed.visibility(vis.to_def_id());
|
||
self.visibilities_for_hashing.push((feed.def_id(), vis));
|
||
}
|
||
|
||
pub fn into_outputs(self) -> ResolverOutputs {
|
||
let proc_macros = self.proc_macros;
|
||
let expn_that_defined = self.expn_that_defined;
|
||
let extern_crate_map = self.extern_crate_map;
|
||
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
|
||
let glob_map = self.glob_map;
|
||
let main_def = self.main_def;
|
||
let confused_type_with_std_module = self.confused_type_with_std_module;
|
||
let effective_visibilities = self.effective_visibilities;
|
||
|
||
let stripped_cfg_items = self
|
||
.stripped_cfg_items
|
||
.into_iter()
|
||
.filter_map(|item| {
|
||
let parent_module =
|
||
self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id();
|
||
Some(StrippedCfgItem { parent_module, ident: item.ident, cfg: item.cfg })
|
||
})
|
||
.collect();
|
||
|
||
let global_ctxt = ResolverGlobalCtxt {
|
||
expn_that_defined,
|
||
visibilities_for_hashing: self.visibilities_for_hashing,
|
||
effective_visibilities,
|
||
extern_crate_map,
|
||
module_children: self.module_children,
|
||
ambig_module_children: self.ambig_module_children,
|
||
glob_map,
|
||
maybe_unused_trait_imports,
|
||
main_def,
|
||
trait_impls: self.trait_impls,
|
||
proc_macros,
|
||
confused_type_with_std_module,
|
||
doc_link_resolutions: self.doc_link_resolutions,
|
||
doc_link_traits_in_scope: self.doc_link_traits_in_scope,
|
||
all_macro_rules: self.all_macro_rules,
|
||
stripped_cfg_items,
|
||
};
|
||
let ast_lowering = ty::ResolverAstLowering {
|
||
partial_res_map: self.partial_res_map,
|
||
import_res_map: self.import_res_map,
|
||
label_res_map: self.label_res_map,
|
||
lifetimes_res_map: self.lifetimes_res_map,
|
||
extra_lifetime_params_map: self.extra_lifetime_params_map,
|
||
next_node_id: self.next_node_id,
|
||
node_id_to_def_id: self
|
||
.node_id_to_def_id
|
||
.into_items()
|
||
.map(|(k, f)| (k, f.key()))
|
||
.collect(),
|
||
trait_map: self.trait_map,
|
||
lifetime_elision_allowed: self.lifetime_elision_allowed,
|
||
lint_buffer: Steal::new(self.lint_buffer),
|
||
delegation_fn_sigs: self.delegation_fn_sigs,
|
||
delegation_infos: self.delegation_infos,
|
||
};
|
||
ResolverOutputs { global_ctxt, ast_lowering }
|
||
}
|
||
|
||
fn cstore(&self) -> FreezeReadGuard<'_, CStore> {
|
||
CStore::from_tcx(self.tcx)
|
||
}
|
||
|
||
fn cstore_mut(&self) -> FreezeWriteGuard<'_, CStore> {
|
||
CStore::from_tcx_mut(self.tcx)
|
||
}
|
||
|
||
fn dummy_ext(&self, macro_kind: MacroKind) -> Arc<SyntaxExtension> {
|
||
match macro_kind {
|
||
MacroKind::Bang => Arc::clone(&self.dummy_ext_bang),
|
||
MacroKind::Derive => Arc::clone(&self.dummy_ext_derive),
|
||
MacroKind::Attr => Arc::clone(&self.non_macro_attr.ext),
|
||
}
|
||
}
|
||
|
||
/// Returns a conditionally mutable resolver.
|
||
///
|
||
/// Currently only dependent on `assert_speculative`, if `assert_speculative` is false,
|
||
/// the resolver will allow mutation; otherwise, it will be immutable.
|
||
fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> {
|
||
CmResolver::new(self, !self.assert_speculative)
|
||
}
|
||
|
||
/// Runs the function on each namespace.
|
||
fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
|
||
f(self, TypeNS);
|
||
f(self, ValueNS);
|
||
f(self, MacroNS);
|
||
}
|
||
|
||
fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>(
|
||
mut self: CmResolver<'r, 'ra, 'tcx>,
|
||
mut f: F,
|
||
) {
|
||
f(self.reborrow(), TypeNS);
|
||
f(self.reborrow(), ValueNS);
|
||
f(self, MacroNS);
|
||
}
|
||
|
||
fn is_builtin_macro(&self, res: Res) -> bool {
|
||
self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some())
|
||
}
|
||
|
||
fn is_specific_builtin_macro(&self, res: Res, symbol: Symbol) -> bool {
|
||
self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name == Some(symbol))
|
||
}
|
||
|
||
fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
|
||
loop {
|
||
match ctxt.outer_expn_data().macro_def_id {
|
||
Some(def_id) => return def_id,
|
||
None => ctxt.remove_mark(),
|
||
};
|
||
}
|
||
}
|
||
|
||
/// Entry point to crate resolution.
|
||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||
self.tcx.sess.time("resolve_crate", || {
|
||
self.tcx.sess.time("finalize_imports", || self.finalize_imports());
|
||
let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
|
||
EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
|
||
});
|
||
self.tcx.sess.time("lint_reexports", || self.lint_reexports(exported_ambiguities));
|
||
self.tcx
|
||
.sess
|
||
.time("finalize_macro_resolutions", || self.finalize_macro_resolutions(krate));
|
||
self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
|
||
self.tcx.sess.time("resolve_main", || self.resolve_main());
|
||
self.tcx.sess.time("resolve_check_unused", || self.check_unused(krate));
|
||
self.tcx.sess.time("resolve_report_errors", || self.report_errors(krate));
|
||
self.tcx
|
||
.sess
|
||
.time("resolve_postprocess", || self.cstore_mut().postprocess(self.tcx, krate));
|
||
});
|
||
|
||
// Make sure we don't mutate the cstore from here on.
|
||
self.tcx.untracked().cstore.freeze();
|
||
}
|
||
|
||
fn traits_in_scope(
|
||
&mut self,
|
||
current_trait: Option<Module<'ra>>,
|
||
parent_scope: &ParentScope<'ra>,
|
||
sp: Span,
|
||
assoc_item: Option<(Symbol, Namespace)>,
|
||
) -> Vec<TraitCandidate> {
|
||
let mut found_traits = Vec::new();
|
||
|
||
if let Some(module) = current_trait {
|
||
if self.trait_may_have_item(Some(module), assoc_item) {
|
||
let def_id = module.def_id();
|
||
found_traits.push(TraitCandidate {
|
||
def_id,
|
||
import_ids: smallvec![],
|
||
lint_ambiguous: false,
|
||
});
|
||
}
|
||
}
|
||
|
||
let scope_set = ScopeSet::All(TypeNS);
|
||
let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt());
|
||
self.cm().visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| {
|
||
match scope {
|
||
Scope::ModuleNonGlobs(module, _) => {
|
||
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
|
||
}
|
||
Scope::ModuleGlobs(..) => {
|
||
// Already handled in `ModuleNonGlobs` (but see #144993).
|
||
}
|
||
Scope::StdLibPrelude => {
|
||
if let Some(module) = this.prelude {
|
||
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
|
||
}
|
||
}
|
||
Scope::ExternPreludeItems
|
||
| Scope::ExternPreludeFlags
|
||
| Scope::ToolPrelude
|
||
| Scope::BuiltinTypes => {}
|
||
_ => unreachable!(),
|
||
}
|
||
ControlFlow::<()>::Continue(())
|
||
});
|
||
|
||
found_traits
|
||
}
|
||
|
||
fn traits_in_module(
|
||
&mut self,
|
||
module: Module<'ra>,
|
||
assoc_item: Option<(Symbol, Namespace)>,
|
||
found_traits: &mut Vec<TraitCandidate>,
|
||
) {
|
||
module.ensure_traits(self);
|
||
let traits = module.traits.borrow();
|
||
for &(trait_name, trait_binding, trait_module, lint_ambiguous) in
|
||
traits.as_ref().unwrap().iter()
|
||
{
|
||
if self.trait_may_have_item(trait_module, assoc_item) {
|
||
let def_id = trait_binding.res().def_id();
|
||
let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name);
|
||
found_traits.push(TraitCandidate { def_id, import_ids, lint_ambiguous });
|
||
}
|
||
}
|
||
}
|
||
|
||
// List of traits in scope is pruned on best effort basis. We reject traits not having an
|
||
// associated item with the given name and namespace (if specified). This is a conservative
|
||
// optimization, proper hygienic type-based resolution of associated items is done in typeck.
|
||
// We don't reject trait aliases (`trait_module == None`) because we don't have access to their
|
||
// associated items.
|
||
fn trait_may_have_item(
|
||
&self,
|
||
trait_module: Option<Module<'ra>>,
|
||
assoc_item: Option<(Symbol, Namespace)>,
|
||
) -> bool {
|
||
match (trait_module, assoc_item) {
|
||
(Some(trait_module), Some((name, ns))) => self
|
||
.resolutions(trait_module)
|
||
.borrow()
|
||
.iter()
|
||
.any(|(key, _name_resolution)| key.ns == ns && key.ident.name == name),
|
||
_ => true,
|
||
}
|
||
}
|
||
|
||
fn find_transitive_imports(
|
||
&mut self,
|
||
mut kind: &DeclKind<'_>,
|
||
trait_name: Symbol,
|
||
) -> SmallVec<[LocalDefId; 1]> {
|
||
let mut import_ids = smallvec![];
|
||
while let DeclKind::Import { import, source_decl, .. } = kind {
|
||
if let Some(node_id) = import.id() {
|
||
let def_id = self.local_def_id(node_id);
|
||
self.maybe_unused_trait_imports.insert(def_id);
|
||
import_ids.push(def_id);
|
||
}
|
||
self.add_to_glob_map(*import, trait_name);
|
||
kind = &source_decl.kind;
|
||
}
|
||
import_ids
|
||
}
|
||
|
||
fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
|
||
if module.populate_on_access.get() {
|
||
module.populate_on_access.set(false);
|
||
self.build_reduced_graph_external(module);
|
||
}
|
||
&module.0.0.lazy_resolutions
|
||
}
|
||
|
||
fn resolution(
|
||
&self,
|
||
module: Module<'ra>,
|
||
key: BindingKey,
|
||
) -> Option<Ref<'ra, NameResolution<'ra>>> {
|
||
self.resolutions(module).borrow().get(&key).map(|resolution| resolution.borrow())
|
||
}
|
||
|
||
fn resolution_or_default(
|
||
&self,
|
||
module: Module<'ra>,
|
||
key: BindingKey,
|
||
orig_ident_span: Span,
|
||
) -> &'ra CmRefCell<NameResolution<'ra>> {
|
||
self.resolutions(module)
|
||
.borrow_mut_unchecked()
|
||
.entry(key)
|
||
.or_insert_with(|| self.arenas.alloc_name_resolution(orig_ident_span))
|
||
}
|
||
|
||
/// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors
|
||
fn matches_previous_ambiguity_error(&self, ambi: &AmbiguityError<'_>) -> bool {
|
||
for ambiguity_error in &self.ambiguity_errors {
|
||
// if the span location and ident as well as its span are the same
|
||
if ambiguity_error.kind == ambi.kind
|
||
&& ambiguity_error.ident == ambi.ident
|
||
&& ambiguity_error.ident.span == ambi.ident.span
|
||
&& ambiguity_error.b1.span == ambi.b1.span
|
||
&& ambiguity_error.b2.span == ambi.b2.span
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
false
|
||
}
|
||
|
||
fn record_use(&mut self, ident: Ident, used_decl: Decl<'ra>, used: Used) {
|
||
self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity.get());
|
||
}
|
||
|
||
fn record_use_inner(
|
||
&mut self,
|
||
ident: Ident,
|
||
used_decl: Decl<'ra>,
|
||
used: Used,
|
||
warn_ambiguity: bool,
|
||
) {
|
||
if let Some(b2) = used_decl.ambiguity.get() {
|
||
let ambiguity_error = AmbiguityError {
|
||
kind: AmbiguityKind::GlobVsGlob,
|
||
ambig_vis: None,
|
||
ident,
|
||
b1: used_decl,
|
||
b2,
|
||
scope1: Scope::ModuleGlobs(used_decl.parent_module.unwrap(), None),
|
||
scope2: Scope::ModuleGlobs(b2.parent_module.unwrap(), None),
|
||
warning: if warn_ambiguity { Some(AmbiguityWarning::GlobImport) } else { None },
|
||
};
|
||
if !self.matches_previous_ambiguity_error(&ambiguity_error) {
|
||
// avoid duplicated span information to be emit out
|
||
self.ambiguity_errors.push(ambiguity_error);
|
||
}
|
||
}
|
||
if let DeclKind::Import { import, source_decl } = used_decl.kind {
|
||
if let ImportKind::MacroUse { warn_private: true } = import.kind {
|
||
// Do not report the lint if the macro name resolves in stdlib prelude
|
||
// even without the problematic `macro_use` import.
|
||
let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| {
|
||
let empty_module = self.empty_module;
|
||
let arenas = self.arenas;
|
||
self.cm()
|
||
.maybe_resolve_ident_in_module(
|
||
ModuleOrUniformRoot::Module(prelude),
|
||
ident,
|
||
MacroNS,
|
||
&ParentScope::module(empty_module, arenas),
|
||
None,
|
||
)
|
||
.is_ok()
|
||
});
|
||
if !found_in_stdlib_prelude {
|
||
self.lint_buffer().buffer_lint(
|
||
PRIVATE_MACRO_USE,
|
||
import.root_id,
|
||
ident.span,
|
||
errors::MacroIsPrivate { ident },
|
||
);
|
||
}
|
||
}
|
||
// Avoid marking `extern crate` items that refer to a name from extern prelude,
|
||
// but not introduce it, as used if they are accessed from lexical scope.
|
||
if used == Used::Scope
|
||
&& let Some(entry) = self.extern_prelude.get(&IdentKey::new(ident))
|
||
&& let Some((item_decl, _, false)) = entry.item_decl
|
||
&& item_decl == used_decl
|
||
{
|
||
return;
|
||
}
|
||
let old_used = self.import_use_map.entry(import).or_insert(used);
|
||
if *old_used < used {
|
||
*old_used = used;
|
||
}
|
||
if let Some(id) = import.id() {
|
||
self.used_imports.insert(id);
|
||
}
|
||
self.add_to_glob_map(import, ident.name);
|
||
self.record_use_inner(
|
||
ident,
|
||
source_decl,
|
||
Used::Other,
|
||
warn_ambiguity || source_decl.warn_ambiguity.get(),
|
||
);
|
||
}
|
||
}
|
||
|
||
#[inline]
|
||
fn add_to_glob_map(&mut self, import: Import<'_>, name: Symbol) {
|
||
if let ImportKind::Glob { id, .. } = import.kind {
|
||
let def_id = self.local_def_id(id);
|
||
self.glob_map.entry(def_id).or_default().insert(name);
|
||
}
|
||
}
|
||
|
||
fn resolve_crate_root(&self, ident: Ident) -> Module<'ra> {
|
||
debug!("resolve_crate_root({:?})", ident);
|
||
let mut ctxt = ident.span.ctxt();
|
||
let mark = if ident.name == kw::DollarCrate {
|
||
// When resolving `$crate` from a `macro_rules!` invoked in a `macro`,
|
||
// we don't want to pretend that the `macro_rules!` definition is in the `macro`
|
||
// as described in `SyntaxContext::apply_mark`, so we ignore prepended opaque marks.
|
||
// FIXME: This is only a guess and it doesn't work correctly for `macro_rules!`
|
||
// definitions actually produced by `macro` and `macro` definitions produced by
|
||
// `macro_rules!`, but at least such configurations are not stable yet.
|
||
ctxt = ctxt.normalize_to_macro_rules();
|
||
debug!(
|
||
"resolve_crate_root: marks={:?}",
|
||
ctxt.marks().into_iter().map(|(i, t)| (i.expn_data(), t)).collect::<Vec<_>>()
|
||
);
|
||
let mut iter = ctxt.marks().into_iter().rev().peekable();
|
||
let mut result = None;
|
||
// Find the last opaque mark from the end if it exists.
|
||
while let Some(&(mark, transparency)) = iter.peek() {
|
||
if transparency == Transparency::Opaque {
|
||
result = Some(mark);
|
||
iter.next();
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
debug!(
|
||
"resolve_crate_root: found opaque mark {:?} {:?}",
|
||
result,
|
||
result.map(|r| r.expn_data())
|
||
);
|
||
// Then find the last semi-opaque mark from the end if it exists.
|
||
for (mark, transparency) in iter {
|
||
if transparency == Transparency::SemiOpaque {
|
||
result = Some(mark);
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
debug!(
|
||
"resolve_crate_root: found semi-opaque mark {:?} {:?}",
|
||
result,
|
||
result.map(|r| r.expn_data())
|
||
);
|
||
result
|
||
} else {
|
||
debug!("resolve_crate_root: not DollarCrate");
|
||
ctxt = ctxt.normalize_to_macros_2_0();
|
||
ctxt.adjust(ExpnId::root())
|
||
};
|
||
let module = match mark {
|
||
Some(def) => self.expn_def_scope(def),
|
||
None => {
|
||
debug!(
|
||
"resolve_crate_root({:?}): found no mark (ident.span = {:?})",
|
||
ident, ident.span
|
||
);
|
||
return self.graph_root;
|
||
}
|
||
};
|
||
let module = self.expect_module(
|
||
module.opt_def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id(),
|
||
);
|
||
debug!(
|
||
"resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})",
|
||
ident,
|
||
module,
|
||
module.kind.name(),
|
||
ident.span
|
||
);
|
||
module
|
||
}
|
||
|
||
fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> {
|
||
let mut module = self.expect_module(module.nearest_parent_mod());
|
||
while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
|
||
let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark()));
|
||
module = self.expect_module(parent.nearest_parent_mod());
|
||
}
|
||
module
|
||
}
|
||
|
||
fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
|
||
debug!("(recording res) recording {:?} for {}", resolution, node_id);
|
||
if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
|
||
panic!("path resolved multiple times ({prev_res:?} before, {resolution:?} now)");
|
||
}
|
||
}
|
||
|
||
fn record_pat_span(&mut self, node: NodeId, span: Span) {
|
||
debug!("(recording pat) recording {:?} for {:?}", node, span);
|
||
self.pat_span_map.insert(node, span);
|
||
}
|
||
|
||
fn is_accessible_from(&self, vis: Visibility<impl Into<DefId>>, module: Module<'ra>) -> bool {
|
||
vis.is_accessible_from(module.nearest_parent_mod(), self.tcx)
|
||
}
|
||
|
||
fn disambiguate_macro_rules_vs_modularized(
|
||
&self,
|
||
macro_rules: Decl<'ra>,
|
||
modularized: Decl<'ra>,
|
||
) -> bool {
|
||
// Some non-controversial subset of ambiguities "modularized macro name" vs "macro_rules"
|
||
// is disambiguated to mitigate regressions from macro modularization.
|
||
// Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
|
||
//
|
||
// Panic on unwrap should be impossible, the only name_bindings passed in should be from
|
||
// `resolve_ident_in_scope_set` which will always refer to a local binding from an
|
||
// import or macro definition.
|
||
let macro_rules = macro_rules.parent_module.unwrap();
|
||
let modularized = modularized.parent_module.unwrap();
|
||
macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod()
|
||
&& modularized.is_ancestor_of(macro_rules)
|
||
}
|
||
|
||
fn extern_prelude_get_item<'r>(
|
||
mut self: CmResolver<'r, 'ra, 'tcx>,
|
||
ident: IdentKey,
|
||
orig_ident_span: Span,
|
||
finalize: bool,
|
||
) -> Option<Decl<'ra>> {
|
||
let entry = self.extern_prelude.get(&ident);
|
||
entry.and_then(|entry| entry.item_decl).map(|(decl, ..)| {
|
||
if finalize {
|
||
self.get_mut().record_use(ident.orig(orig_ident_span), decl, Used::Scope);
|
||
}
|
||
decl
|
||
})
|
||
}
|
||
|
||
fn extern_prelude_get_flag(
|
||
&self,
|
||
ident: IdentKey,
|
||
orig_ident_span: Span,
|
||
finalize: bool,
|
||
) -> Option<Decl<'ra>> {
|
||
let entry = self.extern_prelude.get(&ident);
|
||
entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| {
|
||
let (pending_decl, finalized) = flag_decl.get();
|
||
let decl = match pending_decl {
|
||
PendingDecl::Ready(decl) => {
|
||
if finalize && !finalized {
|
||
self.cstore_mut().process_path_extern(
|
||
self.tcx,
|
||
ident.name,
|
||
orig_ident_span,
|
||
);
|
||
}
|
||
decl
|
||
}
|
||
PendingDecl::Pending => {
|
||
debug_assert!(!finalized);
|
||
let crate_id = if finalize {
|
||
self.cstore_mut().process_path_extern(self.tcx, ident.name, orig_ident_span)
|
||
} else {
|
||
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
|
||
};
|
||
crate_id.map(|crate_id| {
|
||
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
|
||
self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT)
|
||
})
|
||
}
|
||
};
|
||
flag_decl.set((PendingDecl::Ready(decl), finalize || finalized));
|
||
decl.or_else(|| finalize.then_some(self.dummy_decl))
|
||
})
|
||
}
|
||
|
||
/// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>`
|
||
/// isn't something that can be returned because it can't be made to live that long,
|
||
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
|
||
/// just that an error occurred.
|
||
fn resolve_rustdoc_path(
|
||
&mut self,
|
||
path_str: &str,
|
||
ns: Namespace,
|
||
parent_scope: ParentScope<'ra>,
|
||
) -> Option<Res> {
|
||
let segments: Result<Vec<_>, ()> = path_str
|
||
.split("::")
|
||
.enumerate()
|
||
.map(|(i, s)| {
|
||
let sym = if s.is_empty() {
|
||
if i == 0 {
|
||
// For a path like `::a::b`, use `kw::PathRoot` as the leading segment.
|
||
kw::PathRoot
|
||
} else {
|
||
return Err(()); // occurs in cases like `String::`
|
||
}
|
||
} else {
|
||
Symbol::intern(s)
|
||
};
|
||
Ok(Segment::from_ident(Ident::with_dummy_span(sym)))
|
||
})
|
||
.collect();
|
||
let Ok(segments) = segments else { return None };
|
||
|
||
match self.cm().maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
|
||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
|
||
PathResult::NonModule(path_res) => {
|
||
path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _)))
|
||
}
|
||
PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
|
||
None
|
||
}
|
||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||
}
|
||
}
|
||
|
||
/// Retrieves definition span of the given `DefId`.
|
||
fn def_span(&self, def_id: DefId) -> Span {
|
||
match def_id.as_local() {
|
||
Some(def_id) => self.tcx.source_span(def_id),
|
||
// Query `def_span` is not used because hashing its result span is expensive.
|
||
None => self.cstore().def_span_untracked(self.tcx(), def_id),
|
||
}
|
||
}
|
||
|
||
fn field_idents(&self, def_id: DefId) -> Option<Vec<Ident>> {
|
||
match def_id.as_local() {
|
||
Some(def_id) => self.field_names.get(&def_id).cloned(),
|
||
None if matches!(
|
||
self.tcx.def_kind(def_id),
|
||
DefKind::Struct | DefKind::Union | DefKind::Variant
|
||
) =>
|
||
{
|
||
Some(
|
||
self.tcx
|
||
.associated_item_def_ids(def_id)
|
||
.iter()
|
||
.map(|&def_id| {
|
||
Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id))
|
||
})
|
||
.collect(),
|
||
)
|
||
}
|
||
_ => None,
|
||
}
|
||
}
|
||
|
||
fn field_defaults(&self, def_id: DefId) -> Option<Vec<Symbol>> {
|
||
match def_id.as_local() {
|
||
Some(def_id) => self.field_defaults.get(&def_id).cloned(),
|
||
None if matches!(
|
||
self.tcx.def_kind(def_id),
|
||
DefKind::Struct | DefKind::Union | DefKind::Variant
|
||
) =>
|
||
{
|
||
Some(
|
||
self.tcx
|
||
.associated_item_def_ids(def_id)
|
||
.iter()
|
||
.filter_map(|&def_id| {
|
||
self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id))
|
||
})
|
||
.collect(),
|
||
)
|
||
}
|
||
_ => None,
|
||
}
|
||
}
|
||
|
||
/// Checks if an expression refers to a function marked with
|
||
/// `#[rustc_legacy_const_generics]` and returns the argument index list
|
||
/// from the attribute.
|
||
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
|
||
let ExprKind::Path(None, path) = &expr.kind else {
|
||
return None;
|
||
};
|
||
// Don't perform legacy const generics rewriting if the path already
|
||
// has generic arguments.
|
||
if path.segments.last().unwrap().args.is_some() {
|
||
return None;
|
||
}
|
||
|
||
let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
|
||
|
||
// We only support cross-crate argument rewriting. Uses
|
||
// within the same crate should be updated to use the new
|
||
// const generics style.
|
||
if def_id.is_local() {
|
||
return None;
|
||
}
|
||
|
||
find_attr!(
|
||
// we can use parsed attrs here since for other crates they're already available
|
||
self.tcx.get_all_attrs(def_id),
|
||
AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes
|
||
)
|
||
.map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect())
|
||
}
|
||
|
||
fn resolve_main(&mut self) {
|
||
let any_exe = self.tcx.crate_types().contains(&CrateType::Executable);
|
||
// Don't try to resolve main unless it's an executable
|
||
if !any_exe {
|
||
return;
|
||
}
|
||
|
||
let module = self.graph_root;
|
||
let ident = Ident::with_dummy_span(sym::main);
|
||
let parent_scope = &ParentScope::module(module, self.arenas);
|
||
|
||
let Ok(name_binding) = self.cm().maybe_resolve_ident_in_module(
|
||
ModuleOrUniformRoot::Module(module),
|
||
ident,
|
||
ValueNS,
|
||
parent_scope,
|
||
None,
|
||
) else {
|
||
return;
|
||
};
|
||
|
||
let res = name_binding.res();
|
||
let is_import = name_binding.is_import();
|
||
let span = name_binding.span;
|
||
if let Res::Def(DefKind::Fn, _) = res {
|
||
self.record_use(ident, name_binding, Used::Other);
|
||
}
|
||
self.main_def = Some(MainDefinition { res, is_import, span });
|
||
}
|
||
}
|
||
|
||
fn names_to_string(names: impl Iterator<Item = Symbol>) -> String {
|
||
let mut result = String::new();
|
||
for (i, name) in names.filter(|name| *name != kw::PathRoot).enumerate() {
|
||
if i > 0 {
|
||
result.push_str("::");
|
||
}
|
||
if Ident::with_dummy_span(name).is_raw_guess() {
|
||
result.push_str("r#");
|
||
}
|
||
result.push_str(name.as_str());
|
||
}
|
||
result
|
||
}
|
||
|
||
fn path_names_to_string(path: &Path) -> String {
|
||
names_to_string(path.segments.iter().map(|seg| seg.ident.name))
|
||
}
|
||
|
||
/// A somewhat inefficient routine to obtain the name of a module.
|
||
fn module_to_string(mut module: Module<'_>) -> Option<String> {
|
||
let mut names = Vec::new();
|
||
loop {
|
||
if let ModuleKind::Def(.., name) = module.kind {
|
||
if let Some(parent) = module.parent {
|
||
// `unwrap` is safe: the presence of a parent means it's not the crate root.
|
||
names.push(name.unwrap());
|
||
module = parent
|
||
} else {
|
||
break;
|
||
}
|
||
} else {
|
||
names.push(sym::opaque_module_name_placeholder);
|
||
let Some(parent) = module.parent else {
|
||
return None;
|
||
};
|
||
module = parent;
|
||
}
|
||
}
|
||
if names.is_empty() {
|
||
return None;
|
||
}
|
||
Some(names_to_string(names.iter().rev().copied()))
|
||
}
|
||
|
||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||
enum Stage {
|
||
/// Resolving an import or a macro.
|
||
/// Used when macro expansion is either not yet finished, or we are finalizing its results.
|
||
/// Used by default as a more restrictive variant that can produce additional errors.
|
||
Early,
|
||
/// Resolving something in late resolution when all imports are resolved
|
||
/// and all macros are expanded.
|
||
Late,
|
||
}
|
||
|
||
/// Invariant: if `Finalize` is used, expansion and import resolution must be complete.
|
||
#[derive(Copy, Clone, Debug)]
|
||
struct Finalize {
|
||
/// Node ID for linting.
|
||
node_id: NodeId,
|
||
/// Span of the whole path or some its characteristic fragment.
|
||
/// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
|
||
path_span: Span,
|
||
/// Span of the path start, suitable for prepending something to it.
|
||
/// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
|
||
root_span: Span,
|
||
/// Whether to report privacy errors or silently return "no resolution" for them,
|
||
/// similarly to speculative resolution.
|
||
report_private: bool = true,
|
||
/// Tracks whether an item is used in scope or used relatively to a module.
|
||
used: Used = Used::Other,
|
||
/// Finalizing early or late resolution.
|
||
stage: Stage = Stage::Early,
|
||
/// Nominal visibility of the import item, in case we are resolving an import's final segment.
|
||
import_vis: Option<Visibility> = None,
|
||
}
|
||
|
||
impl Finalize {
|
||
fn new(node_id: NodeId, path_span: Span) -> Finalize {
|
||
Finalize::with_root_span(node_id, path_span, path_span)
|
||
}
|
||
|
||
fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
|
||
Finalize { node_id, path_span, root_span, .. }
|
||
}
|
||
}
|
||
|
||
pub fn provide(providers: &mut Providers) {
|
||
providers.registered_tools = macros::registered_tools;
|
||
}
|
||
|
||
/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions.
|
||
///
|
||
/// `Cm` stands for "conditionally mutable".
|
||
///
|
||
/// Prefer constructing it through [`Resolver::cm`] to ensure correctness.
|
||
type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
|
||
|
||
// FIXME: These are cells for caches that can be populated even during speculative resolution,
|
||
// and should be replaced with mutexes, atomics, or other synchronized data when migrating to
|
||
// parallel name resolution.
|
||
use std::cell::{Cell as CacheCell, RefCell as CacheRefCell};
|
||
|
||
// FIXME: `*_unchecked` methods in the module below should be eliminated in the process
|
||
// of migration to parallel name resolution.
|
||
mod ref_mut {
|
||
use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut};
|
||
use std::fmt;
|
||
use std::ops::Deref;
|
||
|
||
use crate::Resolver;
|
||
|
||
/// A wrapper around a mutable reference that conditionally allows mutable access.
|
||
pub(crate) struct RefOrMut<'a, T> {
|
||
p: &'a mut T,
|
||
mutable: bool,
|
||
}
|
||
|
||
impl<'a, T> Deref for RefOrMut<'a, T> {
|
||
type Target = T;
|
||
|
||
fn deref(&self) -> &Self::Target {
|
||
self.p
|
||
}
|
||
}
|
||
|
||
impl<'a, T> AsRef<T> for RefOrMut<'a, T> {
|
||
fn as_ref(&self) -> &T {
|
||
self.p
|
||
}
|
||
}
|
||
|
||
impl<'a, T> RefOrMut<'a, T> {
|
||
pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self {
|
||
RefOrMut { p, mutable }
|
||
}
|
||
|
||
/// This is needed because this wraps a `&mut T` and is therefore not `Copy`.
|
||
pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> {
|
||
RefOrMut { p: self.p, mutable: self.mutable }
|
||
}
|
||
|
||
/// Returns a mutable reference to the inner value if allowed.
|
||
///
|
||
/// # Panics
|
||
/// Panics if the `mutable` flag is false.
|
||
#[track_caller]
|
||
pub(crate) fn get_mut(&mut self) -> &mut T {
|
||
match self.mutable {
|
||
false => panic!("Can't mutably borrow speculative resolver"),
|
||
true => self.p,
|
||
}
|
||
}
|
||
|
||
/// Returns a mutable reference to the inner value without checking if
|
||
/// it's in a mutable state.
|
||
pub(crate) fn get_mut_unchecked(&mut self) -> &mut T {
|
||
self.p
|
||
}
|
||
}
|
||
|
||
/// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver.
|
||
#[derive(Default)]
|
||
pub(crate) struct CmCell<T>(Cell<T>);
|
||
|
||
impl<T: Copy + fmt::Debug> fmt::Debug for CmCell<T> {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
f.debug_tuple("CmCell").field(&self.get()).finish()
|
||
}
|
||
}
|
||
|
||
impl<T: Copy> Clone for CmCell<T> {
|
||
fn clone(&self) -> CmCell<T> {
|
||
CmCell::new(self.get())
|
||
}
|
||
}
|
||
|
||
impl<T: Copy> CmCell<T> {
|
||
pub(crate) const fn get(&self) -> T {
|
||
self.0.get()
|
||
}
|
||
|
||
pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T)
|
||
where
|
||
T: Copy,
|
||
{
|
||
let old = self.get();
|
||
self.set_unchecked(f(old));
|
||
}
|
||
}
|
||
|
||
impl<T> CmCell<T> {
|
||
pub(crate) const fn new(value: T) -> CmCell<T> {
|
||
CmCell(Cell::new(value))
|
||
}
|
||
|
||
pub(crate) fn set_unchecked(&self, val: T) {
|
||
self.0.set(val);
|
||
}
|
||
|
||
pub(crate) fn into_inner(self) -> T {
|
||
self.0.into_inner()
|
||
}
|
||
}
|
||
|
||
/// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver.
|
||
#[derive(Default)]
|
||
pub(crate) struct CmRefCell<T>(RefCell<T>);
|
||
|
||
impl<T> CmRefCell<T> {
|
||
pub(crate) const fn new(value: T) -> CmRefCell<T> {
|
||
CmRefCell(RefCell::new(value))
|
||
}
|
||
|
||
#[track_caller]
|
||
pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> {
|
||
self.0.borrow_mut()
|
||
}
|
||
|
||
#[track_caller]
|
||
pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> {
|
||
if r.assert_speculative {
|
||
panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution");
|
||
}
|
||
self.borrow_mut_unchecked()
|
||
}
|
||
|
||
#[track_caller]
|
||
pub(crate) fn try_borrow_mut_unchecked(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
|
||
self.0.try_borrow_mut()
|
||
}
|
||
|
||
#[track_caller]
|
||
pub(crate) fn borrow(&self) -> Ref<'_, T> {
|
||
self.0.borrow()
|
||
}
|
||
}
|
||
|
||
impl<T: Default> CmRefCell<T> {
|
||
pub(crate) fn take<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> T {
|
||
if r.assert_speculative {
|
||
panic!("Not allowed to mutate a CmRefCell during speculative resolution");
|
||
}
|
||
self.0.take()
|
||
}
|
||
}
|
||
}
|
||
|
||
mod hygiene {
|
||
use rustc_span::{ExpnId, SyntaxContext};
|
||
|
||
/// A newtype around `SyntaxContext` that can only keep contexts produced by
|
||
/// [SyntaxContext::normalize_to_macros_2_0].
|
||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||
pub(crate) struct Macros20NormalizedSyntaxContext(SyntaxContext);
|
||
|
||
impl Macros20NormalizedSyntaxContext {
|
||
#[inline]
|
||
pub(crate) fn new(ctxt: SyntaxContext) -> Macros20NormalizedSyntaxContext {
|
||
Macros20NormalizedSyntaxContext(ctxt.normalize_to_macros_2_0())
|
||
}
|
||
|
||
#[inline]
|
||
pub(crate) fn new_adjusted(
|
||
mut ctxt: SyntaxContext,
|
||
expn_id: ExpnId,
|
||
) -> (Macros20NormalizedSyntaxContext, Option<ExpnId>) {
|
||
let def = ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
|
||
(Macros20NormalizedSyntaxContext(ctxt), def)
|
||
}
|
||
|
||
#[inline]
|
||
pub(crate) fn new_unchecked(ctxt: SyntaxContext) -> Macros20NormalizedSyntaxContext {
|
||
debug_assert_eq!(ctxt, ctxt.normalize_to_macros_2_0());
|
||
Macros20NormalizedSyntaxContext(ctxt)
|
||
}
|
||
|
||
/// The passed closure must preserve the context's normalized-ness.
|
||
#[inline]
|
||
pub(crate) fn update_unchecked<R>(&mut self, f: impl FnOnce(&mut SyntaxContext) -> R) -> R {
|
||
let ret = f(&mut self.0);
|
||
debug_assert_eq!(self.0, self.0.normalize_to_macros_2_0());
|
||
ret
|
||
}
|
||
}
|
||
|
||
impl std::ops::Deref for Macros20NormalizedSyntaxContext {
|
||
type Target = SyntaxContext;
|
||
fn deref(&self) -> &Self::Target {
|
||
&self.0
|
||
}
|
||
}
|
||
}
|