]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/body/lower.rs
feat: allow attributes on all expressions
[rust.git] / crates / hir_def / src / body / lower.rs
index da1fdac33aec5371dfb1d336cdb23278143fad7c..a34c18d6d0cbae115291677fd1cf942200a1743a 100644 (file)
@@ -27,9 +27,8 @@
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
     expr::{
-        dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
-        LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
-        Statement,
+        dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
+        MatchGuard, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
     },
     intern::Interned,
     item_scope::BuiltinShadowMode,
@@ -361,10 +360,15 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
                             self.check_cfg(&arm).map(|()| MatchArm {
                                 pat: self.collect_pat_opt(arm.pat()),
                                 expr: self.collect_expr_opt(arm.expr()),
-                                guard: arm
-                                    .guard()
-                                    .and_then(|guard| guard.expr())
-                                    .map(|e| self.collect_expr(e)),
+                                guard: arm.guard().map(|guard| match guard.pat() {
+                                    Some(pat) => MatchGuard::IfLet {
+                                        pat: self.collect_pat(pat),
+                                        expr: self.collect_expr_opt(guard.expr()),
+                                    },
+                                    None => {
+                                        MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
+                                    }
+                                }),
                             })
                         })
                         .collect()
@@ -504,7 +508,7 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
             ast::Expr::BinExpr(e) => {
                 let lhs = self.collect_expr_opt(e.lhs());
                 let rhs = self.collect_expr_opt(e.rhs());
-                let op = e.op_kind().map(BinaryOp::from);
+                let op = e.op_kind();
                 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
             }
             ast::Expr::TupleExpr(e) => {
@@ -554,7 +558,7 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
             ast::Expr::MacroCall(e) => {
                 let macro_ptr = AstPtr::new(&e);
                 let mut ids = vec![];
-                self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+                self.collect_macro_call(e, macro_ptr, |this, expansion| {
                     ids.push(match expansion {
                         Some(it) => this.collect_expr(it),
                         None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -578,7 +582,6 @@ fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
         &mut self,
         e: ast::MacroCall,
         syntax_ptr: AstPtr<ast::MacroCall>,
-        is_error_recoverable: bool,
         mut collector: F,
     ) {
         // File containing the macro call. Expansion errors will be attached here.
@@ -616,18 +619,11 @@ fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
 
         match res.value {
             Some((mark, expansion)) => {
-                // FIXME: Statements are too complicated to recover from error for now.
-                // It is because we don't have any hygiene for local variable expansion right now.
-                if !is_error_recoverable && res.err.is_some() {
-                    self.expander.exit(self.db, mark);
-                    collector(self, None);
-                } else {
-                    self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
+                self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
 
-                    let id = collector(self, Some(expansion));
-                    self.expander.exit(self.db, mark);
-                    id
-                }
+                let id = collector(self, Some(expansion));
+                self.expander.exit(self.db, mark);
+                id
             }
             None => collector(self, None),
         }
@@ -654,8 +650,10 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
                 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
             }
             ast::Stmt::ExprStmt(stmt) => {
-                if self.check_cfg(&stmt).is_none() {
-                    return;
+                if let Some(expr) = stmt.expr() {
+                    if self.check_cfg(&expr).is_none() {
+                        return;
+                    }
                 }
                 let has_semi = stmt.semicolon_token().is_some();
                 // Note that macro could be expended to multiple statements
@@ -663,36 +661,28 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
                     let macro_ptr = AstPtr::new(&m);
                     let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
 
-                    self.collect_macro_call(
-                        m,
-                        macro_ptr,
-                        false,
-                        |this, expansion| match expansion {
-                            Some(expansion) => {
-                                let statements: ast::MacroStmts = expansion;
-
-                                statements.statements().for_each(|stmt| this.collect_stmt(stmt));
-                                if let Some(expr) = statements.expr() {
-                                    let expr = this.collect_expr(expr);
-                                    this.statements_in_scope
-                                        .push(Statement::Expr { expr, has_semi });
-                                }
-                            }
-                            None => {
-                                let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
+                    self.collect_macro_call(m, macro_ptr, |this, expansion| match expansion {
+                        Some(expansion) => {
+                            let statements: ast::MacroStmts = expansion;
+
+                            statements.statements().for_each(|stmt| this.collect_stmt(stmt));
+                            if let Some(expr) = statements.expr() {
+                                let expr = this.collect_expr(expr);
                                 this.statements_in_scope.push(Statement::Expr { expr, has_semi });
                             }
-                        },
-                    );
+                        }
+                        None => {
+                            let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
+                            this.statements_in_scope.push(Statement::Expr { expr, has_semi });
+                        }
+                    });
                 } else {
                     let expr = self.collect_expr_opt(stmt.expr());
                     self.statements_in_scope.push(Statement::Expr { expr, has_semi });
                 }
             }
             ast::Stmt::Item(item) => {
-                if self.check_cfg(&item).is_none() {
-                    return;
-                }
+                self.check_cfg(&item);
             }
         }
     }
@@ -717,7 +707,8 @@ fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
         block.statements().for_each(|s| self.collect_stmt(s));
         block.tail_expr().and_then(|e| {
             let expr = self.maybe_collect_expr(e)?;
-            Some(self.statements_in_scope.push(Statement::Expr { expr, has_semi: false }))
+            self.statements_in_scope.push(Statement::Expr { expr, has_semi: false });
+            Some(())
         });
 
         let mut tail = None;
@@ -886,7 +877,7 @@ fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
                 Some(call) => {
                     let macro_ptr = AstPtr::new(&call);
                     let mut pat = None;
-                    self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
+                    self.collect_macro_call(call, macro_ptr, |this, expanded_pat| {
                         pat = Some(this.collect_pat_opt(expanded_pat));
                     });
 
@@ -950,68 +941,24 @@ fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
     }
 }
 
-impl From<ast::BinOp> for BinaryOp {
-    fn from(ast_op: ast::BinOp) -> Self {
-        match ast_op {
-            ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
-            ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
-            ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
-            ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
-            ast::BinOp::LesserEqualTest => {
-                BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
-            }
-            ast::BinOp::GreaterEqualTest => {
-                BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
-            }
-            ast::BinOp::LesserTest => {
-                BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
-            }
-            ast::BinOp::GreaterTest => {
-                BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
-            }
-            ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
-            ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
-            ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
-            ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
-            ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
-            ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
-            ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
-            ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
-            ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
-            ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
-            ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
-            ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
-            ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
-            ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
-            ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
-            ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
-            ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
-            ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
-            ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
-            ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
-            ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
-        }
-    }
-}
-
 impl From<ast::LiteralKind> for Literal {
     fn from(ast_lit_kind: ast::LiteralKind) -> Self {
         match ast_lit_kind {
             // FIXME: these should have actual values filled in, but unsure on perf impact
             LiteralKind::IntNumber(lit) => {
                 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
-                    return Literal::Float(Default::default(), builtin);
+                    Literal::Float(Default::default(), builtin)
                 } else if let builtin @ Some(_) =
-                    lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it))
+                    lit.suffix().and_then(|it| BuiltinInt::from_suffix(it))
                 {
                     Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
                 } else {
-                    let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it));
+                    let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it));
                     Literal::Uint(lit.value().unwrap_or(0), builtin)
                 }
             }
             LiteralKind::FloatNumber(lit) => {
-                let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
+                let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it));
                 Literal::Float(Default::default(), ty)
             }
             LiteralKind::ByteString(bs) => {