resolve: extract try_resolve_as_non_binding.

This commit is contained in:
Mazdak Farrokhzad 2019-08-28 10:10:10 +02:00
parent 6d537d4020
commit 219ddde26b
2 changed files with 69 additions and 57 deletions

View File

@ -9,7 +9,7 @@
use RibKind::*;
use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult};
use crate::{Module, ModuleOrUniformRoot, NameBindingKind, ParentScope, PathResult};
use crate::{ResolutionError, Resolver, Segment, UseError};
use log::debug;
@ -1327,78 +1327,37 @@ fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxHashMap<Ident, Res
&mut self.ribs[ns].last_mut().unwrap().bindings
}
fn resolve_pattern(&mut self,
pat: &Pat,
pat_src: PatternSource,
// Maps idents to the node ID for the
// outermost pattern that binds them.
bindings: &mut FxHashMap<Ident, NodeId>) {
fn resolve_pattern(
&mut self,
pat: &Pat,
pat_src: PatternSource,
// Maps idents to the node ID for the outermost pattern that binds them.
bindings: &mut FxHashMap<Ident, NodeId>,
) {
// Visit all direct subpatterns of this pattern.
let outer_pat_id = pat.id;
pat.walk(&mut |pat| {
debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node);
match pat.node {
PatKind::Ident(bmode, ident, ref opt_pat) => {
// First try to resolve the identifier as some existing
// entity, then fall back to a fresh binding.
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS,
None, pat.span)
.and_then(LexicalScopeBinding::item);
let res = binding.map(NameBinding::res).and_then(|res| {
let is_syntactic_ambiguity = opt_pat.is_none() &&
bmode == BindingMode::ByValue(Mutability::Immutable);
match res {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant
// or constant pattern.
self.r.record_use(ident, ValueNS, binding.unwrap(), false);
Some(res)
}
Res::Def(DefKind::Ctor(..), _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::Static, _) => {
// This is unambiguously a fresh binding, either syntactically
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
// 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.
self.r.report_error(
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(), ident.name, binding.unwrap())
);
None
}
Res::Def(DefKind::Fn, _) | Res::Err => {
// These entities are explicitly allowed
// to be shadowed by fresh bindings.
None
}
res => {
span_bug!(ident.span, "unexpected resolution for an \
identifier in pattern: {:?}", res);
}
}
}).unwrap_or_else(|| {
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
});
PatKind::Ident(bmode, ident, ref sub) => {
// First try to resolve the identifier as some existing entity,
// then fall back to a fresh binding.
let has_sub = sub.is_some();
let res = self.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
.unwrap_or_else(|| {
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
});
self.r.record_partial_res(pat.id, PartialRes::new(res));
}
PatKind::TupleStruct(ref path, ..) => {
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
}
PatKind::Path(ref qself, ref path) => {
self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
}
PatKind::Struct(ref path, ..) => {
self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
}
_ => {}
}
true
@ -1407,6 +1366,58 @@ fn resolve_pattern(&mut self,
visit::walk_pat(self, pat);
}
fn try_resolve_as_non_binding(
&mut self,
pat_src: PatternSource,
pat: &Pat,
bm: BindingMode,
ident: Ident,
has_sub: bool,
) -> Option<Res> {
let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?.item()?;
let res = binding.res();
// An immutable (no `mut`) by-value (no `ref`) binding pattern without
// a sub pattern (no `@ $pat`) is syntactically ambiguous as it could
// also be interpreted as a path to e.g. a constant, variant, etc.
let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Immutable);
match res {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant or constant pattern.
self.r.record_use(ident, ValueNS, binding, false);
Some(res)
}
Res::Def(DefKind::Ctor(..), _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::Static, _) => {
// This is unambiguously a fresh binding, either syntactically
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
// 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.
self.r.report_error(
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
pat_src.descr(),
ident.name,
binding,
),
);
None
}
Res::Def(DefKind::Fn, _) | Res::Err => {
// These entities are explicitly allowed to be shadowed by fresh bindings.
None
}
res => {
span_bug!(ident.span, "unexpected resolution for an \
identifier in pattern: {:?}", res);
}
}
}
// High-level and context dependent path resolution routine.
// Resolves the path and records the resolution into definition map.
// If resolution fails tries several techniques to find likely

View File

@ -9,6 +9,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(inner_deref)]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(mem_take)]