aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model.rs49
-rw-r--r--crates/ra_hir/src/code_model/src.rs45
-rw-r--r--crates/ra_hir/src/expr.rs693
-rw-r--r--crates/ra_hir/src/expr/lower.rs630
-rw-r--r--crates/ra_hir/src/expr/scope.rs5
-rw-r--r--crates/ra_hir/src/expr/validation.rs46
-rw-r--r--crates/ra_hir/src/lib.rs10
-rw-r--r--crates/ra_hir/src/path.rs21
-rw-r--r--crates/ra_hir/src/source_binder.rs41
-rw-r--r--crates/ra_hir/src/ty.rs348
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs14
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs2
-rw-r--r--crates/ra_hir/src/ty/lower.rs86
-rw-r--r--crates/ra_hir/src/ty/tests.rs124
-rw-r--r--crates/ra_hir/src/ty/traits.rs17
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs8
17 files changed, 1270 insertions, 871 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 66a58efed..f7efc1b66 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -510,18 +510,6 @@ pub enum DefWithBody {
510impl_froms!(DefWithBody: Function, Const, Static); 510impl_froms!(DefWithBody: Function, Const, Static);
511 511
512impl DefWithBody { 512impl DefWithBody {
513 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
514 db.infer(self)
515 }
516
517 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> {
518 db.body_hir(self)
519 }
520
521 pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
522 db.body_with_source_map(self).1
523 }
524
525 /// Builds a resolver for code inside this item. 513 /// Builds a resolver for code inside this item.
526 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { 514 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
527 match self { 515 match self {
@@ -532,6 +520,43 @@ impl DefWithBody {
532 } 520 }
533} 521}
534 522
523pub trait HasBody: Copy {
524 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>;
525 fn body(self, db: &impl HirDatabase) -> Arc<Body>;
526 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>;
527}
528
529impl<T> HasBody for T
530where
531 T: Into<DefWithBody> + Copy + HasSource,
532{
533 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
534 db.infer(self.into())
535 }
536
537 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
538 db.body_hir(self.into())
539 }
540
541 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
542 db.body_with_source_map(self.into()).1
543 }
544}
545
546impl HasBody for DefWithBody {
547 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
548 db.infer(self)
549 }
550
551 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
552 db.body_hir(self)
553 }
554
555 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
556 db.body_with_source_map(self).1
557 }
558}
559
535#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 560#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
536pub struct Function { 561pub struct Function {
537 pub(crate) id: FunctionId, 562 pub(crate) id: FunctionId,
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 32bd9c661..b9ffb0c7a 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,11 +1,15 @@
1use ra_syntax::ast; 1use ra_syntax::{
2 ast::{self, AstNode},
3 SyntaxNode,
4};
2 5
3use crate::{ 6use crate::{
4 ids::AstItemDef, AstDatabase, Const, DefDatabase, Enum, EnumVariant, FieldSource, Function, 7 ids::AstItemDef, AstDatabase, Const, DefDatabase, Either, Enum, EnumVariant, FieldSource,
5 HirFileId, MacroDef, Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, 8 Function, HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct,
6 Union, 9 StructField, Trait, TypeAlias, Union,
7}; 10};
8 11
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
9pub struct Source<T> { 13pub struct Source<T> {
10 pub file_id: HirFileId, 14 pub file_id: HirFileId,
11 pub ast: T, 15 pub ast: T,
@@ -16,6 +20,15 @@ pub trait HasSource {
16 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 20 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>;
17} 21}
18 22
23impl<T> Source<T> {
24 pub(crate) fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
25 Source { file_id: self.file_id, ast: f(self.ast) }
26 }
27 pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
28 db.parse_or_expand(self.file_id).expect("source created from invalid file")
29 }
30}
31
19/// NB: Module is !HasSource, because it has two source nodes at the same time: 32/// NB: Module is !HasSource, because it has two source nodes at the same time:
20/// definition and declaration. 33/// definition and declaration.
21impl Module { 34impl Module {
@@ -108,3 +121,27 @@ impl HasSource for MacroDef {
108 Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) } 121 Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) }
109 } 122 }
110} 123}
124
125pub trait HasBodySource: HasBody + HasSource
126where
127 Self::Ast: AstNode,
128{
129 fn expr_source(
130 self,
131 db: &impl HirDatabase,
132 expr_id: crate::expr::ExprId,
133 ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> {
134 let source_map = self.body_source_map(db);
135 let source_ptr = source_map.expr_syntax(expr_id)?;
136 let root = source_ptr.file_syntax(db);
137 let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root)));
138 Some(source)
139 }
140}
141
142impl<T> HasBodySource for T
143where
144 T: HasBody + HasSource,
145 T::Ast: AstNode,
146{
147}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 7cdc7555c..fc21e269f 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 TryBlockBodyOwner, TypeAscriptionOwner,
11 },
12 AstNode, AstPtr, SyntaxNodePtr,
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, HasSource, HirDatabase, Name, Path, Resolver, Source,
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 {
@@ -49,22 +43,32 @@ pub struct Body {
49 body_expr: ExprId, 43 body_expr: ExprId,
50} 44}
51 45
46type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
47type ExprSource = Source<ExprPtr>;
48
49type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
50type PatSource = Source<PatPtr>;
51
52/// An item body together with the mapping from syntax nodes to HIR expression 52/// An item body together with the mapping from syntax nodes to HIR expression
53/// IDs. This is needed to go from e.g. a position in a file to the HIR 53/// IDs. This is needed to go from e.g. a position in a file to the HIR
54/// expression containing it; but for type inference etc., we want to operate on 54/// expression containing it; but for type inference etc., we want to operate on
55/// a structure that is agnostic to the actual positions of expressions in the 55/// a structure that is agnostic to the actual positions of expressions in the
56/// file, so that we don't recompute types whenever some whitespace is typed. 56/// file, so that we don't recompute types whenever some whitespace is typed.
57///
58/// One complication here is that, due to macro expansion, a single `Body` might
59/// be spread across several files. So, for each ExprId and PatId, we record
60/// both the HirFileId and the position inside the file. However, we only store
61/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
62/// this properly for macros.
57#[derive(Default, Debug, Eq, PartialEq)] 63#[derive(Default, Debug, Eq, PartialEq)]
58pub struct BodySourceMap { 64pub struct BodySourceMap {
59 expr_map: FxHashMap<SyntaxNodePtr, ExprId>, 65 expr_map: FxHashMap<ExprPtr, ExprId>,
60 expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, 66 expr_map_back: ArenaMap<ExprId, ExprSource>,
61 pat_map: FxHashMap<PatPtr, PatId>, 67 pat_map: FxHashMap<PatPtr, PatId>,
62 pat_map_back: ArenaMap<PatId, PatPtr>, 68 pat_map_back: ArenaMap<PatId, PatSource>,
63 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 69 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
64} 70}
65 71
66type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
67
68impl Body { 72impl Body {
69 pub fn params(&self) -> &[PatId] { 73 pub fn params(&self) -> &[PatId] {
70 &self.params 74 &self.params
@@ -128,20 +132,16 @@ impl Index<PatId> for Body {
128} 132}
129 133
130impl BodySourceMap { 134impl BodySourceMap {
131 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { 135 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> {
132 self.expr_map_back.get(expr).cloned() 136 self.expr_map_back.get(expr).copied()
133 }
134
135 pub(crate) fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> {
136 self.expr_map.get(&ptr).cloned()
137 } 137 }
138 138
139 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 139 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
140 self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() 140 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
141 } 141 }
142 142
143 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { 143 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
144 self.pat_map_back.get(pat).cloned() 144 self.pat_map_back.get(pat).copied()
145 } 145 }
146 146
147 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 147 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
@@ -436,10 +436,6 @@ impl Expr {
436 } 436 }
437} 437}
438 438
439#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
440pub struct PatId(RawId);
441impl_arena_id!(PatId);
442
443/// Explicit binding annotations given in the HIR for a binding. Note 439/// Explicit binding annotations given in the HIR for a binding. Note
444/// that this is not the final binding *mode* that we infer after type 440/// that this is not the final binding *mode* that we infer after type
445/// inference. 441/// inference.
@@ -485,7 +481,7 @@ pub enum Pat {
485 Missing, 481 Missing,
486 Wild, 482 Wild,
487 Tuple(Vec<PatId>), 483 Tuple(Vec<PatId>),
488 Struct { 484 Record {
489 path: Option<Path>, 485 path: Option<Path>,
490 args: Vec<RecordFieldPat>, 486 args: Vec<RecordFieldPat>,
491 // FIXME: 'ellipsis' option 487 // FIXME: 'ellipsis' option
@@ -531,7 +527,7 @@ impl Pat {
531 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); 527 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
532 total_iter.copied().for_each(f); 528 total_iter.copied().for_each(f);
533 } 529 }
534 Pat::Struct { args, .. } => { 530 Pat::Record { args, .. } => {
535 args.iter().map(|f| f.pat).for_each(f); 531 args.iter().map(|f| f.pat).for_each(f);
536 } 532 }
537 } 533 }
@@ -539,624 +535,29 @@ impl Pat {
539} 535}
540 536
541// Queries 537// Queries
542
543pub(crate) struct ExprCollector<DB> {
544 db: DB,
545 owner: DefWithBody,
546 exprs: Arena<ExprId, Expr>,
547 pats: Arena<PatId, Pat>,
548 source_map: BodySourceMap,
549 params: Vec<PatId>,
550 body_expr: Option<ExprId>,
551 resolver: Resolver,
552 // Expr collector expands macros along the way. original points to the file
553 // we started with, current points to the current macro expansion. source
554 // maps don't support macros yet, so we only record info into source map if
555 // current == original (see #1196)
556 original_file_id: HirFileId,
557 current_file_id: HirFileId,
558}
559
560impl<'a, DB> ExprCollector<&'a DB>
561where
562 DB: HirDatabase,
563{
564 fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self {
565 ExprCollector {
566 owner,
567 resolver,
568 db,
569 exprs: Arena::default(),
570 pats: Arena::default(),
571 source_map: BodySourceMap::default(),
572 params: Vec::new(),
573 body_expr: None,
574 original_file_id: file_id,
575 current_file_id: file_id,
576 }
577 }
578 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
579 let id = self.exprs.alloc(expr);
580 if self.current_file_id == self.original_file_id {
581 self.source_map.expr_map.insert(syntax_ptr, id);
582 self.source_map.expr_map_back.insert(id, syntax_ptr);
583 }
584 id
585 }
586
587 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
588 let id = self.pats.alloc(pat);
589
590 if self.current_file_id == self.original_file_id {
591 self.source_map.pat_map.insert(ptr, id);
592 self.source_map.pat_map_back.insert(id, ptr);
593 }
594
595 id
596 }
597
598 fn empty_block(&mut self) -> ExprId {
599 let block = Expr::Block { statements: Vec::new(), tail: None };
600 self.exprs.alloc(block)
601 }
602
603 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
604 let syntax_ptr = SyntaxNodePtr::new(expr.syntax());
605 match expr {
606 ast::Expr::IfExpr(e) => {
607 let then_branch = self.collect_block_opt(e.then_branch());
608
609 let else_branch = e.else_branch().map(|b| match b {
610 ast::ElseBranch::Block(it) => self.collect_block(it),
611 ast::ElseBranch::IfExpr(elif) => {
612 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
613 self.collect_expr(expr)
614 }
615 });
616
617 let condition = match e.condition() {
618 None => self.exprs.alloc(Expr::Missing),
619 Some(condition) => match condition.pat() {
620 None => self.collect_expr_opt(condition.expr()),
621 // if let -- desugar to match
622 Some(pat) => {
623 let pat = self.collect_pat(pat);
624 let match_expr = self.collect_expr_opt(condition.expr());
625 let placeholder_pat = self.pats.alloc(Pat::Missing);
626 let arms = vec![
627 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
628 MatchArm {
629 pats: vec![placeholder_pat],
630 expr: else_branch.unwrap_or_else(|| self.empty_block()),
631 guard: None,
632 },
633 ];
634 return self
635 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
636 }
637 },
638 };
639
640 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
641 }
642 ast::Expr::TryBlockExpr(e) => {
643 let body = self.collect_block_opt(e.try_body());
644 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
645 }
646 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
647 ast::Expr::LoopExpr(e) => {
648 let body = self.collect_block_opt(e.loop_body());
649 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
650 }
651 ast::Expr::WhileExpr(e) => {
652 let body = self.collect_block_opt(e.loop_body());
653
654 let condition = match e.condition() {
655 None => self.exprs.alloc(Expr::Missing),
656 Some(condition) => match condition.pat() {
657 None => self.collect_expr_opt(condition.expr()),
658 // if let -- desugar to match
659 Some(pat) => {
660 tested_by!(infer_while_let);
661 let pat = self.collect_pat(pat);
662 let match_expr = self.collect_expr_opt(condition.expr());
663 let placeholder_pat = self.pats.alloc(Pat::Missing);
664 let break_ = self.exprs.alloc(Expr::Break { expr: None });
665 let arms = vec![
666 MatchArm { pats: vec![pat], expr: body, guard: None },
667 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
668 ];
669 let match_expr =
670 self.exprs.alloc(Expr::Match { expr: match_expr, arms });
671 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
672 }
673 },
674 };
675
676 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
677 }
678 ast::Expr::ForExpr(e) => {
679 let iterable = self.collect_expr_opt(e.iterable());
680 let pat = self.collect_pat_opt(e.pat());
681 let body = self.collect_block_opt(e.loop_body());
682 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
683 }
684 ast::Expr::CallExpr(e) => {
685 let callee = self.collect_expr_opt(e.expr());
686 let args = if let Some(arg_list) = e.arg_list() {
687 arg_list.args().map(|e| self.collect_expr(e)).collect()
688 } else {
689 Vec::new()
690 };
691 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
692 }
693 ast::Expr::MethodCallExpr(e) => {
694 let receiver = self.collect_expr_opt(e.expr());
695 let args = if let Some(arg_list) = e.arg_list() {
696 arg_list.args().map(|e| self.collect_expr(e)).collect()
697 } else {
698 Vec::new()
699 };
700 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
701 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
702 self.alloc_expr(
703 Expr::MethodCall { receiver, method_name, args, generic_args },
704 syntax_ptr,
705 )
706 }
707 ast::Expr::MatchExpr(e) => {
708 let expr = self.collect_expr_opt(e.expr());
709 let arms = if let Some(match_arm_list) = e.match_arm_list() {
710 match_arm_list
711 .arms()
712 .map(|arm| MatchArm {
713 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
714 expr: self.collect_expr_opt(arm.expr()),
715 guard: arm
716 .guard()
717 .and_then(|guard| guard.expr())
718 .map(|e| self.collect_expr(e)),
719 })
720 .collect()
721 } else {
722 Vec::new()
723 };
724 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
725 }
726 ast::Expr::PathExpr(e) => {
727 let path =
728 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
729 self.alloc_expr(path, syntax_ptr)
730 }
731 ast::Expr::ContinueExpr(_e) => {
732 // FIXME: labels
733 self.alloc_expr(Expr::Continue, syntax_ptr)
734 }
735 ast::Expr::BreakExpr(e) => {
736 let expr = e.expr().map(|e| self.collect_expr(e));
737 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
738 }
739 ast::Expr::ParenExpr(e) => {
740 let inner = self.collect_expr_opt(e.expr());
741 // make the paren expr point to the inner expression as well
742 self.source_map.expr_map.insert(syntax_ptr, inner);
743 inner
744 }
745 ast::Expr::ReturnExpr(e) => {
746 let expr = e.expr().map(|e| self.collect_expr(e));
747 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
748 }
749 ast::Expr::RecordLit(e) => {
750 let path = e.path().and_then(Path::from_ast);
751 let mut field_ptrs = Vec::new();
752 let record_lit = if let Some(nfl) = e.record_field_list() {
753 let fields = nfl
754 .fields()
755 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
756 .map(|field| RecordLitField {
757 name: field
758 .name_ref()
759 .map(|nr| nr.as_name())
760 .unwrap_or_else(Name::missing),
761 expr: if let Some(e) = field.expr() {
762 self.collect_expr(e)
763 } else if let Some(nr) = field.name_ref() {
764 // field shorthand
765 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr)));
766 self.source_map
767 .expr_map
768 .insert(SyntaxNodePtr::new(nr.syntax()), id);
769 self.source_map
770 .expr_map_back
771 .insert(id, SyntaxNodePtr::new(nr.syntax()));
772 id
773 } else {
774 self.exprs.alloc(Expr::Missing)
775 },
776 })
777 .collect();
778 let spread = nfl.spread().map(|s| self.collect_expr(s));
779 Expr::RecordLit { path, fields, spread }
780 } else {
781 Expr::RecordLit { path, fields: Vec::new(), spread: None }
782 };
783
784 let res = self.alloc_expr(record_lit, syntax_ptr);
785 for (i, ptr) in field_ptrs.into_iter().enumerate() {
786 self.source_map.field_map.insert((res, i), ptr);
787 }
788 res
789 }
790 ast::Expr::FieldExpr(e) => {
791 let expr = self.collect_expr_opt(e.expr());
792 let name = match e.field_access() {
793 Some(kind) => kind.as_name(),
794 _ => Name::missing(),
795 };
796 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
797 }
798 ast::Expr::AwaitExpr(e) => {
799 let expr = self.collect_expr_opt(e.expr());
800 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
801 }
802 ast::Expr::TryExpr(e) => {
803 let expr = self.collect_expr_opt(e.expr());
804 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
805 }
806 ast::Expr::CastExpr(e) => {
807 let expr = self.collect_expr_opt(e.expr());
808 let type_ref = TypeRef::from_ast_opt(e.type_ref());
809 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
810 }
811 ast::Expr::RefExpr(e) => {
812 let expr = self.collect_expr_opt(e.expr());
813 let mutability = Mutability::from_mutable(e.is_mut());
814 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
815 }
816 ast::Expr::PrefixExpr(e) => {
817 let expr = self.collect_expr_opt(e.expr());
818 if let Some(op) = e.op_kind() {
819 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
820 } else {
821 self.alloc_expr(Expr::Missing, syntax_ptr)
822 }
823 }
824 ast::Expr::LambdaExpr(e) => {
825 let mut args = Vec::new();
826 let mut arg_types = Vec::new();
827 if let Some(pl) = e.param_list() {
828 for param in pl.params() {
829 let pat = self.collect_pat_opt(param.pat());
830 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
831 args.push(pat);
832 arg_types.push(type_ref);
833 }
834 }
835 let body = self.collect_expr_opt(e.body());
836 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
837 }
838 ast::Expr::BinExpr(e) => {
839 let lhs = self.collect_expr_opt(e.lhs());
840 let rhs = self.collect_expr_opt(e.rhs());
841 let op = e.op_kind().map(BinaryOp::from);
842 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
843 }
844 ast::Expr::TupleExpr(e) => {
845 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
846 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
847 }
848
849 ast::Expr::ArrayExpr(e) => {
850 let kind = e.kind();
851
852 match kind {
853 ArrayExprKind::ElementList(e) => {
854 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
855 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
856 }
857 ArrayExprKind::Repeat { initializer, repeat } => {
858 let initializer = self.collect_expr_opt(initializer);
859 let repeat = self.collect_expr_opt(repeat);
860 self.alloc_expr(
861 Expr::Array(Array::Repeat { initializer, repeat }),
862 syntax_ptr,
863 )
864 }
865 }
866 }
867
868 ast::Expr::Literal(e) => {
869 let lit = match e.kind() {
870 LiteralKind::IntNumber { suffix } => {
871 let known_name = suffix
872 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
873
874 Literal::Int(
875 Default::default(),
876 known_name.unwrap_or(UncertainIntTy::Unknown),
877 )
878 }
879 LiteralKind::FloatNumber { suffix } => {
880 let known_name = suffix
881 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
882
883 Literal::Float(
884 Default::default(),
885 known_name.unwrap_or(UncertainFloatTy::Unknown),
886 )
887 }
888 LiteralKind::ByteString => Literal::ByteString(Default::default()),
889 LiteralKind::String => Literal::String(Default::default()),
890 LiteralKind::Byte => {
891 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
892 }
893 LiteralKind::Bool => Literal::Bool(Default::default()),
894 LiteralKind::Char => Literal::Char(Default::default()),
895 };
896 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
897 }
898 ast::Expr::IndexExpr(e) => {
899 let base = self.collect_expr_opt(e.base());
900 let index = self.collect_expr_opt(e.index());
901 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
902 }
903
904 // FIXME implement HIR for these:
905 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
906 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
907 ast::Expr::MacroCall(e) => {
908 let ast_id = self
909 .db
910 .ast_id_map(self.current_file_id)
911 .ast_id(&e)
912 .with_file_id(self.current_file_id);
913
914 if let Some(path) = e.path().and_then(Path::from_ast) {
915 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
916 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
917 let file_id = call_id.as_file(MacroFileKind::Expr);
918 if let Some(node) = self.db.parse_or_expand(file_id) {
919 if let Some(expr) = ast::Expr::cast(node) {
920 log::debug!("macro expansion {:#?}", expr.syntax());
921 let old_file_id =
922 std::mem::replace(&mut self.current_file_id, file_id);
923 let id = self.collect_expr(expr);
924 self.current_file_id = old_file_id;
925 return id;
926 }
927 }
928 }
929 }
930 // FIXME: Instead of just dropping the error from expansion
931 // report it
932 self.alloc_expr(Expr::Missing, syntax_ptr)
933 }
934 }
935 }
936
937 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
938 if let Some(expr) = expr {
939 self.collect_expr(expr)
940 } else {
941 self.exprs.alloc(Expr::Missing)
942 }
943 }
944
945 fn collect_block(&mut self, block: ast::Block) -> ExprId {
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 }, SyntaxNodePtr::new(block.syntax()))
960 }
961
962 fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
963 if let Some(block) = block {
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( 538pub(crate) fn body_with_source_map_query(
1136 db: &impl HirDatabase, 539 db: &impl HirDatabase,
1137 def: DefWithBody, 540 def: DefWithBody,
1138) -> (Arc<Body>, Arc<BodySourceMap>) { 541) -> (Arc<Body>, Arc<BodySourceMap>) {
1139 let mut collector; 542 let mut params = None;
1140 543
1141 match def { 544 let (file_id, body) = match def {
1142 DefWithBody::Const(ref c) => { 545 DefWithBody::Function(f) => {
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); 546 let src = f.source(db);
1149 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); 547 params = src.ast.param_list();
1150 collector.collect_fn_body(src.ast) 548 (src.file_id, src.ast.body().map(ast::Expr::from))
549 }
550 DefWithBody::Const(c) => {
551 let src = c.source(db);
552 (src.file_id, src.ast.body())
1151 } 553 }
1152 DefWithBody::Static(ref s) => { 554 DefWithBody::Static(s) => {
1153 let src = s.source(db); 555 let src = s.source(db);
1154 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); 556 (src.file_id, src.ast.body())
1155 collector.collect_static_body(src.ast)
1156 } 557 }
1157 } 558 };
1158 559
1159 let (body, source_map) = collector.finish(); 560 let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body);
1160 (Arc::new(body), Arc::new(source_map)) 561 (Arc::new(body), Arc::new(source_map))
1161} 562}
1162 563
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
new file mode 100644
index 000000000..6afd80989
--- /dev/null
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -0,0 +1,630 @@
1use ra_arena::Arena;
2use ra_syntax::{
3 ast::{
4 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
5 TypeAscriptionOwner,
6 },
7 AstNode, AstPtr,
8};
9use test_utils::tested_by;
10
11use crate::{
12 name::{AsName, Name, SELF_PARAM},
13 path::GenericArgs,
14 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
15 type_ref::TypeRef,
16 DefWithBody, Either, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path,
17 Resolver, Source,
18};
19
20use super::{
21 ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal,
22 LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement,
23};
24
25pub(super) fn lower(
26 db: &impl HirDatabase,
27 resolver: Resolver,
28 file_id: HirFileId,
29 owner: DefWithBody,
30 params: Option<ast::ParamList>,
31 body: Option<ast::Expr>,
32) -> (Body, BodySourceMap) {
33 ExprCollector {
34 resolver,
35 db,
36 original_file_id: file_id,
37 current_file_id: file_id,
38 source_map: BodySourceMap::default(),
39 body: Body {
40 owner,
41 exprs: Arena::default(),
42 pats: Arena::default(),
43 params: Vec::new(),
44 body_expr: ExprId((!0).into()),
45 },
46 }
47 .collect(params, body)
48}
49
50struct ExprCollector<DB> {
51 db: DB,
52 resolver: Resolver,
53 // Expr collector expands macros along the way. original points to the file
54 // we started with, current points to the current macro expansion. source
55 // maps don't support macros yet, so we only record info into source map if
56 // current == original (see #1196)
57 original_file_id: HirFileId,
58 current_file_id: HirFileId,
59
60 body: Body,
61 source_map: BodySourceMap,
62}
63
64impl<'a, DB> ExprCollector<&'a DB>
65where
66 DB: HirDatabase,
67{
68 fn collect(
69 mut self,
70 param_list: Option<ast::ParamList>,
71 body: Option<ast::Expr>,
72 ) -> (Body, BodySourceMap) {
73 if let Some(param_list) = param_list {
74 if let Some(self_param) = param_list.self_param() {
75 let ptr = AstPtr::new(&self_param);
76 let param_pat = self.alloc_pat(
77 Pat::Bind {
78 name: SELF_PARAM,
79 mode: BindingAnnotation::Unannotated,
80 subpat: None,
81 },
82 Either::B(ptr),
83 );
84 self.body.params.push(param_pat);
85 }
86
87 for param in param_list.params() {
88 let pat = match param.pat() {
89 None => continue,
90 Some(pat) => pat,
91 };
92 let param_pat = self.collect_pat(pat);
93 self.body.params.push(param_pat);
94 }
95 };
96
97 self.body.body_expr = self.collect_expr_opt(body);
98 (self.body, self.source_map)
99 }
100
101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
102 let ptr = Either::A(ptr);
103 let id = self.body.exprs.alloc(expr);
104 if self.current_file_id == self.original_file_id {
105 self.source_map.expr_map.insert(ptr, id);
106 }
107 self.source_map
108 .expr_map_back
109 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
110 id
111 }
112 // desugared exprs don't have ptr, that's wrong and should be fixed
113 // somehow.
114 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
115 self.body.exprs.alloc(expr)
116 }
117 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
118 let ptr = Either::B(ptr);
119 let id = self.body.exprs.alloc(expr);
120 if self.current_file_id == self.original_file_id {
121 self.source_map.expr_map.insert(ptr, id);
122 }
123 self.source_map
124 .expr_map_back
125 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
126 id
127 }
128 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
129 let id = self.body.pats.alloc(pat);
130 if self.current_file_id == self.original_file_id {
131 self.source_map.pat_map.insert(ptr, id);
132 }
133 self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
134 id
135 }
136
137 fn empty_block(&mut self) -> ExprId {
138 let block = Expr::Block { statements: Vec::new(), tail: None };
139 self.body.exprs.alloc(block)
140 }
141
142 fn missing_expr(&mut self) -> ExprId {
143 self.body.exprs.alloc(Expr::Missing)
144 }
145
146 fn missing_pat(&mut self) -> PatId {
147 self.body.pats.alloc(Pat::Missing)
148 }
149
150 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
151 let syntax_ptr = AstPtr::new(&expr);
152 match expr {
153 ast::Expr::IfExpr(e) => {
154 let then_branch = self.collect_block_opt(e.then_branch());
155
156 let else_branch = e.else_branch().map(|b| match b {
157 ast::ElseBranch::Block(it) => self.collect_block(it),
158 ast::ElseBranch::IfExpr(elif) => {
159 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
160 self.collect_expr(expr)
161 }
162 });
163
164 let condition = match e.condition() {
165 None => self.missing_expr(),
166 Some(condition) => match condition.pat() {
167 None => self.collect_expr_opt(condition.expr()),
168 // if let -- desugar to match
169 Some(pat) => {
170 let pat = self.collect_pat(pat);
171 let match_expr = self.collect_expr_opt(condition.expr());
172 let placeholder_pat = self.missing_pat();
173 let arms = vec![
174 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
175 MatchArm {
176 pats: vec![placeholder_pat],
177 expr: else_branch.unwrap_or_else(|| self.empty_block()),
178 guard: None,
179 },
180 ];
181 return self
182 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
183 }
184 },
185 };
186
187 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
188 }
189 ast::Expr::TryBlockExpr(e) => {
190 let body = self.collect_block_opt(e.body());
191 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
192 }
193 ast::Expr::BlockExpr(e) => self.collect_block(e),
194 ast::Expr::LoopExpr(e) => {
195 let body = self.collect_block_opt(e.loop_body());
196 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
197 }
198 ast::Expr::WhileExpr(e) => {
199 let body = self.collect_block_opt(e.loop_body());
200
201 let condition = match e.condition() {
202 None => self.missing_expr(),
203 Some(condition) => match condition.pat() {
204 None => self.collect_expr_opt(condition.expr()),
205 // if let -- desugar to match
206 Some(pat) => {
207 tested_by!(infer_while_let);
208 let pat = self.collect_pat(pat);
209 let match_expr = self.collect_expr_opt(condition.expr());
210 let placeholder_pat = self.missing_pat();
211 let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
212 let arms = vec![
213 MatchArm { pats: vec![pat], expr: body, guard: None },
214 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
215 ];
216 let match_expr =
217 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
218 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
219 }
220 },
221 };
222
223 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
224 }
225 ast::Expr::ForExpr(e) => {
226 let iterable = self.collect_expr_opt(e.iterable());
227 let pat = self.collect_pat_opt(e.pat());
228 let body = self.collect_block_opt(e.loop_body());
229 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
230 }
231 ast::Expr::CallExpr(e) => {
232 let callee = self.collect_expr_opt(e.expr());
233 let args = if let Some(arg_list) = e.arg_list() {
234 arg_list.args().map(|e| self.collect_expr(e)).collect()
235 } else {
236 Vec::new()
237 };
238 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
239 }
240 ast::Expr::MethodCallExpr(e) => {
241 let receiver = self.collect_expr_opt(e.expr());
242 let args = if let Some(arg_list) = e.arg_list() {
243 arg_list.args().map(|e| self.collect_expr(e)).collect()
244 } else {
245 Vec::new()
246 };
247 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
248 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
249 self.alloc_expr(
250 Expr::MethodCall { receiver, method_name, args, generic_args },
251 syntax_ptr,
252 )
253 }
254 ast::Expr::MatchExpr(e) => {
255 let expr = self.collect_expr_opt(e.expr());
256 let arms = if let Some(match_arm_list) = e.match_arm_list() {
257 match_arm_list
258 .arms()
259 .map(|arm| MatchArm {
260 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
261 expr: self.collect_expr_opt(arm.expr()),
262 guard: arm
263 .guard()
264 .and_then(|guard| guard.expr())
265 .map(|e| self.collect_expr(e)),
266 })
267 .collect()
268 } else {
269 Vec::new()
270 };
271 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
272 }
273 ast::Expr::PathExpr(e) => {
274 let path =
275 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
276 self.alloc_expr(path, syntax_ptr)
277 }
278 ast::Expr::ContinueExpr(_e) => {
279 // FIXME: labels
280 self.alloc_expr(Expr::Continue, syntax_ptr)
281 }
282 ast::Expr::BreakExpr(e) => {
283 let expr = e.expr().map(|e| self.collect_expr(e));
284 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
285 }
286 ast::Expr::ParenExpr(e) => {
287 let inner = self.collect_expr_opt(e.expr());
288 // make the paren expr point to the inner expression as well
289 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
290 inner
291 }
292 ast::Expr::ReturnExpr(e) => {
293 let expr = e.expr().map(|e| self.collect_expr(e));
294 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
295 }
296 ast::Expr::RecordLit(e) => {
297 let path = e.path().and_then(Path::from_ast);
298 let mut field_ptrs = Vec::new();
299 let record_lit = if let Some(nfl) = e.record_field_list() {
300 let fields = nfl
301 .fields()
302 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
303 .map(|field| RecordLitField {
304 name: field
305 .name_ref()
306 .map(|nr| nr.as_name())
307 .unwrap_or_else(Name::missing),
308 expr: if let Some(e) = field.expr() {
309 self.collect_expr(e)
310 } else if let Some(nr) = field.name_ref() {
311 // field shorthand
312 self.alloc_expr_field_shorthand(
313 Expr::Path(Path::from_name_ref(&nr)),
314 AstPtr::new(&field),
315 )
316 } else {
317 self.missing_expr()
318 },
319 })
320 .collect();
321 let spread = nfl.spread().map(|s| self.collect_expr(s));
322 Expr::RecordLit { path, fields, spread }
323 } else {
324 Expr::RecordLit { path, fields: Vec::new(), spread: None }
325 };
326
327 let res = self.alloc_expr(record_lit, syntax_ptr);
328 for (i, ptr) in field_ptrs.into_iter().enumerate() {
329 self.source_map.field_map.insert((res, i), ptr);
330 }
331 res
332 }
333 ast::Expr::FieldExpr(e) => {
334 let expr = self.collect_expr_opt(e.expr());
335 let name = match e.field_access() {
336 Some(kind) => kind.as_name(),
337 _ => Name::missing(),
338 };
339 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
340 }
341 ast::Expr::AwaitExpr(e) => {
342 let expr = self.collect_expr_opt(e.expr());
343 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
344 }
345 ast::Expr::TryExpr(e) => {
346 let expr = self.collect_expr_opt(e.expr());
347 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
348 }
349 ast::Expr::CastExpr(e) => {
350 let expr = self.collect_expr_opt(e.expr());
351 let type_ref = TypeRef::from_ast_opt(e.type_ref());
352 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
353 }
354 ast::Expr::RefExpr(e) => {
355 let expr = self.collect_expr_opt(e.expr());
356 let mutability = Mutability::from_mutable(e.is_mut());
357 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
358 }
359 ast::Expr::PrefixExpr(e) => {
360 let expr = self.collect_expr_opt(e.expr());
361 if let Some(op) = e.op_kind() {
362 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
363 } else {
364 self.alloc_expr(Expr::Missing, syntax_ptr)
365 }
366 }
367 ast::Expr::LambdaExpr(e) => {
368 let mut args = Vec::new();
369 let mut arg_types = Vec::new();
370 if let Some(pl) = e.param_list() {
371 for param in pl.params() {
372 let pat = self.collect_pat_opt(param.pat());
373 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
374 args.push(pat);
375 arg_types.push(type_ref);
376 }
377 }
378 let body = self.collect_expr_opt(e.body());
379 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
380 }
381 ast::Expr::BinExpr(e) => {
382 let lhs = self.collect_expr_opt(e.lhs());
383 let rhs = self.collect_expr_opt(e.rhs());
384 let op = e.op_kind().map(BinaryOp::from);
385 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
386 }
387 ast::Expr::TupleExpr(e) => {
388 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
389 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
390 }
391
392 ast::Expr::ArrayExpr(e) => {
393 let kind = e.kind();
394
395 match kind {
396 ArrayExprKind::ElementList(e) => {
397 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
398 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
399 }
400 ArrayExprKind::Repeat { initializer, repeat } => {
401 let initializer = self.collect_expr_opt(initializer);
402 let repeat = self.collect_expr_opt(repeat);
403 self.alloc_expr(
404 Expr::Array(Array::Repeat { initializer, repeat }),
405 syntax_ptr,
406 )
407 }
408 }
409 }
410
411 ast::Expr::Literal(e) => {
412 let lit = match e.kind() {
413 LiteralKind::IntNumber { suffix } => {
414 let known_name = suffix
415 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
416
417 Literal::Int(
418 Default::default(),
419 known_name.unwrap_or(UncertainIntTy::Unknown),
420 )
421 }
422 LiteralKind::FloatNumber { suffix } => {
423 let known_name = suffix
424 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
425
426 Literal::Float(
427 Default::default(),
428 known_name.unwrap_or(UncertainFloatTy::Unknown),
429 )
430 }
431 LiteralKind::ByteString => Literal::ByteString(Default::default()),
432 LiteralKind::String => Literal::String(Default::default()),
433 LiteralKind::Byte => {
434 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
435 }
436 LiteralKind::Bool => Literal::Bool(Default::default()),
437 LiteralKind::Char => Literal::Char(Default::default()),
438 };
439 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
440 }
441 ast::Expr::IndexExpr(e) => {
442 let base = self.collect_expr_opt(e.base());
443 let index = self.collect_expr_opt(e.index());
444 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
445 }
446
447 // FIXME implement HIR for these:
448 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
449 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
450 ast::Expr::MacroCall(e) => {
451 let ast_id = self
452 .db
453 .ast_id_map(self.current_file_id)
454 .ast_id(&e)
455 .with_file_id(self.current_file_id);
456
457 if let Some(path) = e.path().and_then(Path::from_ast) {
458 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
459 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
460 let file_id = call_id.as_file(MacroFileKind::Expr);
461 if let Some(node) = self.db.parse_or_expand(file_id) {
462 if let Some(expr) = ast::Expr::cast(node) {
463 log::debug!("macro expansion {:#?}", expr.syntax());
464 let old_file_id =
465 std::mem::replace(&mut self.current_file_id, file_id);
466 let id = self.collect_expr(expr);
467 self.current_file_id = old_file_id;
468 return id;
469 }
470 }
471 }
472 }
473 // FIXME: Instead of just dropping the error from expansion
474 // report it
475 self.alloc_expr(Expr::Missing, syntax_ptr)
476 }
477 }
478 }
479
480 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
481 if let Some(expr) = expr {
482 self.collect_expr(expr)
483 } else {
484 self.missing_expr()
485 }
486 }
487
488 fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
489 let syntax_node_ptr = AstPtr::new(&expr.clone().into());
490 let block = match expr.block() {
491 Some(block) => block,
492 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
493 };
494 let statements = block
495 .statements()
496 .map(|s| match s {
497 ast::Stmt::LetStmt(stmt) => {
498 let pat = self.collect_pat_opt(stmt.pat());
499 let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
500 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
501 Statement::Let { pat, type_ref, initializer }
502 }
503 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
504 })
505 .collect();
506 let tail = block.expr().map(|e| self.collect_expr(e));
507 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
508 }
509
510 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
511 if let Some(block) = expr {
512 self.collect_block(block)
513 } else {
514 self.missing_expr()
515 }
516 }
517
518 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
519 let pattern = match &pat {
520 ast::Pat::BindPat(bp) => {
521 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
522 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
523 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
524 Pat::Bind { name, mode: annotation, subpat }
525 }
526 ast::Pat::TupleStructPat(p) => {
527 let path = p.path().and_then(Path::from_ast);
528 let args = p.args().map(|p| self.collect_pat(p)).collect();
529 Pat::TupleStruct { path, args }
530 }
531 ast::Pat::RefPat(p) => {
532 let pat = self.collect_pat_opt(p.pat());
533 let mutability = Mutability::from_mutable(p.is_mut());
534 Pat::Ref { pat, mutability }
535 }
536 ast::Pat::PathPat(p) => {
537 let path = p.path().and_then(Path::from_ast);
538 path.map(Pat::Path).unwrap_or(Pat::Missing)
539 }
540 ast::Pat::TuplePat(p) => {
541 let args = p.args().map(|p| self.collect_pat(p)).collect();
542 Pat::Tuple(args)
543 }
544 ast::Pat::PlaceholderPat(_) => Pat::Wild,
545 ast::Pat::RecordPat(p) => {
546 let path = p.path().and_then(Path::from_ast);
547 let record_field_pat_list =
548 p.record_field_pat_list().expect("every struct should have a field list");
549 let mut fields: Vec<_> = record_field_pat_list
550 .bind_pats()
551 .filter_map(|bind_pat| {
552 let ast_pat =
553 ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
554 let pat = self.collect_pat(ast_pat);
555 let name = bind_pat.name()?.as_name();
556 Some(RecordFieldPat { name, pat })
557 })
558 .collect();
559 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
560 let ast_pat = f.pat()?;
561 let pat = self.collect_pat(ast_pat);
562 let name = f.name()?.as_name();
563 Some(RecordFieldPat { name, pat })
564 });
565 fields.extend(iter);
566
567 Pat::Record { path, args: fields }
568 }
569
570 // FIXME: implement
571 ast::Pat::BoxPat(_) => Pat::Missing,
572 ast::Pat::LiteralPat(_) => Pat::Missing,
573 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
574 };
575 let ptr = AstPtr::new(&pat);
576 self.alloc_pat(pattern, Either::A(ptr))
577 }
578
579 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
580 if let Some(pat) = pat {
581 self.collect_pat(pat)
582 } else {
583 self.missing_pat()
584 }
585 }
586}
587
588impl From<ast::BinOp> for BinaryOp {
589 fn from(ast_op: ast::BinOp) -> Self {
590 match ast_op {
591 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
592 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
593 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
594 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
595 ast::BinOp::LesserEqualTest => {
596 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
597 }
598 ast::BinOp::GreaterEqualTest => {
599 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
600 }
601 ast::BinOp::LesserTest => {
602 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
603 }
604 ast::BinOp::GreaterTest => {
605 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
606 }
607 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
608 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
609 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
610 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
611 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
612 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
613 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
614 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
615 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
616 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
617 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
618 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
619 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
620 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
621 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
622 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
623 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
624 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
625 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
626 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
627 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
628 }
629 }
630}
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 79e1857f9..b6d7f3fc1 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -172,7 +172,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
172#[cfg(test)] 172#[cfg(test)]
173mod tests { 173mod tests {
174 use ra_db::SourceDatabase; 174 use ra_db::SourceDatabase;
175 use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNodePtr}; 175 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
176 use test_utils::{assert_eq_text, extract_offset}; 176 use test_utils::{assert_eq_text, extract_offset};
177 177
178 use crate::{mock::MockDatabase, source_binder::SourceAnalyzer}; 178 use crate::{mock::MockDatabase, source_binder::SourceAnalyzer};
@@ -194,8 +194,7 @@ mod tests {
194 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); 194 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
195 195
196 let scopes = analyzer.scopes(); 196 let scopes = analyzer.scopes();
197 let expr_id = 197 let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap();
198 analyzer.body_source_map().syntax_expr(SyntaxNodePtr::new(marker.syntax())).unwrap();
199 let scope = scopes.scope_for(expr_id); 198 let scope = scopes.scope_for(expr_id);
200 199
201 let actual = scopes 200 let actual = scopes
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index c8ae19869..1202913e2 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -1,9 +1,8 @@
1use rustc_hash::FxHashSet;
2use std::sync::Arc; 1use std::sync::Arc;
3 2
4use ra_syntax::ast::{AstNode, RecordLit}; 3use ra_syntax::ast;
4use rustc_hash::FxHashSet;
5 5
6use super::{Expr, ExprId, RecordLitField};
7use crate::{ 6use crate::{
8 adt::AdtDef, 7 adt::AdtDef,
9 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 8 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
@@ -11,9 +10,10 @@ use crate::{
11 name, 10 name,
12 path::{PathKind, PathSegment}, 11 path::{PathKind, PathSegment},
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 12 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, 13 Function, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
15}; 14};
16use ra_syntax::ast; 15
16use super::{Expr, ExprId, RecordLitField};
17 17
18pub(crate) struct ExprValidator<'a, 'b: 'a> { 18pub(crate) struct ExprValidator<'a, 'b: 'a> {
19 func: Function, 19 func: Function,
@@ -79,21 +79,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
79 return; 79 return;
80 } 80 }
81 let source_map = self.func.body_source_map(db); 81 let source_map = self.func.body_source_map(db);
82 let file_id = self.func.source(db).file_id; 82
83 let parse = db.parse(file_id.original_file(db)); 83 if let Some(source_ptr) = source_map.expr_syntax(id) {
84 let source_file = parse.tree(); 84 if let Some(expr) = source_ptr.ast.a() {
85 if let Some(field_list_node) = source_map 85 let root = source_ptr.file_syntax(db);
86 .expr_syntax(id) 86 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
87 .map(|ptr| ptr.to_node(source_file.syntax())) 87 if let Some(field_list) = record_lit.record_field_list() {
88 .and_then(RecordLit::cast) 88 self.sink.push(MissingFields {
89 .and_then(|lit| lit.record_field_list()) 89 file: source_ptr.file_id,
90 { 90 field_list: AstPtr::new(&field_list),
91 let field_list_ptr = AstPtr::new(&field_list_node); 91 missed_fields,
92 self.sink.push(MissingFields { 92 })
93 file: file_id, 93 }
94 field_list: field_list_ptr, 94 }
95 missed_fields, 95 }
96 })
97 } 96 }
98 } 97 }
99 98
@@ -133,10 +132,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
133 132
134 if params.len() == 2 && &params[0] == &mismatch.actual { 133 if params.len() == 2 && &params[0] == &mismatch.actual {
135 let source_map = self.func.body_source_map(db); 134 let source_map = self.func.body_source_map(db);
136 let file_id = self.func.source(db).file_id;
137 135
138 if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) { 136 if let Some(source_ptr) = source_map.expr_syntax(id) {
139 self.sink.push(MissingOkInTailExpr { file: file_id, expr }); 137 if let Some(expr) = source_ptr.ast.a() {
138 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
139 }
140 } 140 }
141 } 141 }
142 } 142 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 018fcd096..c3e589921 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -69,14 +69,16 @@ pub use self::{
69 resolve::Resolution, 69 resolve::Resolution,
70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
71 source_id::{AstIdMap, ErasedFileAstId}, 71 source_id::{AstIdMap, ErasedFileAstId},
72 ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, 72 ty::{
73 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
74 },
73 type_ref::Mutability, 75 type_ref::Mutability,
74}; 76};
75 77
76pub use self::code_model::{ 78pub use self::code_model::{
77 docs::{DocDef, Docs, Documentation}, 79 docs::{DocDef, Docs, Documentation},
78 src::{HasSource, Source}, 80 src::{HasBodySource, HasSource, Source},
79 BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 81 BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
80 EnumVariant, FieldSource, FnData, Function, MacroDef, Module, ModuleDef, ModuleSource, Static, 82 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, ModuleSource,
81 Struct, StructField, Trait, TypeAlias, Union, 83 Static, Struct, StructField, Trait, TypeAlias, Union,
82}; 84};
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 5ee71e421..24316fc91 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -31,7 +31,8 @@ pub struct GenericArgs {
31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type 31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
32 /// is left out. 32 /// is left out.
33 pub has_self_type: bool, 33 pub has_self_type: bool,
34 // someday also bindings 34 /// Associated type bindings like in `Iterator<Item = T>`.
35 pub bindings: Vec<(Name, TypeRef)>,
35} 36}
36 37
37/// A single generic argument. 38/// A single generic argument.
@@ -170,16 +171,24 @@ impl GenericArgs {
170 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 171 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
171 args.push(GenericArg::Type(type_ref)); 172 args.push(GenericArg::Type(type_ref));
172 } 173 }
173 // lifetimes and assoc type args ignored for now 174 // lifetimes ignored for now
174 if !args.is_empty() { 175 let mut bindings = Vec::new();
175 Some(GenericArgs { args, has_self_type: false }) 176 for assoc_type_arg in node.assoc_type_args() {
176 } else { 177 if let Some(name_ref) = assoc_type_arg.name_ref() {
178 let name = name_ref.as_name();
179 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
180 bindings.push((name, type_ref));
181 }
182 }
183 if args.is_empty() && bindings.is_empty() {
177 None 184 None
185 } else {
186 Some(GenericArgs { args, has_self_type: false, bindings })
178 } 187 }
179 } 188 }
180 189
181 pub(crate) fn empty() -> GenericArgs { 190 pub(crate) fn empty() -> GenericArgs {
182 GenericArgs { args: Vec::new(), has_self_type: false } 191 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
183 } 192 }
184} 193}
185 194
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 56ff7da3a..fdbe5e8b0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -27,9 +27,9 @@ use crate::{
27 name, 27 name,
28 path::{PathKind, PathSegment}, 28 path::{PathKind, PathSegment},
29 ty::method_resolution::implements_trait, 29 ty::method_resolution::implements_trait,
30 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, 30 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirDatabase,
31 MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, 31 HirFileId, MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static,
32 Ty, 32 Struct, Trait, Ty,
33}; 33};
34 34
35/// Locates the module by `FileId`. Picks topmost module in the file. 35/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -228,7 +228,7 @@ impl SourceAnalyzer {
228 let scopes = db.expr_scopes(def); 228 let scopes = db.expr_scopes(def);
229 let scope = match offset { 229 let scope = match offset {
230 None => scope_for(&scopes, &source_map, &node), 230 None => scope_for(&scopes, &source_map, &node),
231 Some(offset) => scope_for_offset(&scopes, &source_map, offset), 231 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
232 }; 232 };
233 let resolver = expr::resolver_for_scope(def.body(db), db, scope); 233 let resolver = expr::resolver_for_scope(def.body(db), db, scope);
234 SourceAnalyzer { 234 SourceAnalyzer {
@@ -330,6 +330,7 @@ impl SourceAnalyzer {
330 .body_source_map 330 .body_source_map
331 .as_ref()? 331 .as_ref()?
332 .pat_syntax(it)? 332 .pat_syntax(it)?
333 .ast // FIXME: ignoring file_id here is definitelly wrong
333 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); 334 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
334 PathResolution::LocalBinding(pat_ptr) 335 PathResolution::LocalBinding(pat_ptr)
335 } 336 }
@@ -354,7 +355,7 @@ impl SourceAnalyzer {
354 ret.and_then(|entry| { 355 ret.and_then(|entry| {
355 Some(ScopeEntryWithSyntax { 356 Some(ScopeEntryWithSyntax {
356 name: entry.name().clone(), 357 name: entry.name().clone(),
357 ptr: source_map.pat_syntax(entry.pat())?, 358 ptr: source_map.pat_syntax(entry.pat())?.ast,
358 }) 359 })
359 }) 360 })
360 } 361 }
@@ -462,25 +463,35 @@ fn scope_for(
462 node: &SyntaxNode, 463 node: &SyntaxNode,
463) -> Option<ScopeId> { 464) -> Option<ScopeId> {
464 node.ancestors() 465 node.ancestors()
465 .map(|it| SyntaxNodePtr::new(&it)) 466 .filter_map(ast::Expr::cast)
466 .filter_map(|ptr| source_map.syntax_expr(ptr)) 467 .filter_map(|it| source_map.node_expr(&it))
467 .find_map(|it| scopes.scope_for(it)) 468 .find_map(|it| scopes.scope_for(it))
468} 469}
469 470
470fn scope_for_offset( 471fn scope_for_offset(
471 scopes: &ExprScopes, 472 scopes: &ExprScopes,
472 source_map: &BodySourceMap, 473 source_map: &BodySourceMap,
474 file_id: HirFileId,
473 offset: TextUnit, 475 offset: TextUnit,
474) -> Option<ScopeId> { 476) -> Option<ScopeId> {
475 scopes 477 scopes
476 .scope_by_expr() 478 .scope_by_expr()
477 .iter() 479 .iter()
478 .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) 480 .filter_map(|(id, scope)| {
481 let source = source_map.expr_syntax(*id)?;
482 // FIXME: correctly handle macro expansion
483 if source.file_id != file_id {
484 return None;
485 }
486 let syntax_node_ptr =
487 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
488 Some((syntax_node_ptr, scope))
489 })
479 // find containing scope 490 // find containing scope
480 .min_by_key(|(ptr, _scope)| { 491 .min_by_key(|(ptr, _scope)| {
481 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 492 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len())
482 }) 493 })
483 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) 494 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
484} 495}
485 496
486// XXX: during completion, cursor might be outside of any particular 497// XXX: during completion, cursor might be outside of any particular
@@ -489,13 +500,23 @@ fn adjust(
489 scopes: &ExprScopes, 500 scopes: &ExprScopes,
490 source_map: &BodySourceMap, 501 source_map: &BodySourceMap,
491 ptr: SyntaxNodePtr, 502 ptr: SyntaxNodePtr,
503 file_id: HirFileId,
492 offset: TextUnit, 504 offset: TextUnit,
493) -> Option<ScopeId> { 505) -> Option<ScopeId> {
494 let r = ptr.range(); 506 let r = ptr.range();
495 let child_scopes = scopes 507 let child_scopes = scopes
496 .scope_by_expr() 508 .scope_by_expr()
497 .iter() 509 .iter()
498 .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) 510 .filter_map(|(id, scope)| {
511 let source = source_map.expr_syntax(*id)?;
512 // FIXME: correctly handle macro expansion
513 if source.file_id != file_id {
514 return None;
515 }
516 let syntax_node_ptr =
517 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
518 Some((syntax_node_ptr, scope))
519 })
499 .map(|(ptr, scope)| (ptr.range(), scope)) 520 .map(|(ptr, scope)| (ptr.range(), scope))
500 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); 521 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
501 522
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index b54c80318..a3df08827 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -120,12 +120,44 @@ pub struct ProjectionTy {
120 pub parameters: Substs, 120 pub parameters: Substs,
121} 121}
122 122
123impl ProjectionTy {
124 pub fn trait_ref(&self, db: &impl HirDatabase) -> TraitRef {
125 TraitRef {
126 trait_: self
127 .associated_ty
128 .parent_trait(db)
129 .expect("projection ty without parent trait"),
130 substs: self.parameters.clone(),
131 }
132 }
133}
134
135impl TypeWalk for ProjectionTy {
136 fn walk(&self, f: &mut impl FnMut(&Ty)) {
137 self.parameters.walk(f);
138 }
139
140 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
141 self.parameters.walk_mut(f);
142 }
143}
144
123#[derive(Clone, PartialEq, Eq, Debug, Hash)] 145#[derive(Clone, PartialEq, Eq, Debug, Hash)]
124pub struct UnselectedProjectionTy { 146pub struct UnselectedProjectionTy {
125 pub type_name: Name, 147 pub type_name: Name,
126 pub parameters: Substs, 148 pub parameters: Substs,
127} 149}
128 150
151impl TypeWalk for UnselectedProjectionTy {
152 fn walk(&self, f: &mut impl FnMut(&Ty)) {
153 self.parameters.walk(f);
154 }
155
156 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
157 self.parameters.walk_mut(f);
158 }
159}
160
129/// A type. 161/// A type.
130/// 162///
131/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents 163/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@@ -282,20 +314,14 @@ impl TraitRef {
282 pub fn self_ty(&self) -> &Ty { 314 pub fn self_ty(&self) -> &Ty {
283 &self.substs[0] 315 &self.substs[0]
284 } 316 }
317}
285 318
286 pub fn subst(mut self, substs: &Substs) -> TraitRef { 319impl TypeWalk for TraitRef {
287 self.substs.walk_mut(&mut |ty_mut| { 320 fn walk(&self, f: &mut impl FnMut(&Ty)) {
288 let ty = mem::replace(ty_mut, Ty::Unknown);
289 *ty_mut = ty.subst(substs);
290 });
291 self
292 }
293
294 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
295 self.substs.walk(f); 321 self.substs.walk(f);
296 } 322 }
297 323
298 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 324 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
299 self.substs.walk_mut(f); 325 self.substs.walk_mut(f);
300 } 326 }
301} 327}
@@ -306,6 +332,8 @@ impl TraitRef {
306pub enum GenericPredicate { 332pub enum GenericPredicate {
307 /// The given trait needs to be implemented for its type parameters. 333 /// The given trait needs to be implemented for its type parameters.
308 Implemented(TraitRef), 334 Implemented(TraitRef),
335 /// An associated type bindings like in `Iterator<Item = T>`.
336 Projection(ProjectionPredicate),
309 /// We couldn't resolve the trait reference. (If some type parameters can't 337 /// We couldn't resolve the trait reference. (If some type parameters can't
310 /// be resolved, they will just be Unknown). 338 /// be resolved, they will just be Unknown).
311 Error, 339 Error,
@@ -319,25 +347,35 @@ impl GenericPredicate {
319 } 347 }
320 } 348 }
321 349
322 pub fn subst(self, substs: &Substs) -> GenericPredicate { 350 pub fn is_implemented(&self) -> bool {
323 match self { 351 match self {
324 GenericPredicate::Implemented(trait_ref) => { 352 GenericPredicate::Implemented(_) => true,
325 GenericPredicate::Implemented(trait_ref.subst(substs)) 353 _ => false,
326 }
327 GenericPredicate::Error => self,
328 } 354 }
329 } 355 }
330 356
331 pub fn walk(&self, f: &mut impl FnMut(&Ty)) { 357 pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
358 match self {
359 GenericPredicate::Implemented(tr) => Some(tr.clone()),
360 GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)),
361 GenericPredicate::Error => None,
362 }
363 }
364}
365
366impl TypeWalk for GenericPredicate {
367 fn walk(&self, f: &mut impl FnMut(&Ty)) {
332 match self { 368 match self {
333 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), 369 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
370 GenericPredicate::Projection(projection_pred) => projection_pred.walk(f),
334 GenericPredicate::Error => {} 371 GenericPredicate::Error => {}
335 } 372 }
336 } 373 }
337 374
338 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 375 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
339 match self { 376 match self {
340 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 377 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
378 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f),
341 GenericPredicate::Error => {} 379 GenericPredicate::Error => {}
342 } 380 }
343 } 381 }
@@ -378,16 +416,16 @@ impl FnSig {
378 pub fn ret(&self) -> &Ty { 416 pub fn ret(&self) -> &Ty {
379 &self.params_and_return[self.params_and_return.len() - 1] 417 &self.params_and_return[self.params_and_return.len() - 1]
380 } 418 }
419}
381 420
382 /// Applies the given substitutions to all types in this signature and 421impl TypeWalk for FnSig {
383 /// returns the result. 422 fn walk(&self, f: &mut impl FnMut(&Ty)) {
384 pub fn subst(&self, substs: &Substs) -> FnSig { 423 for t in self.params_and_return.iter() {
385 let result: Vec<_> = 424 t.walk(f);
386 self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); 425 }
387 FnSig { params_and_return: result.into() }
388 } 426 }
389 427
390 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 428 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
391 // Without an Arc::make_mut_slice, we can't avoid the clone here: 429 // Without an Arc::make_mut_slice, we can't avoid the clone here:
392 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); 430 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
393 for t in &mut v { 431 for t in &mut v {
@@ -411,64 +449,6 @@ impl Ty {
411 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 449 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
412 } 450 }
413 451
414 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
415 match self {
416 Ty::Apply(a_ty) => {
417 for t in a_ty.parameters.iter() {
418 t.walk(f);
419 }
420 }
421 Ty::Projection(p_ty) => {
422 for t in p_ty.parameters.iter() {
423 t.walk(f);
424 }
425 }
426 Ty::UnselectedProjection(p_ty) => {
427 for t in p_ty.parameters.iter() {
428 t.walk(f);
429 }
430 }
431 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
432 for p in predicates.iter() {
433 p.walk(f);
434 }
435 }
436 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
437 }
438 f(self);
439 }
440
441 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
442 match self {
443 Ty::Apply(a_ty) => {
444 a_ty.parameters.walk_mut(f);
445 }
446 Ty::Projection(p_ty) => {
447 p_ty.parameters.walk_mut(f);
448 }
449 Ty::UnselectedProjection(p_ty) => {
450 p_ty.parameters.walk_mut(f);
451 }
452 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
453 let mut v: Vec<_> = predicates.iter().cloned().collect();
454 for p in &mut v {
455 p.walk_mut(f);
456 }
457 *predicates = v.into();
458 }
459 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
460 }
461 f(self);
462 }
463
464 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
465 self.walk_mut(&mut |ty_mut| {
466 let ty = mem::replace(ty_mut, Ty::Unknown);
467 *ty_mut = f(ty);
468 });
469 self
470 }
471
472 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 452 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
473 match self { 453 match self {
474 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { 454 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
@@ -544,10 +524,53 @@ impl Ty {
544 } 524 }
545 } 525 }
546 526
527 /// Returns the type parameters of this type if it has some (i.e. is an ADT
528 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
529 pub fn substs(&self) -> Option<Substs> {
530 match self {
531 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
532 _ => None,
533 }
534 }
535
536 /// If this is an `impl Trait` or `dyn Trait`, returns that trait.
537 pub fn inherent_trait(&self) -> Option<Trait> {
538 match self {
539 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
540 predicates.iter().find_map(|pred| match pred {
541 GenericPredicate::Implemented(tr) => Some(tr.trait_),
542 _ => None,
543 })
544 }
545 _ => None,
546 }
547 }
548}
549
550/// This allows walking structures that contain types to do something with those
551/// types, similar to Chalk's `Fold` trait.
552pub trait TypeWalk {
553 fn walk(&self, f: &mut impl FnMut(&Ty));
554 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty));
555
556 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
557 where
558 Self: Sized,
559 {
560 self.walk_mut(&mut |ty_mut| {
561 let ty = mem::replace(ty_mut, Ty::Unknown);
562 *ty_mut = f(ty);
563 });
564 self
565 }
566
547 /// Replaces type parameters in this type using the given `Substs`. (So e.g. 567 /// Replaces type parameters in this type using the given `Substs`. (So e.g.
548 /// if `self` is `&[T]`, where type parameter T has index 0, and the 568 /// if `self` is `&[T]`, where type parameter T has index 0, and the
549 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) 569 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
550 pub fn subst(self, substs: &Substs) -> Ty { 570 fn subst(self, substs: &Substs) -> Self
571 where
572 Self: Sized,
573 {
551 self.fold(&mut |ty| match ty { 574 self.fold(&mut |ty| match ty {
552 Ty::Param { idx, name } => { 575 Ty::Param { idx, name } => {
553 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) 576 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
@@ -557,24 +580,21 @@ impl Ty {
557 } 580 }
558 581
559 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 582 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
560 pub fn subst_bound_vars(self, substs: &Substs) -> Ty { 583 fn subst_bound_vars(self, substs: &Substs) -> Self
584 where
585 Self: Sized,
586 {
561 self.fold(&mut |ty| match ty { 587 self.fold(&mut |ty| match ty {
562 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 588 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)),
563 ty => ty, 589 ty => ty,
564 }) 590 })
565 } 591 }
566 592
567 /// Returns the type parameters of this type if it has some (i.e. is an ADT
568 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
569 pub fn substs(&self) -> Option<Substs> {
570 match self {
571 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
572 _ => None,
573 }
574 }
575
576 /// Shifts up `Ty::Bound` vars by `n`. 593 /// Shifts up `Ty::Bound` vars by `n`.
577 pub fn shift_bound_vars(self, n: i32) -> Ty { 594 fn shift_bound_vars(self, n: i32) -> Self
595 where
596 Self: Sized,
597 {
578 self.fold(&mut |ty| match ty { 598 self.fold(&mut |ty| match ty {
579 Ty::Bound(idx) => { 599 Ty::Bound(idx) => {
580 assert!(idx as i32 >= -n); 600 assert!(idx as i32 >= -n);
@@ -583,18 +603,57 @@ impl Ty {
583 ty => ty, 603 ty => ty,
584 }) 604 })
585 } 605 }
606}
586 607
587 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 608impl TypeWalk for Ty {
588 pub fn inherent_trait(&self) -> Option<Trait> { 609 fn walk(&self, f: &mut impl FnMut(&Ty)) {
610 match self {
611 Ty::Apply(a_ty) => {
612 for t in a_ty.parameters.iter() {
613 t.walk(f);
614 }
615 }
616 Ty::Projection(p_ty) => {
617 for t in p_ty.parameters.iter() {
618 t.walk(f);
619 }
620 }
621 Ty::UnselectedProjection(p_ty) => {
622 for t in p_ty.parameters.iter() {
623 t.walk(f);
624 }
625 }
626 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
627 for p in predicates.iter() {
628 p.walk(f);
629 }
630 }
631 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
632 }
633 f(self);
634 }
635
636 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
589 match self { 637 match self {
638 Ty::Apply(a_ty) => {
639 a_ty.parameters.walk_mut(f);
640 }
641 Ty::Projection(p_ty) => {
642 p_ty.parameters.walk_mut(f);
643 }
644 Ty::UnselectedProjection(p_ty) => {
645 p_ty.parameters.walk_mut(f);
646 }
590 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 647 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
591 predicates.iter().find_map(|pred| match pred { 648 let mut v: Vec<_> = predicates.iter().cloned().collect();
592 GenericPredicate::Implemented(tr) => Some(tr.trait_), 649 for p in &mut v {
593 _ => None, 650 p.walk_mut(f);
594 }) 651 }
652 *predicates = v.into();
595 } 653 }
596 _ => None, 654 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
597 } 655 }
656 f(self);
598 } 657 }
599} 658}
600 659
@@ -742,20 +801,66 @@ impl HirDisplay for Ty {
742 Ty::Opaque(_) => write!(f, "impl ")?, 801 Ty::Opaque(_) => write!(f, "impl ")?,
743 _ => unreachable!(), 802 _ => unreachable!(),
744 }; 803 };
745 // looping by hand here just to format the bounds in a slightly nicer way 804 // Note: This code is written to produce nice results (i.e.
805 // corresponding to surface Rust) for types that can occur in
806 // actual Rust. It will have weird results if the predicates
807 // aren't as expected (i.e. self types = $0, projection
808 // predicates for a certain trait come after the Implemented
809 // predicate for that trait).
746 let mut first = true; 810 let mut first = true;
811 let mut angle_open = false;
747 for p in predicates.iter() { 812 for p in predicates.iter() {
748 if !first {
749 write!(f, " + ")?;
750 }
751 first = false;
752 match p { 813 match p {
753 // don't show the $0 self type
754 GenericPredicate::Implemented(trait_ref) => { 814 GenericPredicate::Implemented(trait_ref) => {
755 trait_ref.hir_fmt_ext(f, false)? 815 if angle_open {
816 write!(f, ">")?;
817 }
818 if !first {
819 write!(f, " + ")?;
820 }
821 // We assume that the self type is $0 (i.e. the
822 // existential) here, which is the only thing that's
823 // possible in actual Rust, and hence don't print it
824 write!(
825 f,
826 "{}",
827 trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing)
828 )?;
829 if trait_ref.substs.len() > 1 {
830 write!(f, "<")?;
831 f.write_joined(&trait_ref.substs[1..], ", ")?;
832 // there might be assoc type bindings, so we leave the angle brackets open
833 angle_open = true;
834 }
835 }
836 GenericPredicate::Projection(projection_pred) => {
837 // in types in actual Rust, these will always come
838 // after the corresponding Implemented predicate
839 if angle_open {
840 write!(f, ", ")?;
841 } else {
842 write!(f, "<")?;
843 angle_open = true;
844 }
845 let name = projection_pred.projection_ty.associated_ty.name(f.db);
846 write!(f, "{} = ", name)?;
847 projection_pred.ty.hir_fmt(f)?;
848 }
849 GenericPredicate::Error => {
850 if angle_open {
851 // impl Trait<X, {error}>
852 write!(f, ", ")?;
853 } else if !first {
854 // impl Trait + {error}
855 write!(f, " + ")?;
856 }
857 p.hir_fmt(f)?;
756 } 858 }
757 GenericPredicate::Error => p.hir_fmt(f)?,
758 } 859 }
860 first = false;
861 }
862 if angle_open {
863 write!(f, ">")?;
759 } 864 }
760 } 865 }
761 Ty::Unknown => write!(f, "{{unknown}}")?, 866 Ty::Unknown => write!(f, "{{unknown}}")?,
@@ -766,13 +871,12 @@ impl HirDisplay for Ty {
766} 871}
767 872
768impl TraitRef { 873impl TraitRef {
769 fn hir_fmt_ext( 874 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
770 &self, 875 self.substs[0].hir_fmt(f)?;
771 f: &mut HirFormatter<impl HirDatabase>, 876 if use_as {
772 with_self_ty: bool, 877 write!(f, " as ")?;
773 ) -> fmt::Result { 878 } else {
774 if with_self_ty { 879 write!(f, ": ")?;
775 write!(f, "{}: ", self.substs[0].display(f.db),)?;
776 } 880 }
777 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; 881 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
778 if self.substs.len() > 1 { 882 if self.substs.len() > 1 {
@@ -786,7 +890,7 @@ impl TraitRef {
786 890
787impl HirDisplay for TraitRef { 891impl HirDisplay for TraitRef {
788 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 892 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
789 self.hir_fmt_ext(f, true) 893 self.hir_fmt_ext(f, false)
790 } 894 }
791} 895}
792 896
@@ -800,6 +904,16 @@ impl HirDisplay for GenericPredicate {
800 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 904 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
801 match self { 905 match self {
802 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 906 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
907 GenericPredicate::Projection(projection_pred) => {
908 write!(f, "<")?;
909 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
910 write!(
911 f,
912 ">::{} = {}",
913 projection_pred.projection_ty.associated_ty.name(f.db),
914 projection_pred.ty.display(f.db)
915 )?;
916 }
803 GenericPredicate::Error => write!(f, "{{error}}")?, 917 GenericPredicate::Error => write!(f, "{{error}}")?,
804 } 918 }
805 Ok(()) 919 Ok(())
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 2535d4ae7..08f52a53b 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -7,7 +7,7 @@ use std::iter::successors;
7 7
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty}; 10use super::{traits::Solution, Canonical, Ty, TypeWalk};
11use crate::{HasGenericParams, HirDatabase, Name, Resolver}; 11use crate::{HasGenericParams, HirDatabase, Name, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 812990426..ec3b7ffef 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -30,7 +30,7 @@ use super::{
30 autoderef, lower, method_resolution, op, primitive, 30 autoderef, lower, method_resolution, op, primitive,
31 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 31 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, 32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef,
33 Ty, TypableDef, TypeCtor, 33 Ty, TypableDef, TypeCtor, TypeWalk,
34}; 34};
35use crate::{ 35use crate::{
36 adt::VariantDef, 36 adt::VariantDef,
@@ -50,8 +50,8 @@ use crate::{
50 }, 50 },
51 ty::infer::diagnostics::InferenceDiagnostic, 51 ty::infer::diagnostics::InferenceDiagnostic,
52 type_ref::{Mutability, TypeRef}, 52 type_ref::{Mutability, TypeRef},
53 AdtDef, ConstData, DefWithBody, FnData, Function, HirDatabase, ImplItem, ModuleDef, Name, Path, 53 AdtDef, ConstData, DefWithBody, FnData, Function, HasBody, HirDatabase, ImplItem, ModuleDef,
54 StructField, 54 Name, Path, StructField,
55}; 55};
56 56
57mod unify; 57mod unify;
@@ -749,7 +749,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
749 let is_non_ref_pat = match &body[pat] { 749 let is_non_ref_pat = match &body[pat] {
750 Pat::Tuple(..) 750 Pat::Tuple(..)
751 | Pat::TupleStruct { .. } 751 | Pat::TupleStruct { .. }
752 | Pat::Struct { .. } 752 | Pat::Record { .. }
753 | Pat::Range { .. } 753 | Pat::Range { .. }
754 | Pat::Slice { .. } => true, 754 | Pat::Slice { .. } => true,
755 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. 755 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
@@ -806,10 +806,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
806 let subty = self.infer_pat(*pat, expectation, default_bm); 806 let subty = self.infer_pat(*pat, expectation, default_bm);
807 Ty::apply_one(TypeCtor::Ref(*mutability), subty) 807 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
808 } 808 }
809 Pat::TupleStruct { path: ref p, args: ref subpats } => { 809 Pat::TupleStruct { path: p, args: subpats } => {
810 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) 810 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
811 } 811 }
812 Pat::Struct { path: ref p, args: ref fields } => { 812 Pat::Record { path: p, args: fields } => {
813 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) 813 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
814 } 814 }
815 Pat::Path(path) => { 815 Pat::Path(path) => {
@@ -817,7 +817,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
817 let resolver = self.resolver.clone(); 817 let resolver = self.resolver.clone();
818 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) 818 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
819 } 819 }
820 Pat::Bind { mode, name: _name, subpat } => { 820 Pat::Bind { mode, name: _, subpat } => {
821 let mode = if mode == &BindingAnnotation::Unannotated { 821 let mode = if mode == &BindingAnnotation::Unannotated {
822 default_bm 822 default_bm
823 } else { 823 } else {
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index e7e8825d1..9a0d2d8f9 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -3,7 +3,7 @@
3use super::{InferenceContext, Obligation}; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{ 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk,
7}; 7};
8 8
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 9impl<'a, D: HirDatabase> InferenceContext<'a, D> {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 47d161277..f6f0137cf 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,7 +8,10 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; 11use super::{
12 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
13 TypeWalk,
14};
12use crate::{ 15use crate::{
13 adt::VariantDef, 16 adt::VariantDef,
14 generics::HasGenericParams, 17 generics::HasGenericParams,
@@ -62,7 +65,9 @@ impl Ty {
62 let self_ty = Ty::Bound(0); 65 let self_ty = Ty::Bound(0);
63 let predicates = bounds 66 let predicates = bounds
64 .iter() 67 .iter()
65 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 68 .flat_map(|b| {
69 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
70 })
66 .collect::<Vec<_>>(); 71 .collect::<Vec<_>>();
67 Ty::Dyn(predicates.into()) 72 Ty::Dyn(predicates.into())
68 } 73 }
@@ -70,7 +75,9 @@ impl Ty {
70 let self_ty = Ty::Bound(0); 75 let self_ty = Ty::Bound(0);
71 let predicates = bounds 76 let predicates = bounds
72 .iter() 77 .iter()
73 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 78 .flat_map(|b| {
79 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
80 })
74 .collect::<Vec<_>>(); 81 .collect::<Vec<_>>();
75 Ty::Opaque(predicates.into()) 82 Ty::Opaque(predicates.into())
76 } 83 }
@@ -326,15 +333,6 @@ impl TraitRef {
326 TraitRef { trait_, substs } 333 TraitRef { trait_, substs }
327 } 334 }
328 335
329 pub(crate) fn from_where_predicate(
330 db: &impl HirDatabase,
331 resolver: &Resolver,
332 pred: &WherePredicate,
333 ) -> Option<TraitRef> {
334 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
335 TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
336 }
337
338 pub(crate) fn from_type_bound( 336 pub(crate) fn from_type_bound(
339 db: &impl HirDatabase, 337 db: &impl HirDatabase,
340 resolver: &Resolver, 338 resolver: &Resolver,
@@ -349,26 +347,58 @@ impl TraitRef {
349} 347}
350 348
351impl GenericPredicate { 349impl GenericPredicate {
352 pub(crate) fn from_where_predicate( 350 pub(crate) fn from_where_predicate<'a>(
353 db: &impl HirDatabase, 351 db: &'a impl HirDatabase,
354 resolver: &Resolver, 352 resolver: &'a Resolver,
355 where_predicate: &WherePredicate, 353 where_predicate: &'a WherePredicate,
356 ) -> GenericPredicate { 354 ) -> impl Iterator<Item = GenericPredicate> + 'a {
357 TraitRef::from_where_predicate(db, &resolver, where_predicate) 355 let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref);
358 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 356 GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty)
359 } 357 }
360 358
361 pub(crate) fn from_type_bound( 359 pub(crate) fn from_type_bound<'a>(
362 db: &impl HirDatabase, 360 db: &'a impl HirDatabase,
363 resolver: &Resolver, 361 resolver: &'a Resolver,
364 bound: &TypeBound, 362 bound: &'a TypeBound,
365 self_ty: Ty, 363 self_ty: Ty,
366 ) -> GenericPredicate { 364 ) -> impl Iterator<Item = GenericPredicate> + 'a {
367 TraitRef::from_type_bound(db, &resolver, bound, self_ty) 365 let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty);
368 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 366 iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented))
367 .chain(
368 trait_ref.into_iter().flat_map(move |tr| {
369 assoc_type_bindings_from_type_bound(db, resolver, bound, tr)
370 }),
371 )
369 } 372 }
370} 373}
371 374
375fn assoc_type_bindings_from_type_bound<'a>(
376 db: &'a impl HirDatabase,
377 resolver: &'a Resolver,
378 bound: &'a TypeBound,
379 trait_ref: TraitRef,
380) -> impl Iterator<Item = GenericPredicate> + 'a {
381 let last_segment = match bound {
382 TypeBound::Path(path) => path.segments.last(),
383 TypeBound::Error => None,
384 };
385 last_segment
386 .into_iter()
387 .flat_map(|segment| segment.args_and_bindings.iter())
388 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
389 .map(move |(name, type_ref)| {
390 let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) {
391 None => return GenericPredicate::Error,
392 Some(t) => t,
393 };
394 let projection_ty =
395 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
396 let ty = Ty::from_hir(db, resolver, type_ref);
397 let projection_predicate = ProjectionPredicate { projection_ty, ty };
398 GenericPredicate::Projection(projection_predicate)
399 })
400}
401
372/// Build the declared type of an item. This depends on the namespace; e.g. for 402/// Build the declared type of an item. This depends on the namespace; e.g. for
373/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 403/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
374/// the constructor function `(usize) -> Foo` which lives in the values 404/// the constructor function `(usize) -> Foo` which lives in the values
@@ -425,7 +455,7 @@ pub(crate) fn trait_env(
425) -> Arc<super::TraitEnvironment> { 455) -> Arc<super::TraitEnvironment> {
426 let predicates = resolver 456 let predicates = resolver
427 .where_predicates_in_scope() 457 .where_predicates_in_scope()
428 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 458 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
429 .collect::<Vec<_>>(); 459 .collect::<Vec<_>>();
430 460
431 Arc::new(super::TraitEnvironment { predicates }) 461 Arc::new(super::TraitEnvironment { predicates })
@@ -439,7 +469,7 @@ pub(crate) fn generic_predicates_query(
439 let resolver = def.resolver(db); 469 let resolver = def.resolver(db);
440 let predicates = resolver 470 let predicates = resolver
441 .where_predicates_in_scope() 471 .where_predicates_in_scope()
442 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 472 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
443 .collect::<Vec<_>>(); 473 .collect::<Vec<_>>();
444 predicates.into() 474 predicates.into()
445} 475}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index b034fd59e..d92d4659b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2793,6 +2793,10 @@ fn main() {
2793} 2793}
2794"#), 2794"#),
2795 @r###" 2795 @r###"
2796 ![0; 17) '{Foo(v...,2,])}': Foo
2797 ![1; 4) 'Foo': Foo({unknown}) -> Foo
2798 ![1; 16) 'Foo(vec![1,2,])': Foo
2799 ![5; 15) 'vec![1,2,]': {unknown}
2796 [156; 182) '{ ...,2); }': () 2800 [156; 182) '{ ...,2); }': ()
2797 [166; 167) 'x': Foo 2801 [166; 167) 'x': Foo
2798 "### 2802 "###
@@ -3548,6 +3552,97 @@ fn test() {
3548 ); 3552 );
3549} 3553}
3550 3554
3555#[test]
3556fn assoc_type_bindings() {
3557 assert_snapshot!(
3558 infer(r#"
3559trait Trait {
3560 type Type;
3561}
3562
3563fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
3564fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
3565fn set<T: Trait<Type = u64>>(t: T) -> T {t}
3566
3567struct S<T>;
3568impl<T> Trait for S<T> { type Type = T; }
3569
3570fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
3571 get(x);
3572 get2(x);
3573 get(y);
3574 get2(y);
3575 get(set(S));
3576 get2(set(S));
3577 get2(S::<str>);
3578}
3579"#),
3580 @r###"
3581 [50; 51) 't': T
3582 [78; 80) '{}': ()
3583 [112; 113) 't': T
3584 [123; 125) '{}': ()
3585 [155; 156) 't': T
3586 [166; 169) '{t}': T
3587 [167; 168) 't': T
3588 [257; 258) 'x': T
3589 [263; 264) 'y': impl Trait<Type = i64>
3590 [290; 398) '{ ...r>); }': ()
3591 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
3592 [296; 302) 'get(x)': {unknown}
3593 [300; 301) 'x': T
3594 [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
3595 [308; 315) 'get2(x)': {unknown}
3596 [313; 314) 'x': T
3597 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
3598 [321; 327) 'get(y)': {unknown}
3599 [325; 326) 'y': impl Trait<Type = i64>
3600 [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
3601 [333; 340) 'get2(y)': {unknown}
3602 [338; 339) 'y': impl Trait<Type = i64>
3603 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
3604 [346; 357) 'get(set(S))': u64
3605 [350; 353) 'set': fn set<S<u64>>(T) -> T
3606 [350; 356) 'set(S)': S<u64>
3607 [354; 355) 'S': S<u64>
3608 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
3609 [363; 375) 'get2(set(S))': u64
3610 [368; 371) 'set': fn set<S<u64>>(T) -> T
3611 [368; 374) 'set(S)': S<u64>
3612 [372; 373) 'S': S<u64>
3613 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
3614 [381; 395) 'get2(S::<str>)': str
3615 [386; 394) 'S::<str>': S<str>
3616 "###
3617 );
3618}
3619
3620#[test]
3621fn projection_eq_within_chalk() {
3622 // std::env::set_var("CHALK_DEBUG", "1");
3623 assert_snapshot!(
3624 infer(r#"
3625trait Trait1 {
3626 type Type;
3627}
3628trait Trait2<T> {
3629 fn foo(self) -> T;
3630}
3631impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
3632
3633fn test<T: Trait1<Type = u32>>(x: T) {
3634 x.foo();
3635}
3636"#),
3637 @r###"
3638 [62; 66) 'self': Self
3639 [164; 165) 'x': T
3640 [170; 186) '{ ...o(); }': ()
3641 [176; 177) 'x': T
3642 [176; 183) 'x.foo()': {unknown}
3643 "###
3644 );
3645}
3551fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3646fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
3552 let file = db.parse(pos.file_id).ok().unwrap(); 3647 let file = db.parse(pos.file_id).ok().unwrap();
3553 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 3648 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
@@ -3566,7 +3661,6 @@ fn infer(content: &str) -> String {
3566 let source_file = db.parse(file_id).ok().unwrap(); 3661 let source_file = db.parse(file_id).ok().unwrap();
3567 3662
3568 let mut acc = String::new(); 3663 let mut acc = String::new();
3569 // acc.push_str("\n");
3570 3664
3571 let mut infer_def = |inference_result: Arc<InferenceResult>, 3665 let mut infer_def = |inference_result: Arc<InferenceResult>,
3572 body_source_map: Arc<BodySourceMap>| { 3666 body_source_map: Arc<BodySourceMap>| {
@@ -3574,7 +3668,9 @@ fn infer(content: &str) -> String {
3574 3668
3575 for (pat, ty) in inference_result.type_of_pat.iter() { 3669 for (pat, ty) in inference_result.type_of_pat.iter() {
3576 let syntax_ptr = match body_source_map.pat_syntax(pat) { 3670 let syntax_ptr = match body_source_map.pat_syntax(pat) {
3577 Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), 3671 Some(sp) => {
3672 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
3673 }
3578 None => continue, 3674 None => continue,
3579 }; 3675 };
3580 types.push((syntax_ptr, ty)); 3676 types.push((syntax_ptr, ty));
@@ -3582,22 +3678,34 @@ fn infer(content: &str) -> String {
3582 3678
3583 for (expr, ty) in inference_result.type_of_expr.iter() { 3679 for (expr, ty) in inference_result.type_of_expr.iter() {
3584 let syntax_ptr = match body_source_map.expr_syntax(expr) { 3680 let syntax_ptr = match body_source_map.expr_syntax(expr) {
3585 Some(sp) => sp, 3681 Some(sp) => {
3682 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
3683 }
3586 None => continue, 3684 None => continue,
3587 }; 3685 };
3588 types.push((syntax_ptr, ty)); 3686 types.push((syntax_ptr, ty));
3589 } 3687 }
3590 3688
3591 // sort ranges for consistency 3689 // sort ranges for consistency
3592 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); 3690 types.sort_by_key(|(src_ptr, _)| (src_ptr.ast.range().start(), src_ptr.ast.range().end()));
3593 for (syntax_ptr, ty) in &types { 3691 for (src_ptr, ty) in &types {
3594 let node = syntax_ptr.to_node(source_file.syntax()); 3692 let node = src_ptr.ast.to_node(&src_ptr.file_syntax(&db));
3693
3595 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { 3694 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
3596 (self_param.self_kw_token().text_range(), "self".to_string()) 3695 (self_param.self_kw_token().text_range(), "self".to_string())
3597 } else { 3696 } else {
3598 (syntax_ptr.range(), node.text().to_string().replace("\n", " ")) 3697 (src_ptr.ast.range(), node.text().to_string().replace("\n", " "))
3599 }; 3698 };
3600 write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); 3699 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
3700 write!(
3701 acc,
3702 "{}{} '{}': {}\n",
3703 macro_prefix,
3704 range,
3705 ellipsize(text, 15),
3706 ty.display(&db)
3707 )
3708 .unwrap();
3601 } 3709 }
3602 }; 3710 };
3603 3711
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index b634f0b79..6e0271a96 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -8,7 +8,7 @@ use ra_db::salsa;
8use ra_prof::profile; 8use ra_prof::profile;
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10 10
11use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; 11use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
12use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; 12use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
13 13
14use self::chalk::{from_chalk, ToChalk}; 14use self::chalk::{from_chalk, ToChalk};
@@ -124,6 +124,9 @@ impl Obligation {
124 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { 124 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> {
125 match predicate { 125 match predicate {
126 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), 126 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)),
127 GenericPredicate::Projection(projection_pred) => {
128 Some(Obligation::Projection(projection_pred))
129 }
127 GenericPredicate::Error => None, 130 GenericPredicate::Error => None,
128 } 131 }
129 } 132 }
@@ -135,6 +138,18 @@ pub struct ProjectionPredicate {
135 pub ty: Ty, 138 pub ty: Ty,
136} 139}
137 140
141impl TypeWalk for ProjectionPredicate {
142 fn walk(&self, f: &mut impl FnMut(&Ty)) {
143 self.projection_ty.walk(f);
144 self.ty.walk(f);
145 }
146
147 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
148 self.projection_ty.walk_mut(f);
149 self.ty.walk_mut(f);
150 }
151}
152
138/// Solve a trait goal using Chalk. 153/// Solve a trait goal using Chalk.
139pub(crate) fn trait_solve_query( 154pub(crate) fn trait_solve_query(
140 db: &impl HirDatabase, 155 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 2ebc06135..c201c5e50 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -19,6 +19,7 @@ use crate::{
19 ty::display::HirDisplay, 19 ty::display::HirDisplay,
20 ty::{ 20 ty::{
21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
22 TypeWalk,
22 }, 23 },
23 Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, 24 Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias,
24}; 25};
@@ -211,6 +212,13 @@ impl ToChalk for GenericPredicate {
211 GenericPredicate::Implemented(trait_ref) => { 212 GenericPredicate::Implemented(trait_ref) => {
212 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 213 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
213 } 214 }
215 GenericPredicate::Projection(projection_pred) => make_binders(
216 chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq {
217 projection: projection_pred.projection_ty.to_chalk(db),
218 ty: projection_pred.ty.to_chalk(db),
219 }),
220 0,
221 ),
214 GenericPredicate::Error => { 222 GenericPredicate::Error => {
215 let impossible_trait_ref = chalk_ir::TraitRef { 223 let impossible_trait_ref = chalk_ir::TraitRef {
216 trait_id: UNKNOWN_TRAIT, 224 trait_id: UNKNOWN_TRAIT,