Auto merge of #90130 - Mark-Simulacrum:revert-namebinding, r=oli-obk
Revert "resolve: Use NameBinding for local variables and generic parameters"
This reverts commit 6162529a01
, that is, PR #89100.
Reverting per performance regression noted post-merge on that PR (https://github.com/rust-lang/rust/pull/89100#issuecomment-948065457).
This commit is contained in:
commit
547a6ffee0
3 changed files with 213 additions and 145 deletions
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use RibKind::*;
|
use RibKind::*;
|
||||||
|
|
||||||
use crate::{path_names_to_string, BindingError, CrateLint, NameBinding, ToNameBinding};
|
use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
|
||||||
use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult};
|
use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult};
|
||||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||||
|
|
||||||
|
@ -21,22 +21,27 @@ use rustc_hir::def::Namespace::{self, *};
|
||||||
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
|
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
|
||||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||||
use rustc_hir::{PrimTy, TraitCandidate};
|
use rustc_hir::{PrimTy, TraitCandidate};
|
||||||
use rustc_middle::{bug, span_bug, ty};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::source_map::{respan, Spanned};
|
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::Span;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
|
use rustc_span::source_map::{respan, Spanned};
|
||||||
use std::collections::{hash_map::Entry, BTreeSet};
|
use std::collections::{hash_map::Entry, BTreeSet};
|
||||||
use std::mem::{replace, take};
|
use std::mem::{replace, take};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
crate mod lifetimes;
|
crate mod lifetimes;
|
||||||
|
|
||||||
type Res = def::Res<NodeId>;
|
type Res = def::Res<NodeId>;
|
||||||
|
|
||||||
|
type IdentMap<T> = FxHashMap<Ident, T>;
|
||||||
|
|
||||||
|
/// Map from the name in a pattern to its binding mode.
|
||||||
|
type BindingMap = IdentMap<BindingInfo>;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct BindingInfo {
|
struct BindingInfo {
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -167,8 +172,8 @@ impl RibKind<'_> {
|
||||||
/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
|
/// 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.
|
/// resolving, the name is looked up from inside out.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
crate struct Rib<'a, R = &'a NameBinding<'a>> {
|
crate struct Rib<'a, R = Res> {
|
||||||
pub bindings: FxHashMap<Ident, R>,
|
pub bindings: IdentMap<R>,
|
||||||
pub kind: RibKind<'a>,
|
pub kind: RibKind<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,12 +567,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
GenericParamKind::Type { .. } => {
|
GenericParamKind::Type { .. } => {
|
||||||
forward_ty_ban_rib
|
forward_ty_ban_rib
|
||||||
.bindings
|
.bindings
|
||||||
.insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding);
|
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { .. } => {
|
GenericParamKind::Const { .. } => {
|
||||||
forward_const_ban_rib
|
forward_const_ban_rib
|
||||||
.bindings
|
.bindings
|
||||||
.insert(Ident::with_dummy_span(param.ident.name), self.r.dummy_binding);
|
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
|
||||||
}
|
}
|
||||||
GenericParamKind::Lifetime => {}
|
GenericParamKind::Lifetime => {}
|
||||||
}
|
}
|
||||||
|
@ -584,9 +589,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
// such as in the case of `trait Add<Rhs = Self>`.)
|
// such as in the case of `trait Add<Rhs = Self>`.)
|
||||||
if self.diagnostic_metadata.current_self_item.is_some() {
|
if self.diagnostic_metadata.current_self_item.is_some() {
|
||||||
// (`Some` if + only if we are in ADT's generics.)
|
// (`Some` if + only if we are in ADT's generics.)
|
||||||
forward_ty_ban_rib
|
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
|
||||||
.bindings
|
|
||||||
.insert(Ident::with_dummy_span(kw::SelfUpper), self.r.dummy_binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for param in &generics.params {
|
for param in &generics.params {
|
||||||
|
@ -734,9 +737,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
ns: Namespace,
|
ns: Namespace,
|
||||||
record_used_id: Option<NodeId>,
|
record_used_id: Option<NodeId>,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
) -> Option<&'a NameBinding<'a>> {
|
) -> Option<LexicalScopeBinding<'a>> {
|
||||||
self.r
|
self.r.resolve_ident_in_lexical_scope(
|
||||||
.resolve_ident_in_lexical_scope(
|
|
||||||
ident,
|
ident,
|
||||||
ns,
|
ns,
|
||||||
&self.parent_scope,
|
&self.parent_scope,
|
||||||
|
@ -744,7 +746,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
path_span,
|
path_span,
|
||||||
&self.ribs[ns],
|
&self.ribs[ns],
|
||||||
)
|
)
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_path(
|
fn resolve_path(
|
||||||
|
@ -902,10 +903,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn future_proof_import(&mut self, use_tree: &UseTree) {
|
fn future_proof_import(&mut self, use_tree: &UseTree) {
|
||||||
if !self.should_report_errs() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let segments = &use_tree.prefix.segments;
|
let segments = &use_tree.prefix.segments;
|
||||||
if !segments.is_empty() {
|
if !segments.is_empty() {
|
||||||
let ident = segments[0].ident;
|
let ident = segments[0].ident;
|
||||||
|
@ -917,42 +914,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
|
UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
|
||||||
_ => &[TypeNS],
|
_ => &[TypeNS],
|
||||||
};
|
};
|
||||||
|
|
||||||
let from_ribs = |binding: &NameBinding<'_>| {
|
|
||||||
matches!(
|
|
||||||
binding.res(),
|
|
||||||
Res::Local(..)
|
|
||||||
| Res::SelfTy(..)
|
|
||||||
| Res::Def(DefKind::TyParam | DefKind::ConstParam, ..)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let report_error = |this: &Self, ns| {
|
let report_error = |this: &Self, ns| {
|
||||||
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
||||||
let msg = format!("imports cannot refer to {what}");
|
if this.should_report_errs() {
|
||||||
this.r.session.span_err(ident.span, &msg);
|
this.r
|
||||||
|
.session
|
||||||
|
.span_err(ident.span, &format!("imports cannot refer to {}", what));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for &ns in nss {
|
for &ns in nss {
|
||||||
if let Some(binding) =
|
match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) {
|
||||||
self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span)
|
Some(LexicalScopeBinding::Res(..)) => {
|
||||||
{
|
|
||||||
if from_ribs(binding) {
|
|
||||||
report_error(self, ns);
|
|
||||||
} else {
|
|
||||||
let orig_unusable_binding =
|
|
||||||
replace(&mut self.r.unusable_binding, Some(binding));
|
|
||||||
if let Some(binding) = self.resolve_ident_in_lexical_scope(
|
|
||||||
ident,
|
|
||||||
ns,
|
|
||||||
None,
|
|
||||||
use_tree.prefix.span,
|
|
||||||
) {
|
|
||||||
if from_ribs(binding) {
|
|
||||||
report_error(self, ns);
|
report_error(self, ns);
|
||||||
}
|
}
|
||||||
|
Some(LexicalScopeBinding::Item(binding)) => {
|
||||||
|
let orig_unusable_binding =
|
||||||
|
replace(&mut self.r.unusable_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.r.unusable_binding = orig_unusable_binding;
|
self.r.unusable_binding = orig_unusable_binding;
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
|
} else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
|
||||||
|
@ -1149,12 +1135,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
|
let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
|
||||||
let binding =
|
|
||||||
(res, ty::Visibility::Invisible, param.ident.span, self.parent_scope.expansion)
|
|
||||||
.to_name_binding(self.r.arenas);
|
|
||||||
|
|
||||||
self.r.record_partial_res(param.id, PartialRes::new(res));
|
self.r.record_partial_res(param.id, PartialRes::new(res));
|
||||||
rib.bindings.insert(ident, binding);
|
rib.bindings.insert(ident, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ribs[ValueNS].push(function_value_rib);
|
self.ribs[ValueNS].push(function_value_rib);
|
||||||
|
@ -1274,12 +1256,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) {
|
fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) {
|
||||||
let binding = (self_res, ty::Visibility::Invisible, DUMMY_SP, self.parent_scope.expansion)
|
|
||||||
.to_name_binding(self.r.arenas);
|
|
||||||
let mut self_type_rib = Rib::new(NormalRibKind);
|
let mut self_type_rib = Rib::new(NormalRibKind);
|
||||||
|
|
||||||
// Plain insert (no renaming, since types are not currently hygienic)
|
// Plain insert (no renaming, since types are not currently hygienic)
|
||||||
self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), binding);
|
self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res);
|
||||||
self.ribs[ns].push(self_type_rib);
|
self.ribs[ns].push(self_type_rib);
|
||||||
f(self);
|
f(self);
|
||||||
self.ribs[ns].pop();
|
self.ribs[ns].pop();
|
||||||
|
@ -1490,7 +1470,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
/// this is done hygienically. This could arise for a macro
|
/// this is done hygienically. This could arise for a macro
|
||||||
/// that expands into an or-pattern where one 'x' was from the
|
/// that expands into an or-pattern where one 'x' was from the
|
||||||
/// user and one 'x' came from the macro.
|
/// user and one 'x' came from the macro.
|
||||||
fn binding_mode_map(&mut self, pat: &Pat) -> FxHashMap<Ident, BindingInfo> {
|
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
|
||||||
let mut binding_map = FxHashMap::default();
|
let mut binding_map = FxHashMap::default();
|
||||||
|
|
||||||
pat.walk(&mut |pat| {
|
pat.walk(&mut |pat| {
|
||||||
|
@ -1523,7 +1503,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
|
|
||||||
/// Checks that all of the arms in an or-pattern have exactly the
|
/// Checks that all of the arms in an or-pattern have exactly the
|
||||||
/// same set of bindings, with the same binding modes for each.
|
/// same set of bindings, with the same binding modes for each.
|
||||||
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<FxHashMap<Ident, BindingInfo>> {
|
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> {
|
||||||
let mut missing_vars = FxHashMap::default();
|
let mut missing_vars = FxHashMap::default();
|
||||||
let mut inconsistent_vars = FxHashMap::default();
|
let mut inconsistent_vars = FxHashMap::default();
|
||||||
|
|
||||||
|
@ -1665,6 +1645,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
|
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
|
||||||
.unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
|
.unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
|
||||||
self.r.record_partial_res(pat.id, PartialRes::new(res));
|
self.r.record_partial_res(pat.id, PartialRes::new(res));
|
||||||
|
self.r.record_pat_span(pat.id, pat.span);
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
|
PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
|
||||||
self.smart_resolve_path(
|
self.smart_resolve_path(
|
||||||
|
@ -1754,24 +1735,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
if already_bound_or {
|
if already_bound_or {
|
||||||
// `Variant1(a) | Variant2(a)`, ok
|
// `Variant1(a) | Variant2(a)`, ok
|
||||||
// Reuse definition from the first `a`.
|
// Reuse definition from the first `a`.
|
||||||
self.innermost_rib_bindings(ValueNS)[&ident].res()
|
self.innermost_rib_bindings(ValueNS)[&ident]
|
||||||
} else {
|
} else {
|
||||||
let res = Res::Local(pat_id);
|
let res = Res::Local(pat_id);
|
||||||
if ident_valid {
|
if ident_valid {
|
||||||
// A completely fresh binding add to the set if it's valid.
|
// A completely fresh binding add to the set if it's valid.
|
||||||
let binding =
|
self.innermost_rib_bindings(ValueNS).insert(ident, res);
|
||||||
(res, ty::Visibility::Invisible, ident.span, self.parent_scope.expansion)
|
|
||||||
.to_name_binding(self.r.arenas);
|
|
||||||
self.innermost_rib_bindings(ValueNS).insert(ident, binding);
|
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn innermost_rib_bindings(
|
fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap<Res> {
|
||||||
&mut self,
|
|
||||||
ns: Namespace,
|
|
||||||
) -> &mut FxHashMap<Ident, &'a NameBinding<'a>> {
|
|
||||||
&mut self.ribs[ns].last_mut().unwrap().bindings
|
&mut self.ribs[ns].last_mut().unwrap().bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1788,8 +1763,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// also be interpreted as a path to e.g. a constant, variant, etc.
|
// also be interpreted as a path to e.g. a constant, variant, etc.
|
||||||
let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
|
let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
|
||||||
|
|
||||||
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?;
|
let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?;
|
||||||
if is_syntactic_ambiguity && binding.is_ambiguity() {
|
let (res, binding) = match ls_binding {
|
||||||
|
LexicalScopeBinding::Item(binding)
|
||||||
|
if is_syntactic_ambiguity && binding.is_ambiguity() =>
|
||||||
|
{
|
||||||
// For ambiguous bindings we don't know all their definitions and cannot check
|
// For ambiguous bindings we don't know all their definitions and cannot check
|
||||||
// whether they can be shadowed by fresh bindings or not, so force an error.
|
// whether they can be shadowed by fresh bindings or not, so force an error.
|
||||||
// issues/33118#issuecomment-233962221 (see below) still applies here,
|
// issues/33118#issuecomment-233962221 (see below) still applies here,
|
||||||
|
@ -1797,8 +1775,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
self.r.record_use(ident, binding, false);
|
self.r.record_use(ident, binding, false);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
|
||||||
|
LexicalScopeBinding::Res(res) => (res, None),
|
||||||
|
};
|
||||||
|
|
||||||
let res = binding.res();
|
|
||||||
match res {
|
match res {
|
||||||
Res::SelfCtor(_) // See #70549.
|
Res::SelfCtor(_) // See #70549.
|
||||||
| Res::Def(
|
| Res::Def(
|
||||||
|
@ -1806,7 +1786,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
_,
|
_,
|
||||||
) if is_syntactic_ambiguity => {
|
) if is_syntactic_ambiguity => {
|
||||||
// Disambiguate in favor of a unit struct/variant or constant pattern.
|
// Disambiguate in favor of a unit struct/variant or constant pattern.
|
||||||
|
if let Some(binding) = binding {
|
||||||
self.r.record_use(ident, binding, false);
|
self.r.record_use(ident, binding, false);
|
||||||
|
}
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => {
|
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static, _) => {
|
||||||
|
@ -1815,6 +1797,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// to something unusable as a pattern (e.g., constructor function),
|
// to something unusable as a pattern (e.g., constructor function),
|
||||||
// but we still conservatively report an error, see
|
// but we still conservatively report an error, see
|
||||||
// issues/33118#issuecomment-233962221 for one reason why.
|
// issues/33118#issuecomment-233962221 for one reason why.
|
||||||
|
let binding = binding.expect("no binding for a ctor or static");
|
||||||
self.report_error(
|
self.report_error(
|
||||||
ident.span,
|
ident.span,
|
||||||
ResolutionError::BindingShadowsSomethingUnacceptable {
|
ResolutionError::BindingShadowsSomethingUnacceptable {
|
||||||
|
@ -2054,15 +2037,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_type_is_available(&mut self, span: Span) -> bool {
|
fn self_type_is_available(&mut self, span: Span) -> bool {
|
||||||
let ident = Ident::with_dummy_span(kw::SelfUpper);
|
let binding = self.resolve_ident_in_lexical_scope(
|
||||||
self.resolve_ident_in_lexical_scope(ident, TypeNS, None, span)
|
Ident::with_dummy_span(kw::SelfUpper),
|
||||||
.map_or(false, |binding| binding.res() != Res::Err)
|
TypeNS,
|
||||||
|
None,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
|
fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool {
|
||||||
let ident = Ident::new(kw::SelfLower, self_span);
|
let ident = Ident::new(kw::SelfLower, self_span);
|
||||||
self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span)
|
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span);
|
||||||
.map_or(false, |binding| binding.res() != Res::Err)
|
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around [`Resolver::report_error`].
|
/// A wrapper around [`Resolver::report_error`].
|
||||||
|
|
|
@ -1294,8 +1294,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
// Walk backwards up the ribs in scope and collect candidates.
|
// Walk backwards up the ribs in scope and collect candidates.
|
||||||
for rib in self.ribs[ns].iter().rev() {
|
for rib in self.ribs[ns].iter().rev() {
|
||||||
// Locals and type parameters
|
// Locals and type parameters
|
||||||
for (ident, binding) in &rib.bindings {
|
for (ident, &res) in &rib.bindings {
|
||||||
let res = binding.res();
|
|
||||||
if filter_fn(res) {
|
if filter_fn(res) {
|
||||||
names.push(TypoSuggestion::typo_from_res(ident.name, res));
|
names.push(TypoSuggestion::typo_from_res(ident.name, res));
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,6 +373,26 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An intermediate resolution result.
|
||||||
|
///
|
||||||
|
/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
|
||||||
|
/// items are visible in their whole block, while `Res`es only from the place they are defined
|
||||||
|
/// forward.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum LexicalScopeBinding<'a> {
|
||||||
|
Item(&'a NameBinding<'a>),
|
||||||
|
Res(Res),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LexicalScopeBinding<'a> {
|
||||||
|
fn res(self) -> Res {
|
||||||
|
match self {
|
||||||
|
LexicalScopeBinding::Item(binding) => binding.res(),
|
||||||
|
LexicalScopeBinding::Res(res) => res,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum ModuleOrUniformRoot<'a> {
|
enum ModuleOrUniformRoot<'a> {
|
||||||
/// Regular module.
|
/// Regular module.
|
||||||
|
@ -898,6 +918,10 @@ pub struct Resolver<'a> {
|
||||||
/// "self-confirming" import resolutions during import validation.
|
/// "self-confirming" import resolutions during import validation.
|
||||||
unusable_binding: Option<&'a NameBinding<'a>>,
|
unusable_binding: Option<&'a NameBinding<'a>>,
|
||||||
|
|
||||||
|
// Spans for local variables found during pattern resolution.
|
||||||
|
// Used for suggestions during error reporting.
|
||||||
|
pat_span_map: NodeMap<Span>,
|
||||||
|
|
||||||
/// Resolutions for nodes that have a single resolution.
|
/// Resolutions for nodes that have a single resolution.
|
||||||
partial_res_map: NodeMap<PartialRes>,
|
partial_res_map: NodeMap<PartialRes>,
|
||||||
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
|
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
|
||||||
|
@ -1308,6 +1332,7 @@ impl<'a> Resolver<'a> {
|
||||||
last_import_segment: false,
|
last_import_segment: false,
|
||||||
unusable_binding: None,
|
unusable_binding: None,
|
||||||
|
|
||||||
|
pat_span_map: Default::default(),
|
||||||
partial_res_map: Default::default(),
|
partial_res_map: Default::default(),
|
||||||
import_res_map: Default::default(),
|
import_res_map: Default::default(),
|
||||||
label_res_map: Default::default(),
|
label_res_map: Default::default(),
|
||||||
|
@ -1333,8 +1358,13 @@ impl<'a> Resolver<'a> {
|
||||||
macro_expanded_macro_export_errors: BTreeSet::new(),
|
macro_expanded_macro_export_errors: BTreeSet::new(),
|
||||||
|
|
||||||
arenas,
|
arenas,
|
||||||
dummy_binding: (Res::Err, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
|
dummy_binding: arenas.alloc_name_binding(NameBinding {
|
||||||
.to_name_binding(arenas),
|
kind: NameBindingKind::Res(Res::Err, false),
|
||||||
|
ambiguity: None,
|
||||||
|
expansion: LocalExpnId::ROOT,
|
||||||
|
span: DUMMY_SP,
|
||||||
|
vis: ty::Visibility::Public,
|
||||||
|
}),
|
||||||
|
|
||||||
crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
|
crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
|
||||||
macro_names: FxHashSet::default(),
|
macro_names: FxHashSet::default(),
|
||||||
|
@ -1891,11 +1921,11 @@ impl<'a> Resolver<'a> {
|
||||||
record_used_id: Option<NodeId>,
|
record_used_id: Option<NodeId>,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
ribs: &[Rib<'a>],
|
ribs: &[Rib<'a>],
|
||||||
) -> Result<&'a NameBinding<'a>, Determinacy> {
|
) -> Option<LexicalScopeBinding<'a>> {
|
||||||
assert!(ns == TypeNS || ns == ValueNS);
|
assert!(ns == TypeNS || ns == ValueNS);
|
||||||
let orig_ident = ident;
|
let orig_ident = ident;
|
||||||
if ident.name == kw::Empty {
|
if ident.name == kw::Empty {
|
||||||
return Ok(self.dummy_binding);
|
return Some(LexicalScopeBinding::Res(Res::Err));
|
||||||
}
|
}
|
||||||
let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
|
let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
|
||||||
// FIXME(jseyfried) improve `Self` hygiene
|
// FIXME(jseyfried) improve `Self` hygiene
|
||||||
|
@ -1918,30 +1948,18 @@ impl<'a> Resolver<'a> {
|
||||||
// Use the rib kind to determine whether we are resolving parameters
|
// Use the rib kind to determine whether we are resolving parameters
|
||||||
// (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
|
// (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
|
||||||
let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
|
let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
|
||||||
if let Some((&original_rib_ident_def, &binding)) =
|
if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
|
||||||
ribs[i].bindings.get_key_value(&rib_ident)
|
|
||||||
{
|
{
|
||||||
// The ident resolves to a type parameter or local variable.
|
// The ident resolves to a type parameter or local variable.
|
||||||
let res = self.validate_res_from_ribs(
|
return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
|
||||||
i,
|
i,
|
||||||
rib_ident,
|
rib_ident,
|
||||||
binding.res(),
|
*res,
|
||||||
record_used,
|
record_used,
|
||||||
path_span,
|
path_span,
|
||||||
original_rib_ident_def,
|
*original_rib_ident_def,
|
||||||
ribs,
|
ribs,
|
||||||
);
|
)));
|
||||||
|
|
||||||
// We have to create a new binding in case of validation errors,
|
|
||||||
// or in case of const generic hack changing the resolution.
|
|
||||||
return Ok(if res != binding.res() {
|
|
||||||
self.arenas.alloc_name_binding(NameBinding {
|
|
||||||
kind: NameBindingKind::Res(res, false),
|
|
||||||
..binding.clone()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
binding
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module = match ribs[i].kind {
|
module = match ribs[i].kind {
|
||||||
|
@ -1960,7 +1978,7 @@ impl<'a> Resolver<'a> {
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
|
|
||||||
let binding = self.resolve_ident_in_module_unadjusted(
|
let item = self.resolve_ident_in_module_unadjusted(
|
||||||
ModuleOrUniformRoot::Module(module),
|
ModuleOrUniformRoot::Module(module),
|
||||||
ident,
|
ident,
|
||||||
ns,
|
ns,
|
||||||
|
@ -1968,9 +1986,9 @@ impl<'a> Resolver<'a> {
|
||||||
record_used,
|
record_used,
|
||||||
path_span,
|
path_span,
|
||||||
);
|
);
|
||||||
if binding.is_ok() {
|
if let Ok(binding) = item {
|
||||||
// The ident resolves to an item.
|
// The ident resolves to an item.
|
||||||
return binding;
|
return Some(LexicalScopeBinding::Item(binding));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.early_resolve_ident_in_lexical_scope(
|
self.early_resolve_ident_in_lexical_scope(
|
||||||
|
@ -1981,6 +1999,8 @@ impl<'a> Resolver<'a> {
|
||||||
record_used,
|
record_used,
|
||||||
path_span,
|
path_span,
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
|
.map(LexicalScopeBinding::Item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hygienic_lexical_parent(
|
fn hygienic_lexical_parent(
|
||||||
|
@ -2205,6 +2225,16 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
|
for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
|
||||||
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
|
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
|
||||||
|
let record_segment_res = |this: &mut Self, res| {
|
||||||
|
if record_used {
|
||||||
|
if let Some(id) = id {
|
||||||
|
if !this.partial_res_map.contains_key(&id) {
|
||||||
|
assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
|
||||||
|
this.record_partial_res(id, PartialRes::new(res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let is_last = i == path.len() - 1;
|
let is_last = i == path.len() - 1;
|
||||||
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
||||||
|
@ -2283,8 +2313,12 @@ impl<'a> Resolver<'a> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FindBindingResult<'a> {
|
||||||
|
Binding(Result<&'a NameBinding<'a>, Determinacy>),
|
||||||
|
PathResult(PathResult<'a>),
|
||||||
|
}
|
||||||
let find_binding_in_ns = |this: &mut Self, ns| {
|
let find_binding_in_ns = |this: &mut Self, ns| {
|
||||||
if let Some(module) = module {
|
let binding = if let Some(module) = module {
|
||||||
this.resolve_ident_in_module(
|
this.resolve_ident_in_module(
|
||||||
module,
|
module,
|
||||||
ident,
|
ident,
|
||||||
|
@ -2309,34 +2343,44 @@ impl<'a> Resolver<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
this.resolve_ident_in_lexical_scope(
|
match this.resolve_ident_in_lexical_scope(
|
||||||
ident,
|
ident,
|
||||||
ns,
|
ns,
|
||||||
parent_scope,
|
parent_scope,
|
||||||
record_used_id,
|
record_used_id,
|
||||||
path_span,
|
path_span,
|
||||||
&ribs.unwrap()[ns],
|
&ribs.unwrap()[ns],
|
||||||
)
|
) {
|
||||||
|
// we found a locally-imported or available item/module
|
||||||
|
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
|
||||||
|
// we found a local variable or type param
|
||||||
|
Some(LexicalScopeBinding::Res(res))
|
||||||
|
if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) =>
|
||||||
|
{
|
||||||
|
record_segment_res(this, res);
|
||||||
|
return FindBindingResult::PathResult(PathResult::NonModule(
|
||||||
|
PartialRes::with_unresolved_segments(res, path.len() - 1),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => Err(Determinacy::determined(record_used)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
FindBindingResult::Binding(binding)
|
||||||
match find_binding_in_ns(self, ns) {
|
};
|
||||||
|
let binding = match find_binding_in_ns(self, ns) {
|
||||||
|
FindBindingResult::PathResult(x) => return x,
|
||||||
|
FindBindingResult::Binding(binding) => binding,
|
||||||
|
};
|
||||||
|
match binding {
|
||||||
Ok(binding) => {
|
Ok(binding) => {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
second_binding = Some(binding);
|
second_binding = Some(binding);
|
||||||
}
|
}
|
||||||
let res = binding.res();
|
let res = binding.res();
|
||||||
if record_used {
|
|
||||||
if let Some(id) = id {
|
|
||||||
if !self.partial_res_map.contains_key(&id) {
|
|
||||||
assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
|
|
||||||
self.record_partial_res(id, PartialRes::new(res));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
|
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
|
||||||
if let Some(next_module) = binding.module() {
|
if let Some(next_module) = binding.module() {
|
||||||
module = Some(ModuleOrUniformRoot::Module(next_module));
|
module = Some(ModuleOrUniformRoot::Module(next_module));
|
||||||
|
record_segment_res(self, res);
|
||||||
} else if res == Res::ToolMod && i + 1 != path.len() {
|
} else if res == Res::ToolMod && i + 1 != path.len() {
|
||||||
if binding.is_import() {
|
if binding.is_import() {
|
||||||
self.session
|
self.session
|
||||||
|
@ -2426,25 +2470,56 @@ impl<'a> Resolver<'a> {
|
||||||
.map_or(false, |c| c.is_ascii_uppercase())
|
.map_or(false, |c| c.is_ascii_uppercase())
|
||||||
{
|
{
|
||||||
// Check whether the name refers to an item in the value namespace.
|
// Check whether the name refers to an item in the value namespace.
|
||||||
let suggestion = ribs
|
let suggestion = if ribs.is_some() {
|
||||||
.and_then(|ribs| {
|
let match_span = match self.resolve_ident_in_lexical_scope(
|
||||||
self.resolve_ident_in_lexical_scope(
|
|
||||||
ident,
|
ident,
|
||||||
ValueNS,
|
ValueNS,
|
||||||
parent_scope,
|
parent_scope,
|
||||||
None,
|
None,
|
||||||
path_span,
|
path_span,
|
||||||
&ribs[ValueNS],
|
&ribs.unwrap()[ValueNS],
|
||||||
)
|
) {
|
||||||
.ok()
|
// Name matches a local variable. For example:
|
||||||
})
|
// ```
|
||||||
.map(|binding| {
|
// fn f() {
|
||||||
(
|
// let Foo: &str = "";
|
||||||
vec![(binding.span, String::from(""))],
|
// println!("{}", Foo::Bar); // Name refers to local
|
||||||
|
// // variable `Foo`.
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
Some(LexicalScopeBinding::Res(Res::Local(id))) => {
|
||||||
|
Some(*self.pat_span_map.get(&id).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name matches item from a local name binding
|
||||||
|
// created by `use` declaration. For example:
|
||||||
|
// ```
|
||||||
|
// pub Foo: &str = "";
|
||||||
|
//
|
||||||
|
// mod submod {
|
||||||
|
// use super::Foo;
|
||||||
|
// println!("{}", Foo::Bar); // Name refers to local
|
||||||
|
// // binding `Foo`.
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
Some(LexicalScopeBinding::Item(name_binding)) => {
|
||||||
|
Some(name_binding.span)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(span) = match_span {
|
||||||
|
Some((
|
||||||
|
vec![(span, String::from(""))],
|
||||||
format!("`{}` is defined here, but is not a type", ident),
|
format!("`{}` is defined here, but is not a type", ident),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
))
|
||||||
});
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
(format!("use of undeclared type `{}`", ident), suggestion)
|
(format!("use of undeclared type `{}`", ident), suggestion)
|
||||||
} else {
|
} else {
|
||||||
|
@ -2482,7 +2557,9 @@ impl<'a> Resolver<'a> {
|
||||||
let mut msg = format!("could not find `{}` in {}", ident, parent);
|
let mut msg = format!("could not find `{}` in {}", ident, parent);
|
||||||
if ns == TypeNS || ns == ValueNS {
|
if ns == TypeNS || ns == ValueNS {
|
||||||
let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
|
let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
|
||||||
if let Ok(binding) = find_binding_in_ns(self, ns_to_try) {
|
if let FindBindingResult::Binding(Ok(binding)) =
|
||||||
|
find_binding_in_ns(self, ns_to_try)
|
||||||
|
{
|
||||||
let mut found = |what| {
|
let mut found = |what| {
|
||||||
msg = format!(
|
msg = format!(
|
||||||
"expected {}, found {} `{}` in {}",
|
"expected {}, found {} `{}` in {}",
|
||||||
|
@ -2824,6 +2901,11 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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: ty::Visibility, module: Module<'a>) -> bool {
|
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
|
||||||
vis.is_accessible_from(module.nearest_parent_mod(), self)
|
vis.is_accessible_from(module.nearest_parent_mod(), self)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue