@@ -120,7 +120,9 @@ enum PatBoundCtx {
120
120
/// - The guard expression of a guard pattern may use bindings from within the guard pattern, but
121
121
/// not from elsewhere in the pattern containing it. This allows us to isolate the bindings in the
122
122
/// 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 ] > ;
124
126
125
127
/// Does this the item (from the item rib scope) allow generic parameters?
126
128
#[ derive( Copy , Clone , Debug ) ]
@@ -2308,7 +2310,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
2308
2310
fn resolve_fn_params (
2309
2311
& mut self ,
2310
2312
has_self : bool ,
2311
- inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
2313
+ inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > + Clone ,
2312
2314
) -> Result < LifetimeRes , ( Vec < MissingLifetime > , Vec < ElisionFnParameter > ) > {
2313
2315
enum Elision {
2314
2316
/// We have not found any candidate.
@@ -2330,15 +2332,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
2330
2332
let mut parameter_info = Vec :: new ( ) ;
2331
2333
let mut all_candidates = Vec :: new ( ) ;
2332
2334
2335
+ // Resolve and apply bindings first so diagnostics can see if they're used in types.
2333
2336
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:?}" ) ;
2336
2339
self . with_lifetime_rib ( LifetimeRibKind :: Elided ( LifetimeRes :: Infer ) , |this| {
2337
2340
if let Some ( pat) = pat {
2338
2341
this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
2339
2342
}
2340
2343
} ) ;
2344
+ }
2345
+ self . apply_pattern_bindings ( bindings) ;
2341
2346
2347
+ for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
2348
+ debug ! ( "resolving type for pat = {pat:?}, ty = {ty:?}" ) ;
2342
2349
// Record elision candidates only for this parameter.
2343
2350
debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
2344
2351
self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
@@ -3626,16 +3633,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
3626
3633
self . visit_path ( & delegation. path , delegation. id ) ;
3627
3634
let Some ( body) = & delegation. body else { return } ;
3628
3635
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
-
3632
3636
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) ;
3639
3640
this. visit_block ( body) ;
3640
3641
} ) ;
3641
3642
}
@@ -3646,6 +3647,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
3646
3647
for Param { pat, .. } in params {
3647
3648
this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
3648
3649
}
3650
+ this. apply_pattern_bindings ( bindings) ;
3649
3651
} ) ;
3650
3652
for Param { ty, .. } in params {
3651
3653
self . visit_ty ( ty) ;
@@ -3862,8 +3864,27 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
3862
3864
fn resolve_pattern_top ( & mut self , pat : & ' ast Pat , pat_src : PatternSource ) {
3863
3865
let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
3864
3866
self . resolve_pattern ( pat, pat_src, & mut bindings) ;
3867
+ self . apply_pattern_bindings ( bindings) ;
3865
3868
}
3866
3869
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.
3867
3888
fn resolve_pattern (
3868
3889
& mut self ,
3869
3890
pat : & ' ast Pat ,
@@ -4001,18 +4022,15 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
4001
4022
pat_src : PatternSource ,
4002
4023
bindings : & mut PatternBindings ,
4003
4024
) -> 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.
4005
4026
// (We must not add it if it's in the bindings map because that breaks the assumptions
4006
4027
// later passes make about or-patterns.)
4007
4028
let ident = ident. normalize_to_macro_rules ( ) ;
4008
4029
4009
- let mut bound_iter = bindings. iter ( ) . filter ( |( _, set) | set. contains ( & ident) ) ;
4010
4030
// 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) ) ;
4016
4034
if already_bound_and {
4017
4035
// Overlap in a product pattern somewhere; report an error.
4018
4036
use ResolutionError :: * ;
@@ -4025,19 +4043,23 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
4025
4043
self . report_error ( ident. span , error ( ident) ) ;
4026
4044
}
4027
4045
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 {
4032
4052
// `Variant1(a) | Variant2(a)`, ok
4033
4053
// 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) ;
4039
4054
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
4041
4063
}
4042
4064
4043
4065
fn innermost_rib_bindings ( & mut self , ns : Namespace ) -> & mut FxIndexMap < Ident , Res > {
0 commit comments