+ fn fresh_binding(
+ &mut self,
+ ident: Ident,
+ pat_id: NodeId,
+ pat_src: PatternSource,
+ bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
+ ) -> Res {
+ // Add the binding to the local ribs, if it doesn't already exist in the bindings map.
+ // (We must not add it if it's in the bindings map because that breaks the assumptions
+ // later passes make about or-patterns.)
+ let ident = ident.modern_and_legacy();
+
+ // Walk outwards the stack of products / or-patterns and
+ // find out if the identifier has been bound in any of these.
+ let mut already_bound_and = false;
+ let mut already_bound_or = false;
+ for (is_sum, set) in bindings.iter_mut().rev() {
+ match (is_sum, set.get(&ident).cloned()) {
+ // Already bound in a product pattern, e.g. `(a, a)` which is not allowed.
+ (PatBoundCtx::Product, Some(..)) => already_bound_and = true,
+ // Already bound in an or-pattern, e.g. `V1(a) | V2(a)`.
+ // This is *required* for consistency which is checked later.
+ (PatBoundCtx::Or, Some(..)) => already_bound_or = true,
+ // Not already bound here.
+ _ => {}
+ }
+ }
+
+ if already_bound_and {
+ // Overlap in a product pattern somewhere; report an error.
+ use ResolutionError::*;
+ let error = match pat_src {
+ // `fn f(a: u8, a: u8)`:
+ PatternSource::FnParam => IdentifierBoundMoreThanOnceInParameterList,
+ // `Variant(a, a)`:
+ _ => IdentifierBoundMoreThanOnceInSamePattern,
+ };
+ self.r.report_error(ident.span, error(&ident.as_str()));
+ }
+
+ // Record as bound if it's valid:
+ let ident_valid = ident.name != kw::Invalid;
+ if ident_valid {
+ bindings.last_mut().unwrap().1.insert(ident);
+ }
+
+ if already_bound_or {
+ // `Variant1(a) | Variant2(a)`, ok
+ // Reuse definition from the first `a`.
+ self.innermost_rib_bindings(ValueNS)[&ident]
+ } else {
+ let res = Res::Local(pat_id);
+ if ident_valid {
+ // A completely fresh binding add to the set if it's valid.
+ self.innermost_rib_bindings(ValueNS).insert(ident, res);
+ }
+ res
+ }
+ }
+
+ fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap<Res> {
+ &mut self.ribs[ns].last_mut().unwrap().bindings
+ }
+
+ 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);
+ }
+ }