diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model/src.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 693 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/lower.rs | 630 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 46 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 41 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 348 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 124 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 8 |
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 { | |||
510 | impl_froms!(DefWithBody: Function, Const, Static); | 510 | impl_froms!(DefWithBody: Function, Const, Static); |
511 | 511 | ||
512 | impl DefWithBody { | 512 | impl 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 | ||
523 | pub 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 | |||
529 | impl<T> HasBody for T | ||
530 | where | ||
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 | |||
546 | impl 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)] |
536 | pub struct Function { | 561 | pub 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 @@ | |||
1 | use ra_syntax::ast; | 1 | use ra_syntax::{ |
2 | ast::{self, AstNode}, | ||
3 | SyntaxNode, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{ | 6 | use 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)] | ||
9 | pub struct Source<T> { | 13 | pub 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 | ||
23 | impl<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. |
21 | impl Module { | 34 | impl 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 | |||
125 | pub trait HasBodySource: HasBody + HasSource | ||
126 | where | ||
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 | |||
142 | impl<T> HasBodySource for T | ||
143 | where | ||
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 @@ | |||
1 | use std::ops::Index; | 1 | pub(crate) mod lower; |
2 | use std::sync::Arc; | 2 | pub(crate) mod scope; |
3 | pub(crate) mod validation; | ||
3 | 4 | ||
4 | use rustc_hash::FxHashMap; | 5 | use std::{ops::Index, sync::Arc}; |
5 | 6 | ||
6 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 7 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
7 | use ra_syntax::{ | 8 | use ra_syntax::{ast, AstPtr}; |
8 | ast::{ | 9 | use rustc_hash::FxHashMap; |
9 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, | ||
10 | TryBlockBodyOwner, TypeAscriptionOwner, | ||
11 | }, | ||
12 | AstNode, AstPtr, SyntaxNodePtr, | ||
13 | }; | ||
14 | use test_utils::tested_by; | ||
15 | 10 | ||
16 | use crate::{ | 11 | use 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 | ||
25 | pub use self::scope::ExprScopes; | 18 | pub use self::scope::ExprScopes; |
26 | 19 | ||
27 | pub(crate) mod scope; | ||
28 | pub(crate) mod validation; | ||
29 | |||
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 20 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
31 | pub struct ExprId(RawId); | 21 | pub struct ExprId(RawId); |
32 | impl_arena_id!(ExprId); | 22 | impl_arena_id!(ExprId); |
33 | 23 | ||
24 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
25 | pub struct PatId(RawId); | ||
26 | impl_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)] |
36 | pub struct Body { | 30 | pub struct Body { |
@@ -49,22 +43,32 @@ pub struct Body { | |||
49 | body_expr: ExprId, | 43 | body_expr: ExprId, |
50 | } | 44 | } |
51 | 45 | ||
46 | type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
47 | type ExprSource = Source<ExprPtr>; | ||
48 | |||
49 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
50 | type 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)] |
58 | pub struct BodySourceMap { | 64 | pub 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 | ||
66 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
67 | |||
68 | impl Body { | 72 | impl 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 | ||
130 | impl BodySourceMap { | 134 | impl 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)] | ||
440 | pub struct PatId(RawId); | ||
441 | impl_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 | |||
543 | pub(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 | |||
560 | impl<'a, DB> ExprCollector<&'a DB> | ||
561 | where | ||
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 | |||
1091 | impl 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 | |||
1135 | pub(crate) fn body_with_source_map_query( | 538 | pub(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 @@ | |||
1 | use ra_arena::Arena; | ||
2 | use ra_syntax::{ | ||
3 | ast::{ | ||
4 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, | ||
5 | TypeAscriptionOwner, | ||
6 | }, | ||
7 | AstNode, AstPtr, | ||
8 | }; | ||
9 | use test_utils::tested_by; | ||
10 | |||
11 | use 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 | |||
20 | use super::{ | ||
21 | ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal, | ||
22 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, | ||
23 | }; | ||
24 | |||
25 | pub(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 | |||
50 | struct 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 | |||
64 | impl<'a, DB> ExprCollector<&'a DB> | ||
65 | where | ||
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 | |||
588 | impl 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)] |
173 | mod tests { | 173 | mod 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 @@ | |||
1 | use rustc_hash::FxHashSet; | ||
2 | use std::sync::Arc; | 1 | use std::sync::Arc; |
3 | 2 | ||
4 | use ra_syntax::ast::{AstNode, RecordLit}; | 3 | use ra_syntax::ast; |
4 | use rustc_hash::FxHashSet; | ||
5 | 5 | ||
6 | use super::{Expr, ExprId, RecordLitField}; | ||
7 | use crate::{ | 6 | use 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 | }; |
16 | use ra_syntax::ast; | 15 | |
16 | use super::{Expr, ExprId, RecordLitField}; | ||
17 | 17 | ||
18 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 18 | pub(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 && ¶ms[0] == &mismatch.actual { | 133 | if params.len() == 2 && ¶ms[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 | ||
76 | pub use self::code_model::{ | 78 | pub 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 | ||
470 | fn scope_for_offset( | 471 | fn 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 | ||
123 | impl 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 | |||
135 | impl 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)] |
124 | pub struct UnselectedProjectionTy { | 146 | pub struct UnselectedProjectionTy { |
125 | pub type_name: Name, | 147 | pub type_name: Name, |
126 | pub parameters: Substs, | 148 | pub parameters: Substs, |
127 | } | 149 | } |
128 | 150 | ||
151 | impl 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 { | 319 | impl 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 { | |||
306 | pub enum GenericPredicate { | 332 | pub 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 | |||
366 | impl 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 | 421 | impl 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. | ||
552 | pub 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. | 608 | impl 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 | ||
768 | impl TraitRef { | 873 | impl 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 | ||
787 | impl HirDisplay for TraitRef { | 891 | impl 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 | ||
8 | use log::{info, warn}; | 8 | use log::{info, warn}; |
9 | 9 | ||
10 | use super::{traits::Solution, Canonical, Ty}; | 10 | use super::{traits::Solution, Canonical, Ty, TypeWalk}; |
11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; | 11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; |
12 | 12 | ||
13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 13 | const 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 | }; |
35 | use crate::{ | 35 | use 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 | ||
57 | mod unify; | 57 | mod 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 @@ | |||
3 | use super::{InferenceContext, Obligation}; | 3 | use super::{InferenceContext, Obligation}; |
4 | use crate::db::HirDatabase; | 4 | use crate::db::HirDatabase; |
5 | use crate::ty::{ | 5 | use crate::ty::{ |
6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, | 6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 9 | impl<'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 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{ |
12 | FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
13 | TypeWalk, | ||
14 | }; | ||
12 | use crate::{ | 15 | use 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 | ||
351 | impl GenericPredicate { | 349 | impl 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 | ||
375 | fn 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] | ||
3556 | fn assoc_type_bindings() { | ||
3557 | assert_snapshot!( | ||
3558 | infer(r#" | ||
3559 | trait Trait { | ||
3560 | type Type; | ||
3561 | } | ||
3562 | |||
3563 | fn get<T: Trait>(t: T) -> <T as Trait>::Type {} | ||
3564 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
3565 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
3566 | |||
3567 | struct S<T>; | ||
3568 | impl<T> Trait for S<T> { type Type = T; } | ||
3569 | |||
3570 | fn 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] | ||
3621 | fn projection_eq_within_chalk() { | ||
3622 | // std::env::set_var("CHALK_DEBUG", "1"); | ||
3623 | assert_snapshot!( | ||
3624 | infer(r#" | ||
3625 | trait Trait1 { | ||
3626 | type Type; | ||
3627 | } | ||
3628 | trait Trait2<T> { | ||
3629 | fn foo(self) -> T; | ||
3630 | } | ||
3631 | impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} | ||
3632 | |||
3633 | fn 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 | } | ||
3551 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3646 | fn 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; | |||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | 10 | ||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, ToChalk}; | 14 | use 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 | ||
141 | impl 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. |
139 | pub(crate) fn trait_solve_query( | 154 | pub(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, |