aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r--crates/ra_hir/src/expr.rs667
1 files changed, 14 insertions, 653 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 5c95bed40..bfd250f38 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,36 +1,30 @@
1use std::ops::Index; 1pub(crate) mod lower;
2use std::sync::Arc; 2pub(crate) mod scope;
3pub(crate) mod validation;
3 4
4use rustc_hash::FxHashMap; 5use std::{ops::Index, sync::Arc};
5 6
6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 7use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_syntax::{ 8use ra_syntax::{ast, AstPtr};
8 ast::{ 9use rustc_hash::FxHashMap;
9 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
10 TypeAscriptionOwner,
11 },
12 AstNode, AstPtr,
13};
14use test_utils::tested_by;
15 10
16use crate::{ 11use crate::{
17 name::{AsName, SELF_PARAM},
18 path::GenericArgs, 12 path::GenericArgs,
19 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 13 ty::primitive::{UncertainFloatTy, UncertainIntTy},
20 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
21 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, 15 DefWithBody, Either, HirDatabase, Name, Path, Resolver,
22 Path, Resolver,
23}; 16};
24 17
25pub use self::scope::ExprScopes; 18pub use self::scope::ExprScopes;
26 19
27pub(crate) mod scope;
28pub(crate) mod validation;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub struct ExprId(RawId); 21pub struct ExprId(RawId);
32impl_arena_id!(ExprId); 22impl_arena_id!(ExprId);
33 23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct PatId(RawId);
26impl_arena_id!(PatId);
27
34/// The body of an item (function, const etc.). 28/// The body of an item (function, const etc.).
35#[derive(Debug, Eq, PartialEq)] 29#[derive(Debug, Eq, PartialEq)]
36pub struct Body { 30pub struct Body {
@@ -433,10 +427,6 @@ impl Expr {
433 } 427 }
434} 428}
435 429
436#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
437pub struct PatId(RawId);
438impl_arena_id!(PatId);
439
440/// Explicit binding annotations given in the HIR for a binding. Note 430/// Explicit binding annotations given in the HIR for a binding. Note
441/// that this is not the final binding *mode* that we infer after type 431/// that this is not the final binding *mode* that we infer after type
442/// inference. 432/// inference.
@@ -482,7 +472,7 @@ pub enum Pat {
482 Missing, 472 Missing,
483 Wild, 473 Wild,
484 Tuple(Vec<PatId>), 474 Tuple(Vec<PatId>),
485 Struct { 475 Record {
486 path: Option<Path>, 476 path: Option<Path>,
487 args: Vec<RecordFieldPat>, 477 args: Vec<RecordFieldPat>,
488 // FIXME: 'ellipsis' option 478 // FIXME: 'ellipsis' option
@@ -528,638 +518,9 @@ impl Pat {
528 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); 518 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
529 total_iter.copied().for_each(f); 519 total_iter.copied().for_each(f);
530 } 520 }
531 Pat::Struct { args, .. } => { 521 Pat::Record { args, .. } => {
532 args.iter().map(|f| f.pat).for_each(f); 522 args.iter().map(|f| f.pat).for_each(f);
533 } 523 }
534 } 524 }
535 } 525 }
536} 526}
537
538// Queries
539
540pub(crate) struct ExprCollector<DB> {
541 db: DB,
542 owner: DefWithBody,
543 exprs: Arena<ExprId, Expr>,
544 pats: Arena<PatId, Pat>,
545 source_map: BodySourceMap,
546 params: Vec<PatId>,
547 body_expr: Option<ExprId>,
548 resolver: Resolver,
549 // Expr collector expands macros along the way. original points to the file
550 // we started with, current points to the current macro expansion. source
551 // maps don't support macros yet, so we only record info into source map if
552 // current == original (see #1196)
553 original_file_id: HirFileId,
554 current_file_id: HirFileId,
555}
556
557impl<'a, DB> ExprCollector<&'a DB>
558where
559 DB: HirDatabase,
560{
561 fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self {
562 ExprCollector {
563 owner,
564 resolver,
565 db,
566 exprs: Arena::default(),
567 pats: Arena::default(),
568 source_map: BodySourceMap::default(),
569 params: Vec::new(),
570 body_expr: None,
571 original_file_id: file_id,
572 current_file_id: file_id,
573 }
574 }
575 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
576 let ptr = Either::A(ptr);
577 let id = self.exprs.alloc(expr);
578 if self.current_file_id == self.original_file_id {
579 self.source_map.expr_map.insert(ptr, id);
580 self.source_map.expr_map_back.insert(id, ptr);
581 }
582 id
583 }
584
585 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
586 let id = self.pats.alloc(pat);
587
588 if self.current_file_id == self.original_file_id {
589 self.source_map.pat_map.insert(ptr, id);
590 self.source_map.pat_map_back.insert(id, ptr);
591 }
592
593 id
594 }
595
596 fn empty_block(&mut self) -> ExprId {
597 let block = Expr::Block { statements: Vec::new(), tail: None };
598 self.exprs.alloc(block)
599 }
600
601 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
602 let syntax_ptr = AstPtr::new(&expr);
603 match expr {
604 ast::Expr::IfExpr(e) => {
605 let then_branch = self.collect_block_opt(e.then_branch());
606
607 let else_branch = e.else_branch().map(|b| match b {
608 ast::ElseBranch::Block(it) => self.collect_block(it),
609 ast::ElseBranch::IfExpr(elif) => {
610 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
611 self.collect_expr(expr)
612 }
613 });
614
615 let condition = match e.condition() {
616 None => self.exprs.alloc(Expr::Missing),
617 Some(condition) => match condition.pat() {
618 None => self.collect_expr_opt(condition.expr()),
619 // if let -- desugar to match
620 Some(pat) => {
621 let pat = self.collect_pat(pat);
622 let match_expr = self.collect_expr_opt(condition.expr());
623 let placeholder_pat = self.pats.alloc(Pat::Missing);
624 let arms = vec![
625 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
626 MatchArm {
627 pats: vec![placeholder_pat],
628 expr: else_branch.unwrap_or_else(|| self.empty_block()),
629 guard: None,
630 },
631 ];
632 return self
633 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
634 }
635 },
636 };
637
638 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
639 }
640 ast::Expr::TryBlockExpr(e) => {
641 let body = self.collect_block_opt(e.body());
642 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
643 }
644 ast::Expr::BlockExpr(e) => self.collect_block(e),
645 ast::Expr::LoopExpr(e) => {
646 let body = self.collect_block_opt(e.loop_body());
647 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
648 }
649 ast::Expr::WhileExpr(e) => {
650 let body = self.collect_block_opt(e.loop_body());
651
652 let condition = match e.condition() {
653 None => self.exprs.alloc(Expr::Missing),
654 Some(condition) => match condition.pat() {
655 None => self.collect_expr_opt(condition.expr()),
656 // if let -- desugar to match
657 Some(pat) => {
658 tested_by!(infer_while_let);
659 let pat = self.collect_pat(pat);
660 let match_expr = self.collect_expr_opt(condition.expr());
661 let placeholder_pat = self.pats.alloc(Pat::Missing);
662 let break_ = self.exprs.alloc(Expr::Break { expr: None });
663 let arms = vec![
664 MatchArm { pats: vec![pat], expr: body, guard: None },
665 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
666 ];
667 let match_expr =
668 self.exprs.alloc(Expr::Match { expr: match_expr, arms });
669 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
670 }
671 },
672 };
673
674 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
675 }
676 ast::Expr::ForExpr(e) => {
677 let iterable = self.collect_expr_opt(e.iterable());
678 let pat = self.collect_pat_opt(e.pat());
679 let body = self.collect_block_opt(e.loop_body());
680 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
681 }
682 ast::Expr::CallExpr(e) => {
683 let callee = self.collect_expr_opt(e.expr());
684 let args = if let Some(arg_list) = e.arg_list() {
685 arg_list.args().map(|e| self.collect_expr(e)).collect()
686 } else {
687 Vec::new()
688 };
689 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
690 }
691 ast::Expr::MethodCallExpr(e) => {
692 let receiver = self.collect_expr_opt(e.expr());
693 let args = if let Some(arg_list) = e.arg_list() {
694 arg_list.args().map(|e| self.collect_expr(e)).collect()
695 } else {
696 Vec::new()
697 };
698 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
699 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
700 self.alloc_expr(
701 Expr::MethodCall { receiver, method_name, args, generic_args },
702 syntax_ptr,
703 )
704 }
705 ast::Expr::MatchExpr(e) => {
706 let expr = self.collect_expr_opt(e.expr());
707 let arms = if let Some(match_arm_list) = e.match_arm_list() {
708 match_arm_list
709 .arms()
710 .map(|arm| MatchArm {
711 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
712 expr: self.collect_expr_opt(arm.expr()),
713 guard: arm
714 .guard()
715 .and_then(|guard| guard.expr())
716 .map(|e| self.collect_expr(e)),
717 })
718 .collect()
719 } else {
720 Vec::new()
721 };
722 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
723 }
724 ast::Expr::PathExpr(e) => {
725 let path =
726 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
727 self.alloc_expr(path, syntax_ptr)
728 }
729 ast::Expr::ContinueExpr(_e) => {
730 // FIXME: labels
731 self.alloc_expr(Expr::Continue, syntax_ptr)
732 }
733 ast::Expr::BreakExpr(e) => {
734 let expr = e.expr().map(|e| self.collect_expr(e));
735 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
736 }
737 ast::Expr::ParenExpr(e) => {
738 let inner = self.collect_expr_opt(e.expr());
739 // make the paren expr point to the inner expression as well
740 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
741 inner
742 }
743 ast::Expr::ReturnExpr(e) => {
744 let expr = e.expr().map(|e| self.collect_expr(e));
745 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
746 }
747 ast::Expr::RecordLit(e) => {
748 let path = e.path().and_then(Path::from_ast);
749 let mut field_ptrs = Vec::new();
750 let record_lit = if let Some(nfl) = e.record_field_list() {
751 let fields = nfl
752 .fields()
753 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
754 .map(|field| RecordLitField {
755 name: field
756 .name_ref()
757 .map(|nr| nr.as_name())
758 .unwrap_or_else(Name::missing),
759 expr: if let Some(e) = field.expr() {
760 self.collect_expr(e)
761 } else if let Some(nr) = field.name_ref() {
762 // field shorthand
763 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr)));
764 let ptr = Either::B(AstPtr::new(&field));
765 self.source_map.expr_map.insert(ptr, id);
766 self.source_map.expr_map_back.insert(id, ptr);
767 id
768 } else {
769 self.exprs.alloc(Expr::Missing)
770 },
771 })
772 .collect();
773 let spread = nfl.spread().map(|s| self.collect_expr(s));
774 Expr::RecordLit { path, fields, spread }
775 } else {
776 Expr::RecordLit { path, fields: Vec::new(), spread: None }
777 };
778
779 let res = self.alloc_expr(record_lit, syntax_ptr);
780 for (i, ptr) in field_ptrs.into_iter().enumerate() {
781 self.source_map.field_map.insert((res, i), ptr);
782 }
783 res
784 }
785 ast::Expr::FieldExpr(e) => {
786 let expr = self.collect_expr_opt(e.expr());
787 let name = match e.field_access() {
788 Some(kind) => kind.as_name(),
789 _ => Name::missing(),
790 };
791 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
792 }
793 ast::Expr::AwaitExpr(e) => {
794 let expr = self.collect_expr_opt(e.expr());
795 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
796 }
797 ast::Expr::TryExpr(e) => {
798 let expr = self.collect_expr_opt(e.expr());
799 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
800 }
801 ast::Expr::CastExpr(e) => {
802 let expr = self.collect_expr_opt(e.expr());
803 let type_ref = TypeRef::from_ast_opt(e.type_ref());
804 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
805 }
806 ast::Expr::RefExpr(e) => {
807 let expr = self.collect_expr_opt(e.expr());
808 let mutability = Mutability::from_mutable(e.is_mut());
809 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
810 }
811 ast::Expr::PrefixExpr(e) => {
812 let expr = self.collect_expr_opt(e.expr());
813 if let Some(op) = e.op_kind() {
814 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
815 } else {
816 self.alloc_expr(Expr::Missing, syntax_ptr)
817 }
818 }
819 ast::Expr::LambdaExpr(e) => {
820 let mut args = Vec::new();
821 let mut arg_types = Vec::new();
822 if let Some(pl) = e.param_list() {
823 for param in pl.params() {
824 let pat = self.collect_pat_opt(param.pat());
825 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
826 args.push(pat);
827 arg_types.push(type_ref);
828 }
829 }
830 let body = self.collect_expr_opt(e.body());
831 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
832 }
833 ast::Expr::BinExpr(e) => {
834 let lhs = self.collect_expr_opt(e.lhs());
835 let rhs = self.collect_expr_opt(e.rhs());
836 let op = e.op_kind().map(BinaryOp::from);
837 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
838 }
839 ast::Expr::TupleExpr(e) => {
840 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
841 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
842 }
843
844 ast::Expr::ArrayExpr(e) => {
845 let kind = e.kind();
846
847 match kind {
848 ArrayExprKind::ElementList(e) => {
849 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
850 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
851 }
852 ArrayExprKind::Repeat { initializer, repeat } => {
853 let initializer = self.collect_expr_opt(initializer);
854 let repeat = self.collect_expr_opt(repeat);
855 self.alloc_expr(
856 Expr::Array(Array::Repeat { initializer, repeat }),
857 syntax_ptr,
858 )
859 }
860 }
861 }
862
863 ast::Expr::Literal(e) => {
864 let lit = match e.kind() {
865 LiteralKind::IntNumber { suffix } => {
866 let known_name = suffix
867 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
868
869 Literal::Int(
870 Default::default(),
871 known_name.unwrap_or(UncertainIntTy::Unknown),
872 )
873 }
874 LiteralKind::FloatNumber { suffix } => {
875 let known_name = suffix
876 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
877
878 Literal::Float(
879 Default::default(),
880 known_name.unwrap_or(UncertainFloatTy::Unknown),
881 )
882 }
883 LiteralKind::ByteString => Literal::ByteString(Default::default()),
884 LiteralKind::String => Literal::String(Default::default()),
885 LiteralKind::Byte => {
886 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
887 }
888 LiteralKind::Bool => Literal::Bool(Default::default()),
889 LiteralKind::Char => Literal::Char(Default::default()),
890 };
891 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
892 }
893 ast::Expr::IndexExpr(e) => {
894 let base = self.collect_expr_opt(e.base());
895 let index = self.collect_expr_opt(e.index());
896 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
897 }
898
899 // FIXME implement HIR for these:
900 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
901 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
902 ast::Expr::MacroCall(e) => {
903 let ast_id = self
904 .db
905 .ast_id_map(self.current_file_id)
906 .ast_id(&e)
907 .with_file_id(self.current_file_id);
908
909 if let Some(path) = e.path().and_then(Path::from_ast) {
910 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
911 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
912 let file_id = call_id.as_file(MacroFileKind::Expr);
913 if let Some(node) = self.db.parse_or_expand(file_id) {
914 if let Some(expr) = ast::Expr::cast(node) {
915 log::debug!("macro expansion {:#?}", expr.syntax());
916 let old_file_id =
917 std::mem::replace(&mut self.current_file_id, file_id);
918 let id = self.collect_expr(expr);
919 self.current_file_id = old_file_id;
920 return id;
921 }
922 }
923 }
924 }
925 // FIXME: Instead of just dropping the error from expansion
926 // report it
927 self.alloc_expr(Expr::Missing, syntax_ptr)
928 }
929 }
930 }
931
932 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
933 if let Some(expr) = expr {
934 self.collect_expr(expr)
935 } else {
936 self.exprs.alloc(Expr::Missing)
937 }
938 }
939
940 fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
941 let syntax_node_ptr = AstPtr::new(&expr.clone().into());
942 let block = match expr.block() {
943 Some(block) => block,
944 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
945 };
946 let statements = block
947 .statements()
948 .map(|s| match s {
949 ast::Stmt::LetStmt(stmt) => {
950 let pat = self.collect_pat_opt(stmt.pat());
951 let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
952 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
953 Statement::Let { pat, type_ref, initializer }
954 }
955 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
956 })
957 .collect();
958 let tail = block.expr().map(|e| self.collect_expr(e));
959 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
960 }
961
962 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
963 if let Some(block) = expr {
964 self.collect_block(block)
965 } else {
966 self.exprs.alloc(Expr::Missing)
967 }
968 }
969
970 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
971 let pattern = match &pat {
972 ast::Pat::BindPat(bp) => {
973 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
974 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
975 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
976 Pat::Bind { name, mode: annotation, subpat }
977 }
978 ast::Pat::TupleStructPat(p) => {
979 let path = p.path().and_then(Path::from_ast);
980 let args = p.args().map(|p| self.collect_pat(p)).collect();
981 Pat::TupleStruct { path, args }
982 }
983 ast::Pat::RefPat(p) => {
984 let pat = self.collect_pat_opt(p.pat());
985 let mutability = Mutability::from_mutable(p.is_mut());
986 Pat::Ref { pat, mutability }
987 }
988 ast::Pat::PathPat(p) => {
989 let path = p.path().and_then(Path::from_ast);
990 path.map(Pat::Path).unwrap_or(Pat::Missing)
991 }
992 ast::Pat::TuplePat(p) => {
993 let args = p.args().map(|p| self.collect_pat(p)).collect();
994 Pat::Tuple(args)
995 }
996 ast::Pat::PlaceholderPat(_) => Pat::Wild,
997 ast::Pat::RecordPat(p) => {
998 let path = p.path().and_then(Path::from_ast);
999 let record_field_pat_list =
1000 p.record_field_pat_list().expect("every struct should have a field list");
1001 let mut fields: Vec<_> = record_field_pat_list
1002 .bind_pats()
1003 .filter_map(|bind_pat| {
1004 let ast_pat =
1005 ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
1006 let pat = self.collect_pat(ast_pat);
1007 let name = bind_pat.name()?.as_name();
1008 Some(RecordFieldPat { name, pat })
1009 })
1010 .collect();
1011 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
1012 let ast_pat = f.pat()?;
1013 let pat = self.collect_pat(ast_pat);
1014 let name = f.name()?.as_name();
1015 Some(RecordFieldPat { name, pat })
1016 });
1017 fields.extend(iter);
1018
1019 Pat::Struct { path, args: fields }
1020 }
1021
1022 // FIXME: implement
1023 ast::Pat::BoxPat(_) => Pat::Missing,
1024 ast::Pat::LiteralPat(_) => Pat::Missing,
1025 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
1026 };
1027 let ptr = AstPtr::new(&pat);
1028 self.alloc_pat(pattern, Either::A(ptr))
1029 }
1030
1031 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
1032 if let Some(pat) = pat {
1033 self.collect_pat(pat)
1034 } else {
1035 self.pats.alloc(Pat::Missing)
1036 }
1037 }
1038
1039 fn collect_const_body(&mut self, node: ast::ConstDef) {
1040 let body = self.collect_expr_opt(node.body());
1041 self.body_expr = Some(body);
1042 }
1043
1044 fn collect_static_body(&mut self, node: ast::StaticDef) {
1045 let body = self.collect_expr_opt(node.body());
1046 self.body_expr = Some(body);
1047 }
1048
1049 fn collect_fn_body(&mut self, node: ast::FnDef) {
1050 if let Some(param_list) = node.param_list() {
1051 if let Some(self_param) = param_list.self_param() {
1052 let ptr = AstPtr::new(&self_param);
1053 let param_pat = self.alloc_pat(
1054 Pat::Bind {
1055 name: SELF_PARAM,
1056 mode: BindingAnnotation::Unannotated,
1057 subpat: None,
1058 },
1059 Either::B(ptr),
1060 );
1061 self.params.push(param_pat);
1062 }
1063
1064 for param in param_list.params() {
1065 let pat = if let Some(pat) = param.pat() {
1066 pat
1067 } else {
1068 continue;
1069 };
1070 let param_pat = self.collect_pat(pat);
1071 self.params.push(param_pat);
1072 }
1073 };
1074
1075 let body = self.collect_block_opt(node.body());
1076 self.body_expr = Some(body);
1077 }
1078
1079 fn finish(self) -> (Body, BodySourceMap) {
1080 let body = Body {
1081 owner: self.owner,
1082 exprs: self.exprs,
1083 pats: self.pats,
1084 params: self.params,
1085 body_expr: self.body_expr.expect("A body should have been collected"),
1086 };
1087 (body, self.source_map)
1088 }
1089}
1090
1091impl From<ast::BinOp> for BinaryOp {
1092 fn from(ast_op: ast::BinOp) -> Self {
1093 match ast_op {
1094 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
1095 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
1096 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
1097 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
1098 ast::BinOp::LesserEqualTest => {
1099 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
1100 }
1101 ast::BinOp::GreaterEqualTest => {
1102 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
1103 }
1104 ast::BinOp::LesserTest => {
1105 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
1106 }
1107 ast::BinOp::GreaterTest => {
1108 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
1109 }
1110 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
1111 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
1112 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
1113 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
1114 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
1115 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
1116 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
1117 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
1118 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
1119 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
1120 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
1121 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
1122 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
1123 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
1124 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
1125 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
1126 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
1127 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
1128 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
1129 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
1130 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
1131 }
1132 }
1133}
1134
1135pub(crate) fn body_with_source_map_query(
1136 db: &impl HirDatabase,
1137 def: DefWithBody,
1138) -> (Arc<Body>, Arc<BodySourceMap>) {
1139 let mut collector;
1140
1141 match def {
1142 DefWithBody::Const(ref c) => {
1143 let src = c.source(db);
1144 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
1145 collector.collect_const_body(src.ast)
1146 }
1147 DefWithBody::Function(ref f) => {
1148 let src = f.source(db);
1149 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
1150 collector.collect_fn_body(src.ast)
1151 }
1152 DefWithBody::Static(ref s) => {
1153 let src = s.source(db);
1154 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
1155 collector.collect_static_body(src.ast)
1156 }
1157 }
1158
1159 let (body, source_map) = collector.finish();
1160 (Arc::new(body), Arc::new(source_map))
1161}
1162
1163pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
1164 db.body_with_source_map(def).0
1165}