Skip to content

Commit 30a0ac6

Browse files
committed
delay introducing pattern bindings into scope
This splits introduction of bindings into scope (`apply_pattern_bindings`) apart from manipulation of the pattern's binding map (`fresh_binding`). By delaying the latter, we can keep bindings from appearing in-scope in guards. Since `fresh_binding` is now specifically for manipulating a pattern's bindings map, this commit also inlines a use of `fresh_binding` that was only adding to the innermost rib.
1 parent 3007433 commit 30a0ac6

File tree

1 file changed

+52
-30
lines changed

1 file changed

+52
-30
lines changed

compiler/rustc_resolve/src/late.rs

+52-30
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ enum PatBoundCtx {
120120
/// - The guard expression of a guard pattern may use bindings from within the guard pattern, but
121121
/// not from elsewhere in the pattern containing it. This allows us to isolate the bindings in the
122122
/// subpattern to construct the scope for the guard.
123-
type PatternBindings = SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>;
123+
///
124+
/// Each identifier must map to at most one distinct [`Res`].
125+
type PatternBindings = SmallVec<[(PatBoundCtx, FxIndexMap<Ident, Res>); 1]>;
124126

125127
/// Does this the item (from the item rib scope) allow generic parameters?
126128
#[derive(Copy, Clone, Debug)]
@@ -2308,7 +2310,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
23082310
fn resolve_fn_params(
23092311
&mut self,
23102312
has_self: bool,
2311-
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
2313+
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
23122314
) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
23132315
enum Elision {
23142316
/// We have not found any candidate.
@@ -2330,15 +2332,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
23302332
let mut parameter_info = Vec::new();
23312333
let mut all_candidates = Vec::new();
23322334

2335+
// Resolve and apply bindings first so diagnostics can see if they're used in types.
23332336
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
2334-
for (index, (pat, ty)) in inputs.enumerate() {
2335-
debug!(?pat, ?ty);
2337+
for (pat, _) in inputs.clone() {
2338+
debug!("resolving bindings in pat = {pat:?}");
23362339
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
23372340
if let Some(pat) = pat {
23382341
this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
23392342
}
23402343
});
2344+
}
2345+
self.apply_pattern_bindings(bindings);
23412346

2347+
for (index, (pat, ty)) in inputs.enumerate() {
2348+
debug!("resolving type for pat = {pat:?}, ty = {ty:?}");
23422349
// Record elision candidates only for this parameter.
23432350
debug_assert_matches!(self.lifetime_elision_candidates, None);
23442351
self.lifetime_elision_candidates = Some(Default::default());
@@ -3626,16 +3633,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
36263633
self.visit_path(&delegation.path, delegation.id);
36273634
let Some(body) = &delegation.body else { return };
36283635
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
3629-
// `PatBoundCtx` is not necessary in this context
3630-
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
3631-
36323636
let span = delegation.path.segments.last().unwrap().ident.span;
3633-
this.fresh_binding(
3634-
Ident::new(kw::SelfLower, span),
3635-
delegation.id,
3636-
PatternSource::FnParam,
3637-
&mut bindings,
3638-
);
3637+
let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules());
3638+
let res = Res::Local(delegation.id);
3639+
this.innermost_rib_bindings(ValueNS).insert(ident, res);
36393640
this.visit_block(body);
36403641
});
36413642
}
@@ -3646,6 +3647,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
36463647
for Param { pat, .. } in params {
36473648
this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
36483649
}
3650+
this.apply_pattern_bindings(bindings);
36493651
});
36503652
for Param { ty, .. } in params {
36513653
self.visit_ty(ty);
@@ -3862,8 +3864,27 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
38623864
fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) {
38633865
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
38643866
self.resolve_pattern(pat, pat_src, &mut bindings);
3867+
self.apply_pattern_bindings(bindings);
38653868
}
38663869

3870+
/// Apply the bindings from a pattern to the innermost rib of the current scope.
3871+
fn apply_pattern_bindings(&mut self, mut pat_bindings: PatternBindings) {
3872+
let rib_bindings = self.innermost_rib_bindings(ValueNS);
3873+
let Some((_, pat_bindings)) = pat_bindings.pop() else {
3874+
bug!("tried applying nonexistent bindings from pattern");
3875+
};
3876+
3877+
if rib_bindings.is_empty() {
3878+
// Often, such as for match arms, the bindings are introduced into a new rib.
3879+
// In this case, we can move the bindings over directly.
3880+
*rib_bindings = pat_bindings;
3881+
} else {
3882+
rib_bindings.extend(pat_bindings);
3883+
}
3884+
}
3885+
3886+
/// Resolve bindings in a pattern. `apply_pattern_bindings` must be called after to introduce
3887+
/// the bindings into scope.
38673888
fn resolve_pattern(
38683889
&mut self,
38693890
pat: &'ast Pat,
@@ -4001,18 +4022,15 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
40014022
pat_src: PatternSource,
40024023
bindings: &mut PatternBindings,
40034024
) -> Res {
4004-
// Add the binding to the local ribs, if it doesn't already exist in the bindings map.
4025+
// Add the binding to the bindings map, if it doesn't already exist.
40054026
// (We must not add it if it's in the bindings map because that breaks the assumptions
40064027
// later passes make about or-patterns.)
40074028
let ident = ident.normalize_to_macro_rules();
40084029

4009-
let mut bound_iter = bindings.iter().filter(|(_, set)| set.contains(&ident));
40104030
// Already bound in a product pattern? e.g. `(a, a)` which is not allowed.
4011-
let already_bound_and = bound_iter.clone().any(|(ctx, _)| *ctx == PatBoundCtx::Product);
4012-
// Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
4013-
// This is *required* for consistency which is checked later.
4014-
let already_bound_or = bound_iter.any(|(ctx, _)| *ctx == PatBoundCtx::Or);
4015-
4031+
let already_bound_and = bindings
4032+
.iter()
4033+
.any(|(ctx, map)| *ctx == PatBoundCtx::Product && map.contains_key(&ident));
40164034
if already_bound_and {
40174035
// Overlap in a product pattern somewhere; report an error.
40184036
use ResolutionError::*;
@@ -4025,19 +4043,23 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
40254043
self.report_error(ident.span, error(ident));
40264044
}
40274045

4028-
// Record as bound.
4029-
bindings.last_mut().unwrap().1.insert(ident);
4030-
4031-
if already_bound_or {
4046+
// Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
4047+
// This is *required* for consistency which is checked later.
4048+
let already_bound_or = bindings
4049+
.iter()
4050+
.find_map(|(ctx, map)| if *ctx == PatBoundCtx::Or { map.get(&ident) } else { None });
4051+
let res = if let Some(&res) = already_bound_or {
40324052
// `Variant1(a) | Variant2(a)`, ok
40334053
// Reuse definition from the first `a`.
4034-
self.innermost_rib_bindings(ValueNS)[&ident]
4035-
} else {
4036-
// A completely fresh binding is added to the set.
4037-
let res = Res::Local(pat_id);
4038-
self.innermost_rib_bindings(ValueNS).insert(ident, res);
40394054
res
4040-
}
4055+
} else {
4056+
// A completely fresh binding is added to the map.
4057+
Res::Local(pat_id)
4058+
};
4059+
4060+
// Record as bound.
4061+
bindings.last_mut().unwrap().1.insert(ident, res);
4062+
res
40414063
}
40424064

40434065
fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxIndexMap<Ident, Res> {

0 commit comments

Comments
 (0)