@@ -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