// ignore-tidy-filelength
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
#![feature(type_alias_enum_variants)]
#![recursion_limit="256"]
#![deny(rust_2018_idioms)]
#![deny(internal)]
pub use rustc::hir::def::{Namespace, PerNS};
use GenericParameters::*;
use RibKind::*;
use rustc::hir::map::{Definitions, DefCollector};
use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str};
use rustc::middle::cstore::CrateStore;
use rustc::session::Session;
use rustc::lint;
use rustc::hir::def::{
self, PathResolution, CtorKind, CtorOf, NonMacroAttrKind, DefMap, ImportMap, ExportMap
};
use rustc::hir::def::Namespace::*;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::ty::{self, DefIdTree};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
use rustc::{bug, span_bug};
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::CStore;
use syntax::source_map::SourceMap;
use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind;
use syntax::symbol::{Symbol, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, FnKind, Visitor};
use syntax::attr;
use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::ptr::P;
use syntax::{span_err, struct_span_err, unwrap_or, walk_list};
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use log::debug;
use std::cell::{Cell, RefCell};
use std::{cmp, fmt, iter, mem, ptr};
use std::collections::BTreeSet;
use std::mem::replace;
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
use macros::{InvocationData, LegacyBinding, ParentScope};
type Def = def::Def;
// N.B., this module needs to be declared first so diagnostics are
// registered before they are used.
mod error_codes;
mod diagnostics;
mod macros;
mod check_unused;
mod build_reduced_graph;
mod resolve_imports;
fn is_known_tool(name: Name) -> bool {
["clippy", "rustfmt"].contains(&&*name.as_str())
}
enum Weak {
Yes,
No,
}
enum ScopeSet {
Import(Namespace),
AbsolutePath(Namespace),
Macro(MacroKind),
Module,
}
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
did: Option,
path: Path,
}
/// A field or associated item from self type suggested in case of resolution failure.
enum AssocSuggestion {
Field,
MethodWithSelf,
AssocItem,
}
#[derive(Eq)]
struct BindingError {
name: Name,
origin: BTreeSet,
target: BTreeSet,
}
struct TypoSuggestion {
candidate: Symbol,
/// The kind of the binding ("crate", "module", etc.)
kind: &'static str,
/// An appropriate article to refer to the binding ("a", "an", etc.)
article: &'static str,
}
impl PartialOrd for BindingError {
fn partial_cmp(&self, other: &BindingError) -> Option {
Some(self.cmp(other))
}
}
impl PartialEq for BindingError {
fn eq(&self, other: &BindingError) -> bool {
self.name == other.name
}
}
impl Ord for BindingError {
fn cmp(&self, other: &BindingError) -> cmp::Ordering {
self.name.cmp(&other.name)
}
}
/// A vector of spans and replacements, a message and applicability.
type Suggestion = (Vec<(Span, String)>, String, Applicability);
enum ResolutionError<'a> {
/// Error E0401: can't use type or const parameters from outer function.
GenericParamsFromOuterFunction(Def),
/// Error E0403: the name is already used for a type or const parameter in this generic
/// parameter list.
NameAlreadyUsedInParameterList(Name, &'a Span),
/// Error E0407: method is not a member of trait.
MethodNotMemberOfTrait(Name, &'a str),
/// Error E0437: type is not a member of trait.
TypeNotMemberOfTrait(Name, &'a str),
/// Error E0438: const is not a member of trait.
ConstNotMemberOfTrait(Name, &'a str),
/// Error E0408: variable `{}` is not bound in all patterns.
VariableNotBoundInPattern(&'a BindingError),
/// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
VariableBoundWithDifferentMode(Name, Span),
/// Error E0415: identifier is bound more than once in this parameter list.
IdentifierBoundMoreThanOnceInParameterList(&'a str),
/// Error E0416: identifier is bound more than once in the same pattern.
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
/// Error E0426: use of undeclared label.
UndeclaredLabel(&'a str, Option),
/// Error E0429: `self` imports are only allowed within a `{ }` list.
SelfImportsOnlyAllowedWithin,
/// 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 { label: String, suggestion: Option },
/// 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,
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
/// Error E0671: const parameter cannot depend on type parameter.
ConstParamDependentOnTypeParam,
}
/// Combines an error with provided span and emits it.
///
/// This takes the error provided, combines it with the span and any additional spans inside the
/// error and emits it.
fn resolve_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
span: Span,
resolution_error: ResolutionError<'a>) {
resolve_struct_error(resolver, span, resolution_error).emit();
}
fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
span: Span,
resolution_error: ResolutionError<'a>)
-> DiagnosticBuilder<'sess> {
match resolution_error {
ResolutionError::GenericParamsFromOuterFunction(outer_def) => {
let mut err = struct_span_err!(resolver.session,
span,
E0401,
"can't use generic parameters from outer function",
);
err.span_label(span, format!("use of generic parameter from outer function"));
let cm = resolver.session.source_map();
match outer_def {
Def::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
resolver.definitions.opt_span(def_id)
}) {
err.span_label(
reduce_impl_span_to_impl_keyword(cm, impl_span),
"`Self` type implicitly declared here, by this `impl`",
);
}
match (maybe_trait_defid, maybe_impl_defid) {
(Some(_), None) => {
err.span_label(span, "can't use `Self` here");
}
(_, Some(_)) => {
err.span_label(span, "use a type here instead");
}
(None, None) => bug!("`impl` without trait nor type?"),
}
return err;
},
Def::TyParam(def_id) => {
if let Some(span) = resolver.definitions.opt_span(def_id) {
err.span_label(span, "type parameter from outer function");
}
}
Def::ConstParam(def_id) => {
if let Some(span) = resolver.definitions.opt_span(def_id) {
err.span_label(span, "const parameter from outer function");
}
}
_ => {
bug!("GenericParamsFromOuterFunction should only be used with Def::SelfTy, \
Def::TyParam");
}
}
// Try to retrieve the span of the function signature and generate a new message with
// a local type or const parameter.
let sugg_msg = &format!("try using a local generic parameter instead");
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
// Suggest the modification to the user
err.span_suggestion(
sugg_span,
sugg_msg,
new_snippet,
Applicability::MachineApplicable,
);
} else if let Some(sp) = cm.generate_fn_name_span(span) {
err.span_label(sp,
format!("try adding a local generic parameter in this method instead"));
} else {
err.help(&format!("try using a local generic parameter instead"));
}
err
}
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
let mut err = struct_span_err!(resolver.session,
span,
E0403,
"the name `{}` is already used for a generic \
parameter in this list of generic parameters",
name);
err.span_label(span, "already used");
err.span_label(first_use_span.clone(), format!("first use of `{}`", name));
err
}
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
let mut err = struct_span_err!(resolver.session,
span,
E0407,
"method `{}` is not a member of trait `{}`",
method,
trait_);
err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
let mut err = struct_span_err!(resolver.session,
span,
E0437,
"type `{}` is not a member of trait `{}`",
type_,
trait_);
err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
let mut err = struct_span_err!(resolver.session,
span,
E0438,
"const `{}` is not a member of trait `{}`",
const_,
trait_);
err.span_label(span, format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::VariableNotBoundInPattern(binding_error) => {
let target_sp = binding_error.target.iter().cloned().collect::>();
let msp = MultiSpan::from_spans(target_sp.clone());
let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
let mut err = resolver.session.struct_span_err_with_code(
msp,
&msg,
DiagnosticId::Error("E0408".into()),
);
for sp in target_sp {
err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
}
let origin_sp = binding_error.origin.iter().cloned();
for sp in origin_sp {
err.span_label(sp, "variable not in all patterns");
}
err
}
ResolutionError::VariableBoundWithDifferentMode(variable_name,
first_binding_span) => {
let mut err = struct_span_err!(resolver.session,
span,
E0409,
"variable `{}` is bound in inconsistent \
ways within the same match arm",
variable_name);
err.span_label(span, "bound in different ways");
err.span_label(first_binding_span, "first binding");
err
}
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
let mut err = struct_span_err!(resolver.session,
span,
E0415,
"identifier `{}` is bound more than once in this parameter list",
identifier);
err.span_label(span, "used as parameter more than once");
err
}
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
let mut err = struct_span_err!(resolver.session,
span,
E0416,
"identifier `{}` is bound more than once in the same pattern",
identifier);
err.span_label(span, "used in a pattern more than once");
err
}
ResolutionError::UndeclaredLabel(name, lev_candidate) => {
let mut err = struct_span_err!(resolver.session,
span,
E0426,
"use of undeclared label `{}`",
name);
if let Some(lev_candidate) = lev_candidate {
err.span_suggestion(
span,
"a label with a similar name exists in this scope",
lev_candidate.to_string(),
Applicability::MaybeIncorrect,
);
} else {
err.span_label(span, format!("undeclared label `{}`", name));
}
err
}
ResolutionError::SelfImportsOnlyAllowedWithin => {
struct_span_err!(resolver.session,
span,
E0429,
"{}",
"`self` imports are only allowed within a { } list")
}
ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
let mut err = struct_span_err!(resolver.session, span, E0430,
"`self` import can only appear once in an import list");
err.span_label(span, "can only appear once in an import list");
err
}
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
let mut err = struct_span_err!(resolver.session, span, E0431,
"`self` import can only appear in an import list with \
a non-empty prefix");
err.span_label(span, "can only appear in an import list with a non-empty prefix");
err
}
ResolutionError::FailedToResolve { label, suggestion } => {
let mut err = struct_span_err!(resolver.session, span, E0433,
"failed to resolve: {}", &label);
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
err.multipart_suggestion(&msg, suggestions, applicability);
}
err
}
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
let mut err = struct_span_err!(resolver.session,
span,
E0434,
"{}",
"can't capture dynamic environment in a fn item");
err.help("use the `|| { ... }` closure form instead");
err
}
ResolutionError::AttemptToUseNonConstantValueInConstant => {
let mut err = struct_span_err!(resolver.session, span, E0435,
"attempt to use a non-constant value in a constant");
err.span_label(span, "non-constant value");
err
}
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
let shadows_what = binding.descr();
let mut err = struct_span_err!(resolver.session, span, E0530, "{}s cannot shadow {}s",
what_binding, shadows_what);
err.span_label(span, format!("cannot be named the same as {} {}",
binding.article(), shadows_what));
let participle = if binding.is_import() { "imported" } else { "defined" };
let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
err.span_label(binding.span, msg);
err
}
ResolutionError::ForwardDeclaredTyParam => {
let mut err = struct_span_err!(resolver.session, span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
err.span_label(
span, "defaulted type parameters cannot be forward declared".to_string());
err
}
ResolutionError::ConstParamDependentOnTypeParam => {
let mut err = struct_span_err!(
resolver.session,
span,
E0671,
"const parameters cannot depend on type parameters"
);
err.span_label(span, format!("const parameter depends on type parameter"));
err
}
}
}
/// Adjust the impl span so that just the `impl` keyword is taken by removing
/// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and
/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
///
/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
/// parser. If you need to use this function or something similar, please consider updating the
/// `source_map` functions and this function to something more robust.
fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span {
let impl_span = cm.span_until_char(impl_span, '<');
let impl_span = cm.span_until_whitespace(impl_span);
impl_span
}
#[derive(Copy, Clone, Debug)]
struct BindingInfo {
span: Span,
binding_mode: BindingMode,
}
/// Map from the name in a pattern to its binding mode.
type BindingMap = FxHashMap;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum PatternSource {
Match,
IfLet,
WhileLet,
Let,
For,
FnParam,
}
impl PatternSource {
fn descr(self) -> &'static str {
match self {
PatternSource::Match => "match binding",
PatternSource::IfLet => "if let binding",
PatternSource::WhileLet => "while let binding",
PatternSource::Let => "let binding",
PatternSource::For => "for binding",
PatternSource::FnParam => "function parameter",
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum AliasPossibility {
No,
Maybe,
}
#[derive(Copy, Clone, Debug)]
enum PathSource<'a> {
// Type paths `Path`.
Type,
// Trait paths in bounds or impls.
Trait(AliasPossibility),
// Expression paths `path`, with optional parent context.
Expr(Option<&'a Expr>),
// Paths in path patterns `Path`.
Pat,
// Paths in struct expressions and patterns `Path { .. }`.
Struct,
// Paths in tuple struct patterns `Path(..)`.
TupleStruct,
// `m::A::B` in `::B::C`.
TraitItem(Namespace),
// Path in `pub(path)`
Visibility,
}
impl<'a> PathSource<'a> {
fn namespace(self) -> Namespace {
match self {
PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
PathSource::Visibility => TypeNS,
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
PathSource::TraitItem(ns) => ns,
}
}
fn global_by_default(self) -> bool {
match self {
PathSource::Visibility => true,
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
PathSource::Struct | PathSource::TupleStruct |
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
}
}
fn defer_to_typeck(self) -> bool {
match self {
PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
PathSource::Struct | PathSource::TupleStruct => true,
PathSource::Trait(_) | PathSource::TraitItem(..) |
PathSource::Visibility => false,
}
}
fn descr_expected(self) -> &'static str {
match self {
PathSource::Type => "type",
PathSource::Trait(_) => "trait",
PathSource::Pat => "unit struct/variant or constant",
PathSource::Struct => "struct, variant or union type",
PathSource::TupleStruct => "tuple struct/variant",
PathSource::Visibility => "module",
PathSource::TraitItem(ns) => match ns {
TypeNS => "associated type",
ValueNS => "method or associated constant",
MacroNS => bug!("associated macro"),
},
PathSource::Expr(parent) => match parent.map(|p| &p.node) {
// "function" here means "anything callable" rather than `Def::Fn`,
// this is not precise but usually more helpful than just "value".
Some(&ExprKind::Call(..)) => "function",
_ => "value",
},
}
}
fn is_expected(self, def: Def) -> bool {
match self {
PathSource::Type => match def {
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
Def::Trait(..) | Def::TraitAlias(..) | Def::TyAlias(..) |
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) |
Def::SelfTy(..) | Def::Existential(..) | Def::ForeignTy(..) => true,
_ => false,
},
PathSource::Trait(AliasPossibility::No) => match def {
Def::Trait(..) => true,
_ => false,
},
PathSource::Trait(AliasPossibility::Maybe) => match def {
Def::Trait(..) => true,
Def::TraitAlias(..) => true,
_ => false,
},
PathSource::Expr(..) => match def {
Def::Ctor(_, _, CtorKind::Const) | Def::Ctor(_, _, CtorKind::Fn) |
Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) |
Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) |
Def::SelfCtor(..) | Def::ConstParam(..) => true,
_ => false,
},
PathSource::Pat => match def {
Def::Ctor(_, _, CtorKind::Const) |
Def::Const(..) | Def::AssociatedConst(..) |
Def::SelfCtor(..) => true,
_ => false,
},
PathSource::TupleStruct => match def {
Def::Ctor(_, _, CtorKind::Fn) | Def::SelfCtor(..) => true,
_ => false,
},
PathSource::Struct => match def {
Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
_ => false,
},
PathSource::TraitItem(ns) => match def {
Def::AssociatedConst(..) | Def::Method(..) if ns == ValueNS => true,
Def::AssociatedTy(..) if ns == TypeNS => true,
_ => false,
},
PathSource::Visibility => match def {
Def::Mod(..) => true,
_ => false,
},
}
}
fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
__diagnostic_used!(E0404);
__diagnostic_used!(E0405);
__diagnostic_used!(E0412);
__diagnostic_used!(E0422);
__diagnostic_used!(E0423);
__diagnostic_used!(E0425);
__diagnostic_used!(E0531);
__diagnostic_used!(E0532);
__diagnostic_used!(E0573);
__diagnostic_used!(E0574);
__diagnostic_used!(E0575);
__diagnostic_used!(E0576);
__diagnostic_used!(E0577);
__diagnostic_used!(E0578);
match (self, has_unexpected_resolution) {
(PathSource::Trait(_), true) => "E0404",
(PathSource::Trait(_), false) => "E0405",
(PathSource::Type, true) => "E0573",
(PathSource::Type, false) => "E0412",
(PathSource::Struct, true) => "E0574",
(PathSource::Struct, false) => "E0422",
(PathSource::Expr(..), true) => "E0423",
(PathSource::Expr(..), false) => "E0425",
(PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
(PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
(PathSource::TraitItem(..), true) => "E0575",
(PathSource::TraitItem(..), false) => "E0576",
(PathSource::Visibility, true) => "E0577",
(PathSource::Visibility, false) => "E0578",
}
}
}
// 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)]
pub struct Segment {
ident: Ident,
id: Option,
}
impl Segment {
fn from_path(path: &Path) -> Vec {
path.segments.iter().map(|s| s.into()).collect()
}
fn from_ident(ident: Ident) -> Segment {
Segment {
ident,
id: None,
}
}
fn names_to_string(segments: &[Segment]) -> String {
names_to_string(&segments.iter()
.map(|seg| seg.ident)
.collect::>())
}
}
impl<'a> From<&'a ast::PathSegment> for Segment {
fn from(seg: &'a ast::PathSegment) -> Segment {
Segment {
ident: seg.ident,
id: Some(seg.id),
}
}
}
struct UsePlacementFinder {
target_module: NodeId,
span: Option,
found_use: bool,
}
impl UsePlacementFinder {
fn check(krate: &Crate, target_module: NodeId) -> (Option, bool) {
let mut finder = UsePlacementFinder {
target_module,
span: None,
found_use: false,
};
visit::walk_crate(&mut finder, krate);
(finder.span, finder.found_use)
}
}
impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
fn visit_mod(
&mut self,
module: &'tcx ast::Mod,
_: Span,
_: &[ast::Attribute],
node_id: NodeId,
) {
if self.span.is_some() {
return;
}
if node_id != self.target_module {
visit::walk_mod(self, module);
return;
}
// find a use statement
for item in &module.items {
match item.node {
ItemKind::Use(..) => {
// don't suggest placing a use before the prelude
// import or other generated ones
if item.span.ctxt().outer().expn_info().is_none() {
self.span = Some(item.span.shrink_to_lo());
self.found_use = true;
return;
}
},
// don't place use before extern crate
ItemKind::ExternCrate(_) => {}
// but place them before the first other item
_ => if self.span.map_or(true, |span| item.span < span ) {
if item.span.ctxt().outer().expn_info().is_none() {
// don't insert between attributes and an item
if item.attrs.is_empty() {
self.span = Some(item.span.shrink_to_lo());
} else {
// find the first attribute on the item
for attr in &item.attrs {
if self.span.map_or(true, |span| attr.span < span) {
self.span = Some(attr.span.shrink_to_lo());
}
}
}
}
},
}
}
}
}
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
fn visit_item(&mut self, item: &'tcx Item) {
self.resolve_item(item);
}
fn visit_arm(&mut self, arm: &'tcx Arm) {
self.resolve_arm(arm);
}
fn visit_block(&mut self, block: &'tcx Block) {
self.resolve_block(block);
}
fn visit_anon_const(&mut self, constant: &'tcx ast::AnonConst) {
debug!("visit_anon_const {:?}", constant);
self.with_constant_rib(|this| {
visit::walk_anon_const(this, constant);
});
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
self.resolve_expr(expr, None);
}
fn visit_local(&mut self, local: &'tcx Local) {
self.resolve_local(local);
}
fn visit_ty(&mut self, ty: &'tcx Ty) {
match ty.node {
TyKind::Path(ref qself, ref path) => {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
}
TyKind::ImplicitSelf => {
let self_ty = keywords::SelfUpper.ident();
let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
}
_ => (),
}
visit::walk_ty(self, ty);
}
fn visit_poly_trait_ref(&mut self,
tref: &'tcx ast::PolyTraitRef,
m: &'tcx ast::TraitBoundModifier) {
self.smart_resolve_path(tref.trait_ref.ref_id, None,
&tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
visit::walk_poly_trait_ref(self, tref, m);
}
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
let generic_params = match foreign_item.node {
ForeignItemKind::Fn(_, ref generics) => {
HasGenericParams(generics, ItemRibKind)
}
ForeignItemKind::Static(..) => NoGenericParams,
ForeignItemKind::Ty => NoGenericParams,
ForeignItemKind::Macro(..) => NoGenericParams,
};
self.with_generic_param_rib(generic_params, |this| {
visit::walk_foreign_item(this, foreign_item);
});
}
fn visit_fn(&mut self,
function_kind: FnKind<'tcx>,
declaration: &'tcx FnDecl,
_: Span,
node_id: NodeId)
{
debug!("(resolving function) entering function");
let (rib_kind, asyncness) = match function_kind {
FnKind::ItemFn(_, ref header, ..) =>
(FnItemRibKind, &header.asyncness.node),
FnKind::Method(_, ref sig, _, _) =>
(TraitOrImplItemRibKind, &sig.header.asyncness.node),
FnKind::Closure(_) =>
// Async closures aren't resolved through `visit_fn`-- they're
// processed separately
(ClosureRibKind(node_id), &IsAsync::NotAsync),
};
// Create a value rib for the function.
self.ribs[ValueNS].push(Rib::new(rib_kind));
// Create a label rib for the function.
self.label_ribs.push(Rib::new(rib_kind));
// Add each argument to the rib.
let mut bindings_list = FxHashMap::default();
let mut add_argument = |argument: &ast::Arg| {
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
self.visit_ty(&argument.ty);
debug!("(resolving function) recorded argument");
};
// Walk the generated async arguments if this is an `async fn`, otherwise walk the
// normal arguments.
if let IsAsync::Async { ref arguments, .. } = asyncness {
for a in arguments { add_argument(&a.arg); }
} else {
for a in &declaration.inputs { add_argument(a); }
}
visit::walk_fn_ret_ty(self, &declaration.output);
// Resolve the function body, potentially inside the body of an async closure
if let IsAsync::Async { closure_id, .. } = asyncness {
let rib_kind = ClosureRibKind(*closure_id);
self.ribs[ValueNS].push(Rib::new(rib_kind));
self.label_ribs.push(Rib::new(rib_kind));
}
match function_kind {
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => {
if let IsAsync::Async { ref arguments, .. } = asyncness {
let mut body = body.clone();
// Insert the generated statements into the body before attempting to
// resolve names.
for a in arguments {
body.stmts.insert(0, a.stmt.clone());
}
self.visit_block(&body);
} else {
self.visit_block(body);
}
}
FnKind::Closure(body) => {
self.visit_expr(body);
}
};
// Leave the body of the async closure
if asyncness.is_async() {
self.label_ribs.pop();
self.ribs[ValueNS].pop();
}
debug!("(resolving function) leaving function");
self.label_ribs.pop();
self.ribs[ValueNS].pop();
}
fn visit_generics(&mut self, generics: &'tcx Generics) {
// For type parameter defaults, we have to ban access
// to following type parameters, as the InternalSubsts can only
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
let mut found_default = false;
default_ban_rib.bindings.extend(generics.params.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Const { .. } |
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { ref default, .. } => {
found_default |= default.is_some();
if found_default {
Some((Ident::with_empty_ctxt(param.ident.name), Def::Err))
} else {
None
}
}
}));
// We also ban access to type parameters for use as the types of const parameters.
let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
const_ty_param_ban_rib.bindings.extend(generics.params.iter()
.filter(|param| {
if let GenericParamKind::Type { .. } = param.kind {
true
} else {
false
}
})
.map(|param| (Ident::with_empty_ctxt(param.ident.name), Def::Err)));
for param in &generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
GenericParamKind::Type { ref default, .. } => {
for bound in ¶m.bounds {
self.visit_param_bound(bound);
}
if let Some(ref ty) = default {
self.ribs[TypeNS].push(default_ban_rib);
self.visit_ty(ty);
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
}
GenericParamKind::Const { ref ty } => {
self.ribs[TypeNS].push(const_ty_param_ban_rib);
for bound in ¶m.bounds {
self.visit_param_bound(bound);
}
self.visit_ty(ty);
const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
}
}
for p in &generics.where_clause.predicates {
self.visit_where_predicate(p);
}
}
}
#[derive(Copy, Clone)]
enum GenericParameters<'a, 'b> {
NoGenericParams,
HasGenericParams(// Type parameters.
&'b Generics,
// The kind of the rib used for type parameters.
RibKind<'a>),
}
/// The rib kind controls the translation of local
/// definitions (`Def::Local`) to upvars (`Def::Upvar`).
#[derive(Copy, Clone, Debug)]
enum RibKind<'a> {
/// No translation needs to be applied.
NormalRibKind,
/// We passed through a closure scope at the given `NodeId`.
/// Translate upvars as appropriate.
ClosureRibKind(NodeId /* func id */),
/// We passed through an impl or trait and are now in one of its
/// methods or associated types. Allow references to ty params that impl or trait
/// binds. Disallow any other upvars (including other ty params that are
/// upvars).
TraitOrImplItemRibKind,
/// We passed through a function definition. Disallow upvars.
/// Permit only those const parameters that are specified in the function's generics.
FnItemRibKind,
/// We passed through an item scope. Disallow upvars.
ItemRibKind,
/// We're in a constant item. Can't refer to dynamic stuff.
ConstantItemRibKind,
/// We passed through a module.
ModuleRibKind(Module<'a>),
/// We passed through a `macro_rules!` statement
MacroDefinition(DefId),
/// All bindings in this rib are type parameters that can't be used
/// from the default of a type parameter because they're not declared
/// before said type parameter. Also see the `visit_generics` override.
ForwardTyParamBanRibKind,
/// We forbid the use of type parameters as the types of const parameters.
TyParamAsConstParamTy,
}
/// A single local scope.
///
/// A rib represents a scope names can live in. Note that these appear in many places, not just
/// around braces. At any place where the list of accessible names (of the given namespace)
/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a
/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
/// etc.
///
/// Different [rib kinds](enum.RibKind) are transparent for different names.
///
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
/// resolving, the name is looked up from inside out.
#[derive(Debug)]
struct Rib<'a> {
bindings: FxHashMap,
kind: RibKind<'a>,
}
impl<'a> Rib<'a> {
fn new(kind: RibKind<'a>) -> Rib<'a> {
Rib {
bindings: Default::default(),
kind,
}
}
}
/// An intermediate resolution result.
///
/// This refers to the thing referred by a name. The difference between `Def` and `Item` is that
/// items are visible in their whole block, while defs only from the place they are defined
/// forward.
enum LexicalScopeBinding<'a> {
Item(&'a NameBinding<'a>),
Def(Def),
}
impl<'a> LexicalScopeBinding<'a> {
fn item(self) -> Option<&'a NameBinding<'a>> {
match self {
LexicalScopeBinding::Item(binding) => Some(binding),
_ => None,
}
}
fn def(self) -> Def {
match self {
LexicalScopeBinding::Item(binding) => binding.def(),
LexicalScopeBinding::Def(def) => def,
}
}
}
#[derive(Copy, Clone, Debug)]
enum ModuleOrUniformRoot<'a> {
/// Regular module.
Module(Module<'a>),
/// Virtual module that denotes resolution in crate root with fallback to extern prelude.
CrateRootAndExternPrelude,
/// 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,
}
impl ModuleOrUniformRoot<'_> {
fn same_def(lhs: Self, rhs: Self) -> bool {
match (lhs, rhs) {
(ModuleOrUniformRoot::Module(lhs),
ModuleOrUniformRoot::Module(rhs)) => lhs.def() == rhs.def(),
(ModuleOrUniformRoot::CrateRootAndExternPrelude,
ModuleOrUniformRoot::CrateRootAndExternPrelude) |
(ModuleOrUniformRoot::ExternPrelude, ModuleOrUniformRoot::ExternPrelude) |
(ModuleOrUniformRoot::CurrentScope, ModuleOrUniformRoot::CurrentScope) => true,
_ => false,
}
}
}
#[derive(Clone, Debug)]
enum PathResult<'a> {
Module(ModuleOrUniformRoot<'a>),
NonModule(PathResolution),
Indeterminate,
Failed {
span: Span,
label: String,
suggestion: Option,
is_error_from_last_segment: bool,
},
}
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(NodeId),
/// Any module with a name.
///
/// This could be:
///
/// * A normal module ‒ either `mod from_file;` or `mod from_block { }`.
/// * A trait or an enum (it implicitly contains associated types, methods and variant
/// constructors).
Def(Def, Name),
}
impl ModuleKind {
/// Get name of the module.
pub fn name(&self) -> Option {
match self {
ModuleKind::Block(..) => None,
ModuleKind::Def(_, name) => Some(*name),
}
}
}
/// One node in the tree of modules.
pub struct ModuleData<'a> {
parent: Option>,
kind: ModuleKind,
// The def id of the closest normal module (`mod`) ancestor (including this module).
normal_ancestor_id: DefId,
resolutions: RefCell>>>,
single_segment_macro_resolutions: RefCell,
Option<&'a NameBinding<'a>>)>>,
multi_segment_macro_resolutions: RefCell, Span, MacroKind, ParentScope<'a>,
Option)>>,
builtin_attrs: RefCell)>>,
// Macro invocations that can expand into items in this module.
unresolved_invocations: RefCell>,
no_implicit_prelude: bool,
glob_importers: RefCell>>,
globs: RefCell>>,
// Used to memoize the traits in this module for faster searches through all traits in scope.
traits: RefCell