@@ -30,9 +30,9 @@ use crate::{
3030 db:: DefDatabase ,
3131 expander:: Expander ,
3232 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 ,
3636 } ,
3737 item_scope:: BuiltinShadowMode ,
3838 lang_item:: LangItem ,
@@ -141,6 +141,8 @@ impl RibKind {
141141#[ derive( Debug , Default ) ]
142142struct BindingList {
143143 map : FxHashMap < Name , BindingId > ,
144+ is_used : FxHashMap < BindingId , bool > ,
145+ reject_new : bool ,
144146}
145147
146148impl BindingList {
@@ -150,7 +152,27 @@ impl BindingList {
150152 name : Name ,
151153 mode : BindingAnnotation ,
152154 ) -> 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 ) ;
154176 }
155177}
156178
@@ -1208,9 +1230,34 @@ impl ExprCollector<'_> {
12081230 p. path ( ) . and_then ( |path| self . expander . parse_path ( self . db , path) ) . map ( Box :: new) ;
12091231 path. map ( Pat :: Path ) . unwrap_or ( Pat :: Missing )
12101232 }
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 ( ) )
12141261 }
12151262 ast:: Pat :: ParenPat ( p) => return self . collect_pat_opt ( p. pat ( ) , binding_list) ,
12161263 ast:: Pat :: TuplePat ( p) => {
@@ -1499,6 +1546,7 @@ impl ExprCollector<'_> {
14991546 mode,
15001547 definitions : SmallVec :: new ( ) ,
15011548 owner : self . current_binding_owner ,
1549+ problems : None ,
15021550 } )
15031551 }
15041552
0 commit comments