+//! "Late resolution" is the pass that resolves most of names in a crate beside imports and macros.
+//! It runs when the crate is fully expanded and its module structure is fully built.
+//! So it just walks through the crate and resolves all the expressions, types, etc.
+//!
+//! If you wonder why there's no `early.rs`, that's because it's split into three files -
+//! `build_reduced_graph.rs`, `macros.rs` and `resolve_imports.rs`.
+
use GenericParameters::*;
+use RibKind::*;
-use crate::{path_names_to_string, resolve_error};
-use crate::{AliasPossibility, BindingError, CrateLint, LexicalScopeBinding, Module};
-use crate::{ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
-use crate::{PathSource, ResolutionError, Resolver, Rib, RibKind, Segment, UseError};
-use crate::RibKind::*;
+use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
+use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
+use crate::{ResolutionError, Resolver, Segment, UseError};
use log::debug;
use rustc::{bug, lint, span_bug};
use std::collections::BTreeSet;
use std::mem::replace;
-use std::ops::{Deref, DerefMut};
mod diagnostics;
}
}
+/// The rib kind restricts certain accesses,
+/// e.g. to a `Res::Local` of an outer item.
+#[derive(Copy, Clone, Debug)]
+crate enum RibKind<'a> {
+ /// No restriction needs to be applied.
+ NormalRibKind,
+
+ /// 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).
+ AssocItemRibKind,
+
+ /// 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)]
+crate struct Rib<'a, R = Res> {
+ pub bindings: FxHashMap<Ident, R>,
+ pub kind: RibKind<'a>,
+}
+
+impl<'a, R> Rib<'a, R> {
+ fn new(kind: RibKind<'a>) -> Rib<'a, R> {
+ Rib {
+ bindings: Default::default(),
+ kind,
+ }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+crate enum AliasPossibility {
+ No,
+ Maybe,
+}
+
+#[derive(Copy, Clone, Debug)]
+crate 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 `<T as m::A>::B::C`.
+ TraitItem(Namespace),
+}
+
+impl<'a> PathSource<'a> {
+ fn namespace(self) -> Namespace {
+ match self {
+ PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
+ PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
+ PathSource::TraitItem(ns) => ns,
+ }
+ }
+
+ fn defer_to_typeck(self) -> bool {
+ match self {
+ PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+ PathSource::Struct | PathSource::TupleStruct => true,
+ PathSource::Trait(_) | PathSource::TraitItem(..) => 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::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 `DefKind::Fn`,
+ // this is not precise but usually more helpful than just "value".
+ Some(&ExprKind::Call(..)) => "function",
+ _ => "value",
+ },
+ }
+ }
+
+ crate fn is_expected(self, res: Res) -> bool {
+ match self {
+ PathSource::Type => match res {
+ Res::Def(DefKind::Struct, _)
+ | Res::Def(DefKind::Union, _)
+ | Res::Def(DefKind::Enum, _)
+ | Res::Def(DefKind::Trait, _)
+ | Res::Def(DefKind::TraitAlias, _)
+ | Res::Def(DefKind::TyAlias, _)
+ | Res::Def(DefKind::AssocTy, _)
+ | Res::PrimTy(..)
+ | Res::Def(DefKind::TyParam, _)
+ | Res::SelfTy(..)
+ | Res::Def(DefKind::OpaqueTy, _)
+ | Res::Def(DefKind::ForeignTy, _) => true,
+ _ => false,
+ },
+ PathSource::Trait(AliasPossibility::No) => match res {
+ Res::Def(DefKind::Trait, _) => true,
+ _ => false,
+ },
+ PathSource::Trait(AliasPossibility::Maybe) => match res {
+ Res::Def(DefKind::Trait, _) => true,
+ Res::Def(DefKind::TraitAlias, _) => true,
+ _ => false,
+ },
+ PathSource::Expr(..) => match res {
+ Res::Def(DefKind::Ctor(_, CtorKind::Const), _)
+ | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+ | Res::Def(DefKind::Const, _)
+ | Res::Def(DefKind::Static, _)
+ | Res::Local(..)
+ | Res::Def(DefKind::Fn, _)
+ | Res::Def(DefKind::Method, _)
+ | Res::Def(DefKind::AssocConst, _)
+ | Res::SelfCtor(..)
+ | Res::Def(DefKind::ConstParam, _) => true,
+ _ => false,
+ },
+ PathSource::Pat => match res {
+ Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
+ Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
+ Res::SelfCtor(..) => true,
+ _ => false,
+ },
+ PathSource::TupleStruct => match res {
+ Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
+ _ => false,
+ },
+ PathSource::Struct => match res {
+ Res::Def(DefKind::Struct, _)
+ | Res::Def(DefKind::Union, _)
+ | Res::Def(DefKind::Variant, _)
+ | Res::Def(DefKind::TyAlias, _)
+ | Res::Def(DefKind::AssocTy, _)
+ | Res::SelfTy(..) => true,
+ _ => false,
+ },
+ PathSource::TraitItem(ns) => match res {
+ Res::Def(DefKind::AssocConst, _)
+ | Res::Def(DefKind::Method, _) if ns == ValueNS => true,
+ Res::Def(DefKind::AssocTy, _) if ns == TypeNS => 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);
+ 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",
+ }
+ }
+}
+
struct LateResolutionVisitor<'a, 'b> {
- resolver: &'b mut Resolver<'a>,
+ r: &'b mut Resolver<'a>,
/// The module that represents the current item scope.
- current_module: Module<'a>,
+ parent_scope: ParentScope<'a>,
/// The current set of local scopes for types and values.
/// FIXME #4948: Reuse ribs to avoid allocation.
current_type_ascription: Vec<Span>,
}
-impl<'a> Deref for LateResolutionVisitor<'a, '_> {
- type Target = Resolver<'a>;
- fn deref(&self) -> &Self::Target {
- self.resolver
- }
-}
-
-impl<'a> DerefMut for LateResolutionVisitor<'a, '_> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.resolver
- }
-}
-
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
fn visit_item(&mut self, item: &'tcx Item) {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
}
TyKind::ImplicitSelf => {
- let self_ty = Ident::with_empty_ctxt(kw::SelfUpper);
+ let self_ty = Ident::with_dummy_span(kw::SelfUpper);
let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span)
.map_or(Res::Err, |d| d.res());
- self.record_partial_res(ty.id, PartialRes::new(res));
+ self.r.record_partial_res(ty.id, PartialRes::new(res));
}
_ => (),
}
GenericParamKind::Type { ref default, .. } => {
found_default |= default.is_some();
if found_default {
- Some((Ident::with_empty_ctxt(param.ident.name), Res::Err))
+ Some((Ident::with_dummy_span(param.ident.name), Res::Err))
} else {
None
}
false
}
})
- .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err)));
+ .map(|param| (Ident::with_dummy_span(param.ident.name), Res::Err)));
for param in &generics.params {
match param.kind {
}
// Allow all following defaults to refer to this type parameter.
- default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
+ default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
}
GenericParamKind::Const { ref ty } => {
self.ribs[TypeNS].push(const_ty_param_ban_rib);
impl<'a, 'b> LateResolutionVisitor<'a, '_> {
fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
+ // During late resolution we only track the module component of the parent scope,
+ // although it may be useful to track other components as well for diagnostics.
let graph_root = resolver.graph_root;
+ let parent_scope = ParentScope::module(graph_root);
LateResolutionVisitor {
- resolver,
- current_module: graph_root,
+ r: resolver,
+ parent_scope,
ribs: PerNS {
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
}
}
- fn parent_scope(&self) -> ParentScope<'a> {
- ParentScope { module: self.current_module, ..self.dummy_parent_scope() }
- }
-
fn resolve_ident_in_lexical_scope(&mut self,
ident: Ident,
ns: Namespace,
record_used_id: Option<NodeId>,
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
- self.resolver.resolve_ident_in_lexical_scope(
- ident, ns, &self.parent_scope(), record_used_id, path_span, &self.ribs[ns]
+ self.r.resolve_ident_in_lexical_scope(
+ ident, ns, &self.parent_scope, record_used_id, path_span, &self.ribs[ns]
)
}
path_span: Span,
crate_lint: CrateLint,
) -> PathResult<'a> {
- self.resolver.resolve_path_with_ribs(
- path, opt_ns, &self.parent_scope(), record_used, path_span, crate_lint, &self.ribs
+ self.r.resolve_path_with_ribs(
+ path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&self.ribs)
)
}
// We maintain a list of value ribs and type ribs.
//
// Simultaneously, we keep track of the current position in the module
- // graph in the `current_module` pointer. When we go to resolve a name in
+ // graph in the `parent_scope.module` pointer. When we go to resolve a name in
// the value or type namespaces, we first look through all the ribs and
// then query the module graph. When we resolve a name in the module
// namespace, we can skip all the ribs (since nested modules are not
fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T
where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T
{
- let id = self.definitions.local_def_id(id);
- let module = self.module_map.get(&id).cloned(); // clones a reference
+ let id = self.r.definitions.local_def_id(id);
+ let module = self.r.module_map.get(&id).cloned(); // clones a reference
if let Some(module) = module {
// Move down in the graph.
- let orig_module = replace(&mut self.current_module, module);
+ let orig_module = replace(&mut self.parent_scope.module, module);
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module)));
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module)));
- self.finalize_current_module_macro_resolutions(module);
let ret = f(self);
- self.current_module = orig_module;
+ self.parent_scope.module = orig_module;
self.ribs[ValueNS].pop();
self.ribs[TypeNS].pop();
ret
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
MacroDefinition(def) => {
- if def == self.macro_def(ident.span.ctxt()) {
+ if def == self.r.macro_def(ident.span.ctxt()) {
ident.span.remove_mark();
}
}
debug!("resolve_adt");
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
- let item_def_id = this.definitions.local_def_id(item.id);
+ let item_def_id = this.r.definitions.local_def_id(item.id);
this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
visit::walk_item(this, item);
});
};
let report_error = |this: &Self, ns| {
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
- this.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
+ this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
};
for &ns in nss {
}
Some(LexicalScopeBinding::Item(binding)) => {
let orig_blacklisted_binding =
- replace(&mut self.blacklisted_binding, Some(binding));
+ replace(&mut self.r.blacklisted_binding, Some(binding));
if let Some(LexicalScopeBinding::Res(..)) =
self.resolve_ident_in_lexical_scope(ident, ns, None,
use_tree.prefix.span) {
report_error(self, ns);
}
- self.blacklisted_binding = orig_blacklisted_binding;
+ self.r.blacklisted_binding = orig_blacklisted_binding;
}
None => {}
}
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
- let local_def_id = this.definitions.local_def_id(item.id);
+ let local_def_id = this.r.definitions.local_def_id(item.id);
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
ItemKind::TraitAlias(ref generics, ref bounds) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
- let local_def_id = this.definitions.local_def_id(item.id);
+ let local_def_id = this.r.definitions.local_def_id(item.id);
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
ident.name,
*span,
);
- resolve_error(self, param.ident.span, err);
+ self.r.report_error(param.ident.span, err);
}
seen_bindings.entry(ident).or_insert(param.ident.span);
// Plain insert (no renaming).
let res = Res::Def(
DefKind::TyParam,
- self.definitions.local_def_id(param.id),
+ self.r.definitions.local_def_id(param.id),
);
function_type_rib.bindings.insert(ident, res);
- self.record_partial_res(param.id, PartialRes::new(res));
+ self.r.record_partial_res(param.id, PartialRes::new(res));
}
GenericParamKind::Const { .. } => {
let ident = param.ident.modern();
ident.name,
*span,
);
- resolve_error(self, param.ident.span, err);
+ self.r.report_error(param.ident.span, err);
}
seen_bindings.entry(ident).or_insert(param.ident.span);
let res = Res::Def(
DefKind::ConstParam,
- self.definitions.local_def_id(param.id),
+ self.r.definitions.local_def_id(param.id),
);
function_value_rib.bindings.insert(ident, res);
- self.record_partial_res(param.id, PartialRes::new(res));
+ self.r.record_partial_res(param.id, PartialRes::new(res));
}
}
}
let mut self_type_rib = Rib::new(NormalRibKind);
// Plain insert (no renaming, since types are not currently hygienic)
- self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
+ self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res);
self.ribs[TypeNS].push(self_type_rib);
f(self);
self.ribs[TypeNS].pop();
{
let self_res = Res::SelfCtor(impl_id);
let mut self_type_rib = Rib::new(NormalRibKind);
- self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res);
+ self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res);
self.ribs[ValueNS].push(self_type_rib);
f(self);
self.ribs[ValueNS].pop();
this.with_self_rib(Res::SelfTy(None, None), |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
- let item_def_id = this.definitions.local_def_id(item_id);
+ let item_def_id = this.r.definitions.local_def_id(item_id);
this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
this.with_self_struct_ctor_rib(item_def_id, |this| {
debug!("resolve_implementation with_self_struct_ctor_rib");
for impl_item in impl_items {
- this.resolver.resolve_visibility(
- &impl_item.vis, &this.parent_scope()
- );
// We also need a new scope for the impl item type parameters.
let generic_params = HasGenericParams(&impl_item.generics,
AssocItemRibKind);
// If there is a TraitRef in scope for an impl, then the method must be in the
// trait.
if let Some((module, _)) = self.current_trait_ref {
- let parent_scope = &self.parent_scope();
- if self.resolve_ident_in_module(
+ if self.r.resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
ns,
- parent_scope,
+ &self.parent_scope,
false,
span,
).is_err() {
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
- resolve_error(self, span, err(ident.name, &path_names_to_string(path)));
+ self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
}
}
}
pat.walk(&mut |pat| {
if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
- if sub_pat.is_some() || match self.partial_res_map.get(&pat.id)
+ if sub_pat.is_some() || match self.r.partial_res_map.get(&pat.id)
.map(|res| res.base_res()) {
Some(Res::Local(..)) => true,
_ => false,
// Checks that all of the arms in an or-pattern have exactly the
// same set of bindings, with the same binding modes for each.
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
- if pats.is_empty() {
- return;
- }
-
let mut missing_vars = FxHashMap::default();
let mut inconsistent_vars = FxHashMap::default();
- for (i, p) in pats.iter().enumerate() {
- let map_i = self.binding_mode_map(&p);
-
- for (j, q) in pats.iter().enumerate() {
- if i == j {
- continue;
- }
- let map_j = self.binding_mode_map(&q);
- for (&key, &binding_i) in &map_i {
- if map_j.is_empty() { // Account for missing bindings when
- let binding_error = missing_vars // `map_j` has none.
- .entry(key.name)
- .or_insert(BindingError {
- name: key.name,
- origin: BTreeSet::new(),
- target: BTreeSet::new(),
- });
- binding_error.origin.insert(binding_i.span);
- binding_error.target.insert(q.span);
- }
- for (&key_j, &binding_j) in &map_j {
- match map_i.get(&key_j) {
- None => { // missing binding
- let binding_error = missing_vars
- .entry(key_j.name)
- .or_insert(BindingError {
- name: key_j.name,
- origin: BTreeSet::new(),
- target: BTreeSet::new(),
- });
- binding_error.origin.insert(binding_j.span);
- binding_error.target.insert(p.span);
- }
- Some(binding_i) => { // check consistent binding
- if binding_i.binding_mode != binding_j.binding_mode {
- inconsistent_vars
- .entry(key.name)
- .or_insert((binding_j.span, binding_i.span));
- }
+ for pat_outer in pats.iter() {
+ let map_outer = self.binding_mode_map(&pat_outer);
+
+ for pat_inner in pats.iter().filter(|pat| pat.id != pat_outer.id) {
+ let map_inner = self.binding_mode_map(&pat_inner);
+
+ for (&key_inner, &binding_inner) in map_inner.iter() {
+ match map_outer.get(&key_inner) {
+ None => { // missing binding
+ let binding_error = missing_vars
+ .entry(key_inner.name)
+ .or_insert(BindingError {
+ name: key_inner.name,
+ origin: BTreeSet::new(),
+ target: BTreeSet::new(),
+ could_be_path:
+ key_inner.name.as_str().starts_with(char::is_uppercase)
+ });
+ binding_error.origin.insert(binding_inner.span);
+ binding_error.target.insert(pat_outer.span);
+ }
+ Some(binding_outer) => { // check consistent binding
+ if binding_outer.binding_mode != binding_inner.binding_mode {
+ inconsistent_vars
+ .entry(key_inner.name)
+ .or_insert((binding_inner.span, binding_outer.span));
}
}
}
}
}
}
- let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
+
+ let mut missing_vars = missing_vars.iter_mut().collect::<Vec<_>>();
missing_vars.sort();
- for (_, v) in missing_vars {
- resolve_error(self,
- *v.origin.iter().next().unwrap(),
- ResolutionError::VariableNotBoundInPattern(v));
+ for (name, mut v) in missing_vars {
+ if inconsistent_vars.contains_key(name) {
+ v.could_be_path = false;
+ }
+ self.r.report_error(
+ *v.origin.iter().next().unwrap(),
+ ResolutionError::VariableNotBoundInPattern(v));
}
+
let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
inconsistent_vars.sort();
for (name, v) in inconsistent_vars {
- resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
+ self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
}
}
self.resolve_pattern(pat, source, &mut bindings_list);
}
// This has to happen *after* we determine which pat_idents are variants
- self.check_consistent_bindings(pats);
+ if pats.len() > 1 {
+ self.check_consistent_bindings(pats);
+ }
}
fn resolve_block(&mut self, block: &Block) {
debug!("(resolving block) entering block");
// Move down in the graph, if there's an anonymous module rooted here.
- let orig_module = self.current_module;
- let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
+ let orig_module = self.parent_scope.module;
+ let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference
let mut num_macro_definition_ribs = 0;
if let Some(anonymous_module) = anonymous_module {
debug!("(resolving block) found anonymous module, moving down");
self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
- self.current_module = anonymous_module;
- self.finalize_current_module_macro_resolutions(anonymous_module);
+ self.parent_scope.module = anonymous_module;
} else {
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
}
if let StmtKind::Item(ref item) = stmt.node {
if let ItemKind::MacroDef(..) = item.node {
num_macro_definition_ribs += 1;
- let res = self.definitions.local_def_id(item.id);
+ let res = self.r.definitions.local_def_id(item.id);
self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
self.label_ribs.push(Rib::new(MacroDefinition(res)));
}
}
// Move back up.
- self.current_module = orig_module;
+ self.parent_scope.module = orig_module;
for _ in 0 .. num_macro_definition_ribs {
self.ribs[ValueNS].pop();
self.label_ribs.pop();
match bindings.get(&ident).cloned() {
Some(id) if id == outer_pat_id => {
// `Variant(a, a)`, error
- resolve_error(
- self,
+ self.r.report_error(
ident.span,
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
&ident.as_str())
}
Some(..) if pat_src == PatternSource::FnParam => {
// `fn f(a: u8, a: u8)`, error
- resolve_error(
- self,
+ self.r.report_error(
ident.span,
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
&ident.as_str())
Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant
// or constant pattern.
- self.record_use(ident, ValueNS, binding.unwrap(), false);
+ self.r.record_use(ident, ValueNS, binding.unwrap(), false);
Some(res)
}
Res::Def(DefKind::Ctor(..), _)
// to something unusable as a pattern (e.g., constructor function),
// but we still conservatively report an error, see
// issues/33118#issuecomment-233962221 for one reason why.
- resolve_error(
- self,
+ self.r.report_error(
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(), ident.name, binding.unwrap())
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
});
- self.record_partial_res(pat.id, PartialRes::new(res));
+ self.r.record_partial_res(pat.id, PartialRes::new(res));
}
PatKind::TupleStruct(ref path, ..) => {
let report_errors = |this: &mut Self, res: Option<Res>| {
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
- let def_id = this.current_module.normal_ancestor_id;
- let node_id = this.definitions.as_local_node_id(def_id).unwrap();
+ let def_id = this.parent_scope.module.normal_ancestor_id;
+ let node_id = this.r.definitions.as_local_node_id(def_id).unwrap();
let better = res.is_some();
- this.use_injections.push(UseError { err, candidates, node_id, better });
+ this.r.use_injections.push(UseError { err, candidates, node_id, better });
PartialRes::new(Res::Err)
};
let mut res = None;
if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() {
if let Some((ctor_res, ctor_vis))
- = self.struct_constructors.get(&def_id).cloned() {
+ = self.r.struct_constructors.get(&def_id).cloned() {
if is_expected(ctor_res) &&
- self.is_accessible_from(ctor_vis, self.current_module) {
+ self.r.is_accessible_from(ctor_vis, self.parent_scope.module) {
let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
- self.session.buffer_lint(lint, id, span,
+ self.r.session.buffer_lint(lint, id, span,
"private struct constructors are not usable through \
re-exports in outer modules",
);
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
let traits = self.get_traits_containing_item(item_name, ns);
- self.trait_map.insert(id, traits);
+ self.r.trait_map.insert(id, traits);
}
- let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
+ let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))];
std_path.extend(path);
- if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
+ if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
let cl = CrateLint::No;
let ns = Some(ns);
if let PathResult::Module(_) | PathResult::NonModule(_) =
let item_span = path.iter().last().map(|segment| segment.ident.span)
.unwrap_or(span);
debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
- let mut hm = self.session.confused_type_with_std_module.borrow_mut();
+ let mut hm = self.r.session.confused_type_with_std_module.borrow_mut();
hm.insert(item_span, span);
// In some places (E0223) we only have access to the full path
hm.insert(span, span);
if let PathSource::TraitItem(..) = source {} else {
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
- self.record_partial_res(id, partial_res);
+ self.r.record_partial_res(id, partial_res);
}
partial_res
}
fn self_type_is_available(&mut self, span: Span) -> bool {
let binding = self.resolve_ident_in_lexical_scope(
- Ident::with_empty_ctxt(kw::SelfUpper),
+ Ident::with_dummy_span(kw::SelfUpper),
TypeNS,
None,
span,
if qself.is_none() {
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
let path = Path { segments: path.iter().map(path_seg).collect(), span };
- let parent_scope = &self.parent_scope();
- if let Ok((_, res)) =
- self.resolve_macro_path(&path, None, parent_scope, false, false) {
+ if let Ok((_, res)) = self.r.resolve_macro_path(
+ &path, None, &self.parent_scope, false, false
+ ) {
return Some(PartialRes::new(res));
}
}
PathResult::Module(ModuleOrUniformRoot::Module(_)) |
PathResult::Failed { .. }
if (ns == TypeNS || path.len() > 1) &&
- self.primitive_type_table.primitive_types
+ self.r.primitive_type_table.primitive_types
.contains_key(&path[0].ident.name) => {
- let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
+ let prim = self.r.primitive_type_table.primitive_types[&path[0].ident.name];
PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
}
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
PartialRes::new(module.res().unwrap()),
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
- resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
+ self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
PartialRes::new(Res::Err)
}
PathResult::Module(..) | PathResult::Failed { .. } => return None,
};
if result.base_res() == unqualified_result {
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
- self.session.buffer_lint(lint, id, span, "unnecessary qualification")
+ self.r.session.buffer_lint(lint, id, span, "unnecessary qualification")
}
}
});
find_best_match_for_name(names, &*ident.as_str(), None)
});
- self.record_partial_res(expr.id, PartialRes::new(Res::Err));
- resolve_error(self,
- label.ident.span,
- ResolutionError::UndeclaredLabel(&label.ident.as_str(),
- close_match));
+ self.r.record_partial_res(expr.id, PartialRes::new(Res::Err));
+ self.r.report_error(
+ label.ident.span,
+ ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match),
+ );
}
Some(node_id) => {
// Since this res is a label, it is never read.
- self.label_res_map.insert(expr.id, node_id);
+ self.r.label_res_map.insert(expr.id, node_id);
self.unused_labels.remove(&node_id);
}
}
// the field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.get_traits_containing_item(ident, ValueNS);
- self.trait_map.insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
ExprKind::MethodCall(ref segment, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}",
expr.id);
let traits = self.get_traits_containing_item(segment.ident, ValueNS);
- self.trait_map.insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
_ => {
// Nothing to do.
let mut found_traits = Vec::new();
// Look for the current trait.
if let Some((module, _)) = self.current_trait_ref {
- let parent_scope = &self.parent_scope();
- if self.resolve_ident_in_module(
+ if self.r.resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
ns,
- parent_scope,
+ &self.parent_scope,
false,
module.span,
).is_ok() {
}
ident.span = ident.span.modern();
- let mut search_module = self.current_module;
+ let mut search_module = self.parent_scope.module;
loop {
self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
search_module = unwrap_or!(
- self.hygienic_lexical_parent(search_module, &mut ident.span), break
+ self.r.hygienic_lexical_parent(search_module, &mut ident.span), break
);
}
- if let Some(prelude) = self.prelude {
+ if let Some(prelude) = self.r.prelude {
if !search_module.no_implicit_prelude {
self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits);
}
let mut traits = module.traits.borrow_mut();
if traits.is_none() {
let mut collected_traits = Vec::new();
- module.for_each_child(|name, ns, binding| {
+ module.for_each_child(self.r, |_, name, ns, binding| {
if ns != TypeNS { return }
match binding.res() {
Res::Def(DefKind::Trait, _) |
).is_none() {
continue
}
- let parent_scope = &self.parent_scope();
- if self.resolve_ident_in_module_unadjusted(
+ if self.r.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
- parent_scope,
+ &self.parent_scope,
false,
module.span,
).is_ok() {
trait_name: Ident) -> SmallVec<[NodeId; 1]> {
let mut import_ids = smallvec![];
while let NameBindingKind::Import { directive, binding, .. } = kind {
- self.maybe_unused_trait_imports.insert(directive.id);
- self.add_to_glob_map(&directive, trait_name);
+ self.r.maybe_unused_trait_imports.insert(directive.id);
+ self.r.add_to_glob_map(&directive, trait_name);
import_ids.push(directive.id);
kind = &binding.kind;
};
impl<'a> Resolver<'a> {
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
- let module = late_resolution_visitor.current_module;
- late_resolution_visitor.finalize_current_module_macro_resolutions(module);
visit::walk_crate(&mut late_resolution_visitor, krate);
for (id, span) in late_resolution_visitor.unused_labels.iter() {
self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");