@@ -30,9 +30,9 @@ use crate::{
30
30
db:: DefDatabase ,
31
31
expander:: Expander ,
32
32
hir:: {
33
- dummy_expr_id, Array , Binding , BindingAnnotation , BindingId , CaptureBy , ClosureKind , Expr ,
34
- ExprId , Label , LabelId , Literal , LiteralOrConst , MatchArm , Movability , Pat , PatId ,
35
- RecordFieldPat , RecordLitField , Statement ,
33
+ dummy_expr_id, Array , Binding , BindingAnnotation , BindingId , BindingProblems , CaptureBy ,
34
+ ClosureKind , Expr , ExprId , Label , LabelId , Literal , LiteralOrConst , MatchArm , Movability ,
35
+ Pat , PatId , RecordFieldPat , RecordLitField , Statement ,
36
36
} ,
37
37
item_scope:: BuiltinShadowMode ,
38
38
lang_item:: LangItem ,
@@ -141,6 +141,8 @@ impl RibKind {
141
141
#[ derive( Debug , Default ) ]
142
142
struct BindingList {
143
143
map : FxHashMap < Name , BindingId > ,
144
+ is_used : FxHashMap < BindingId , bool > ,
145
+ reject_new : bool ,
144
146
}
145
147
146
148
impl BindingList {
@@ -150,7 +152,27 @@ impl BindingList {
150
152
name : Name ,
151
153
mode : BindingAnnotation ,
152
154
) -> BindingId {
153
- * self . map . entry ( name) . or_insert_with_key ( |n| ec. alloc_binding ( n. clone ( ) , mode) )
155
+ let id = * self . map . entry ( name) . or_insert_with_key ( |n| ec. alloc_binding ( n. clone ( ) , mode) ) ;
156
+ if ec. body . bindings [ id] . mode != mode {
157
+ ec. body . bindings [ id] . problems = Some ( BindingProblems :: BoundInconsistently ) ;
158
+ }
159
+ self . check_is_used ( ec, id) ;
160
+ id
161
+ }
162
+
163
+ fn check_is_used ( & mut self , ec : & mut ExprCollector < ' _ > , id : BindingId ) {
164
+ match self . is_used . get ( & id) {
165
+ None => {
166
+ if self . reject_new {
167
+ ec. body . bindings [ id] . problems = Some ( BindingProblems :: NotBoundAcrossAll ) ;
168
+ }
169
+ }
170
+ Some ( true ) => {
171
+ ec. body . bindings [ id] . problems = Some ( BindingProblems :: BoundMoreThanOnce ) ;
172
+ }
173
+ Some ( false ) => { }
174
+ }
175
+ self . is_used . insert ( id, true ) ;
154
176
}
155
177
}
156
178
@@ -1208,9 +1230,34 @@ impl ExprCollector<'_> {
1208
1230
p. path ( ) . and_then ( |path| self . expander . parse_path ( self . db , path) ) . map ( Box :: new) ;
1209
1231
path. map ( Pat :: Path ) . unwrap_or ( Pat :: Missing )
1210
1232
}
1211
- ast:: Pat :: OrPat ( p) => {
1212
- let pats = p. pats ( ) . map ( |p| self . collect_pat ( p, binding_list) ) . collect ( ) ;
1213
- Pat :: Or ( pats)
1233
+ ast:: Pat :: OrPat ( p) => ' b: {
1234
+ let prev_is_used = mem:: take ( & mut binding_list. is_used ) ;
1235
+ let prev_reject_new = mem:: take ( & mut binding_list. reject_new ) ;
1236
+ let mut pats = Vec :: with_capacity ( p. pats ( ) . count ( ) ) ;
1237
+ let mut it = p. pats ( ) ;
1238
+ let Some ( first) = it. next ( ) else {
1239
+ break ' b Pat :: Or ( Box :: new ( [ ] ) ) ;
1240
+ } ;
1241
+ pats. push ( self . collect_pat ( first, binding_list) ) ;
1242
+ binding_list. reject_new = true ;
1243
+ for rest in it {
1244
+ for ( _, x) in binding_list. is_used . iter_mut ( ) {
1245
+ * x = false ;
1246
+ }
1247
+ pats. push ( self . collect_pat ( rest, binding_list) ) ;
1248
+ for ( & id, & x) in binding_list. is_used . iter ( ) {
1249
+ if !x {
1250
+ self . body . bindings [ id] . problems =
1251
+ Some ( BindingProblems :: NotBoundAcrossAll ) ;
1252
+ }
1253
+ }
1254
+ }
1255
+ binding_list. reject_new = prev_reject_new;
1256
+ let current_is_used = mem:: replace ( & mut binding_list. is_used , prev_is_used) ;
1257
+ for ( id, _) in current_is_used. into_iter ( ) {
1258
+ binding_list. check_is_used ( self , id) ;
1259
+ }
1260
+ Pat :: Or ( pats. into ( ) )
1214
1261
}
1215
1262
ast:: Pat :: ParenPat ( p) => return self . collect_pat_opt ( p. pat ( ) , binding_list) ,
1216
1263
ast:: Pat :: TuplePat ( p) => {
@@ -1499,6 +1546,7 @@ impl ExprCollector<'_> {
1499
1546
mode,
1500
1547
definitions : SmallVec :: new ( ) ,
1501
1548
owner : self . current_binding_owner ,
1549
+ problems : None ,
1502
1550
} )
1503
1551
}
1504
1552
0 commit comments