diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 85 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 744 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/lower.rs | 647 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 354 | ||||
-rw-r--r-- | crates/ra_hir/src/from_id.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 83 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/expr.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/primitive.rs | 58 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 6 |
21 files changed, 500 insertions, 1733 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e5bfad3ca..962d5a8c1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -8,6 +8,7 @@ use std::sync::Arc; | |||
8 | 8 | ||
9 | use hir_def::{ | 9 | use hir_def::{ |
10 | adt::VariantData, | 10 | adt::VariantData, |
11 | body::scope::ExprScopes, | ||
11 | builtin_type::BuiltinType, | 12 | builtin_type::BuiltinType, |
12 | type_ref::{Mutability, TypeRef}, | 13 | type_ref::{Mutability, TypeRef}, |
13 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, | 14 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, |
@@ -22,8 +23,8 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | |||
22 | use crate::{ | 23 | use crate::{ |
23 | adt::VariantDef, | 24 | adt::VariantDef, |
24 | db::{AstDatabase, DefDatabase, HirDatabase}, | 25 | db::{AstDatabase, DefDatabase, HirDatabase}, |
25 | expr::{validation::ExprValidator, Body, BodySourceMap}, | 26 | expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, |
26 | generics::HasGenericParams, | 27 | generics::{GenericDef, HasGenericParams}, |
27 | ids::{ | 28 | ids::{ |
28 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
29 | TypeAliasId, | 30 | TypeAliasId, |
@@ -32,7 +33,7 @@ use crate::{ | |||
32 | resolve::{Resolver, Scope, TypeNs}, | 33 | resolve::{Resolver, Scope, TypeNs}, |
33 | traits::TraitData, | 34 | traits::TraitData, |
34 | ty::{InferenceResult, Namespace, TraitRef}, | 35 | ty::{InferenceResult, Namespace, TraitRef}, |
35 | Either, HasSource, ImportId, Name, ScopeDef, Ty, | 36 | Either, HasSource, ImportId, Name, ScopeDef, Source, Ty, |
36 | }; | 37 | }; |
37 | 38 | ||
38 | /// hir::Crate describes a single crate. It's the main interface with which | 39 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -539,6 +540,7 @@ pub trait HasBody: Copy { | |||
539 | fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>; | 540 | fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>; |
540 | fn body(self, db: &impl HirDatabase) -> Arc<Body>; | 541 | fn body(self, db: &impl HirDatabase) -> Arc<Body>; |
541 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>; | 542 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>; |
543 | fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes>; | ||
542 | } | 544 | } |
543 | 545 | ||
544 | impl<T> HasBody for T | 546 | impl<T> HasBody for T |
@@ -550,11 +552,15 @@ where | |||
550 | } | 552 | } |
551 | 553 | ||
552 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 554 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
553 | db.body_hir(self.into()) | 555 | self.into().body(db) |
554 | } | 556 | } |
555 | 557 | ||
556 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 558 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
557 | db.body_with_source_map(self.into()).1 | 559 | self.into().body_source_map(db) |
560 | } | ||
561 | |||
562 | fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> { | ||
563 | self.into().expr_scopes(db) | ||
558 | } | 564 | } |
559 | } | 565 | } |
560 | 566 | ||
@@ -564,11 +570,15 @@ impl HasBody for DefWithBody { | |||
564 | } | 570 | } |
565 | 571 | ||
566 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 572 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
567 | db.body_hir(self) | 573 | db.body(self.into()) |
568 | } | 574 | } |
569 | 575 | ||
570 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 576 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
571 | db.body_with_source_map(self).1 | 577 | db.body_with_source_map(self.into()).1 |
578 | } | ||
579 | |||
580 | fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> { | ||
581 | db.expr_scopes(self.into()) | ||
572 | } | 582 | } |
573 | } | 583 | } |
574 | 584 | ||
@@ -662,11 +672,11 @@ impl Function { | |||
662 | } | 672 | } |
663 | 673 | ||
664 | pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 674 | pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
665 | db.body_with_source_map(self.into()).1 | 675 | db.body_with_source_map(self.id.into()).1 |
666 | } | 676 | } |
667 | 677 | ||
668 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 678 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
669 | db.body_hir(self.into()) | 679 | db.body(self.id.into()) |
670 | } | 680 | } |
671 | 681 | ||
672 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | 682 | pub fn ty(self, db: &impl HirDatabase) -> Ty { |
@@ -1070,3 +1080,60 @@ impl AssocItem { | |||
1070 | .expect("AssocItem without container") | 1080 | .expect("AssocItem without container") |
1071 | } | 1081 | } |
1072 | } | 1082 | } |
1083 | |||
1084 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1085 | pub struct Local { | ||
1086 | pub(crate) parent: DefWithBody, | ||
1087 | pub(crate) pat_id: PatId, | ||
1088 | } | ||
1089 | |||
1090 | impl Local { | ||
1091 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
1092 | let body = self.parent.body(db); | ||
1093 | match &body[self.pat_id] { | ||
1094 | Pat::Bind { name, .. } => Some(name.clone()), | ||
1095 | _ => None, | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | pub fn is_self(self, db: &impl HirDatabase) -> bool { | ||
1100 | self.name(db) == Some(name::SELF_PARAM) | ||
1101 | } | ||
1102 | |||
1103 | pub fn is_mut(self, db: &impl HirDatabase) -> bool { | ||
1104 | let body = self.parent.body(db); | ||
1105 | match &body[self.pat_id] { | ||
1106 | Pat::Bind { mode, .. } => match mode { | ||
1107 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | ||
1108 | _ => false, | ||
1109 | }, | ||
1110 | _ => false, | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody { | ||
1115 | self.parent | ||
1116 | } | ||
1117 | |||
1118 | pub fn module(self, db: &impl HirDatabase) -> Module { | ||
1119 | self.parent.module(db) | ||
1120 | } | ||
1121 | |||
1122 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | ||
1123 | let infer = db.infer(self.parent); | ||
1124 | infer[self.pat_id].clone() | ||
1125 | } | ||
1126 | |||
1127 | pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { | ||
1128 | let source_map = self.parent.body_source_map(db); | ||
1129 | let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... | ||
1130 | let root = src.file_syntax(db); | ||
1131 | src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1135 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1136 | pub struct GenericParam { | ||
1137 | pub(crate) parent: GenericDef, | ||
1138 | pub(crate) idx: u32, | ||
1139 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 75c322c99..c60029c01 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -18,13 +18,14 @@ use crate::{ | |||
18 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, | 18 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, |
19 | }, | 19 | }, |
20 | type_alias::TypeAliasData, | 20 | type_alias::TypeAliasData, |
21 | Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, | 21 | Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait, |
22 | StructField, Trait, TypeAlias, | 22 | TypeAlias, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub use hir_def::db::{ | 25 | pub use hir_def::db::{ |
26 | CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, | 26 | BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, |
27 | InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, | 27 | EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, |
28 | RawItemsWithSourceMapQuery, StructDataQuery, | ||
28 | }; | 29 | }; |
29 | pub use hir_expand::db::{ | 30 | pub use hir_expand::db::{ |
30 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, | 31 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, |
@@ -84,9 +85,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
84 | #[salsa::query_group(HirDatabaseStorage)] | 85 | #[salsa::query_group(HirDatabaseStorage)] |
85 | #[salsa::requires(salsa::Database)] | 86 | #[salsa::requires(salsa::Database)] |
86 | pub trait HirDatabase: DefDatabase + AstDatabase { | 87 | pub trait HirDatabase: DefDatabase + AstDatabase { |
87 | #[salsa::invoke(ExprScopes::expr_scopes_query)] | ||
88 | fn expr_scopes(&self, def: DefWithBody) -> Arc<ExprScopes>; | ||
89 | |||
90 | #[salsa::invoke(crate::ty::infer_query)] | 88 | #[salsa::invoke(crate::ty::infer_query)] |
91 | fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; | 89 | fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; |
92 | 90 | ||
@@ -112,15 +110,6 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
112 | #[salsa::invoke(crate::ty::generic_defaults_query)] | 110 | #[salsa::invoke(crate::ty::generic_defaults_query)] |
113 | fn generic_defaults(&self, def: GenericDef) -> Substs; | 111 | fn generic_defaults(&self, def: GenericDef) -> Substs; |
114 | 112 | ||
115 | #[salsa::invoke(crate::expr::body_with_source_map_query)] | ||
116 | fn body_with_source_map( | ||
117 | &self, | ||
118 | def: DefWithBody, | ||
119 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); | ||
120 | |||
121 | #[salsa::invoke(crate::expr::body_hir_query)] | ||
122 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; | ||
123 | |||
124 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 113 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
125 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 114 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
126 | 115 | ||
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 6e23197a4..9262325f2 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1,118 +1,41 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub(crate) mod lower; | ||
4 | pub(crate) mod scope; | ||
5 | pub(crate) mod validation; | 3 | pub(crate) mod validation; |
6 | 4 | ||
7 | use std::{ops::Index, sync::Arc}; | 5 | use std::sync::Arc; |
8 | 6 | ||
9 | use hir_def::{ | 7 | use ra_syntax::AstPtr; |
10 | path::GenericArgs, | ||
11 | type_ref::{Mutability, TypeRef}, | ||
12 | }; | ||
13 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | ||
14 | use ra_syntax::{ast, AstPtr}; | ||
15 | use rustc_hash::FxHashMap; | ||
16 | |||
17 | use crate::{ | ||
18 | db::HirDatabase, | ||
19 | ty::primitive::{UncertainFloatTy, UncertainIntTy}, | ||
20 | DefWithBody, Either, HasSource, Name, Path, Resolver, Source, | ||
21 | }; | ||
22 | |||
23 | pub use self::scope::ExprScopes; | ||
24 | |||
25 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
26 | pub struct ExprId(RawId); | ||
27 | impl_arena_id!(ExprId); | ||
28 | |||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
30 | pub struct PatId(RawId); | ||
31 | impl_arena_id!(PatId); | ||
32 | |||
33 | /// The body of an item (function, const etc.). | ||
34 | #[derive(Debug, Eq, PartialEq)] | ||
35 | pub struct Body { | ||
36 | /// The def of the item this body belongs to | ||
37 | owner: DefWithBody, | ||
38 | exprs: Arena<ExprId, Expr>, | ||
39 | pats: Arena<PatId, Pat>, | ||
40 | /// The patterns for the function's parameters. While the parameter types are | ||
41 | /// part of the function signature, the patterns are not (they don't change | ||
42 | /// the external type of the function). | ||
43 | /// | ||
44 | /// If this `Body` is for the body of a constant, this will just be | ||
45 | /// empty. | ||
46 | params: Vec<PatId>, | ||
47 | /// The `ExprId` of the actual body expression. | ||
48 | body_expr: ExprId, | ||
49 | } | ||
50 | |||
51 | type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
52 | type ExprSource = Source<ExprPtr>; | ||
53 | 8 | ||
54 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 9 | use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; |
55 | type PatSource = Source<PatPtr>; | ||
56 | 10 | ||
57 | /// An item body together with the mapping from syntax nodes to HIR expression | 11 | pub use hir_def::{ |
58 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | 12 | body::{ |
59 | /// expression containing it; but for type inference etc., we want to operate on | 13 | scope::{ExprScopes, ScopeEntry, ScopeId}, |
60 | /// a structure that is agnostic to the actual positions of expressions in the | 14 | Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource, |
61 | /// file, so that we don't recompute types whenever some whitespace is typed. | 15 | }, |
62 | /// | 16 | expr::{ |
63 | /// One complication here is that, due to macro expansion, a single `Body` might | 17 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
64 | /// be spread across several files. So, for each ExprId and PatId, we record | 18 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, |
65 | /// both the HirFileId and the position inside the file. However, we only store | 19 | }, |
66 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | 20 | }; |
67 | /// this properly for macros. | ||
68 | #[derive(Default, Debug, Eq, PartialEq)] | ||
69 | pub struct BodySourceMap { | ||
70 | expr_map: FxHashMap<ExprPtr, ExprId>, | ||
71 | expr_map_back: ArenaMap<ExprId, ExprSource>, | ||
72 | pat_map: FxHashMap<PatPtr, PatId>, | ||
73 | pat_map_back: ArenaMap<PatId, PatSource>, | ||
74 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | ||
75 | } | ||
76 | |||
77 | impl Body { | ||
78 | pub fn params(&self) -> &[PatId] { | ||
79 | &self.params | ||
80 | } | ||
81 | |||
82 | pub fn body_expr(&self) -> ExprId { | ||
83 | self.body_expr | ||
84 | } | ||
85 | |||
86 | pub fn owner(&self) -> DefWithBody { | ||
87 | self.owner | ||
88 | } | ||
89 | |||
90 | pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> { | ||
91 | self.exprs.iter() | ||
92 | } | ||
93 | |||
94 | pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> { | ||
95 | self.pats.iter() | ||
96 | } | ||
97 | } | ||
98 | 21 | ||
99 | // needs arbitrary_self_types to be a method... or maybe move to the def? | 22 | // needs arbitrary_self_types to be a method... or maybe move to the def? |
100 | pub(crate) fn resolver_for_expr( | 23 | pub(crate) fn resolver_for_expr( |
101 | body: Arc<Body>, | ||
102 | db: &impl HirDatabase, | 24 | db: &impl HirDatabase, |
25 | owner: DefWithBody, | ||
103 | expr_id: ExprId, | 26 | expr_id: ExprId, |
104 | ) -> Resolver { | 27 | ) -> Resolver { |
105 | let scopes = db.expr_scopes(body.owner); | 28 | let scopes = owner.expr_scopes(db); |
106 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) | 29 | resolver_for_scope(db, owner, scopes.scope_for(expr_id)) |
107 | } | 30 | } |
108 | 31 | ||
109 | pub(crate) fn resolver_for_scope( | 32 | pub(crate) fn resolver_for_scope( |
110 | body: Arc<Body>, | ||
111 | db: &impl HirDatabase, | 33 | db: &impl HirDatabase, |
112 | scope_id: Option<scope::ScopeId>, | 34 | owner: DefWithBody, |
35 | scope_id: Option<ScopeId>, | ||
113 | ) -> Resolver { | 36 | ) -> Resolver { |
114 | let mut r = body.owner.resolver(db); | 37 | let mut r = owner.resolver(db); |
115 | let scopes = db.expr_scopes(body.owner); | 38 | let scopes = owner.expr_scopes(db); |
116 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | 39 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); |
117 | for scope in scope_chain.into_iter().rev() { | 40 | for scope in scope_chain.into_iter().rev() { |
118 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | 41 | r = r.push_expr_scope(Arc::clone(&scopes), scope); |
@@ -120,456 +43,191 @@ pub(crate) fn resolver_for_scope( | |||
120 | r | 43 | r |
121 | } | 44 | } |
122 | 45 | ||
123 | impl Index<ExprId> for Body { | 46 | #[cfg(test)] |
124 | type Output = Expr; | 47 | mod tests { |
125 | 48 | use hir_expand::Source; | |
126 | fn index(&self, expr: ExprId) -> &Expr { | 49 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
127 | &self.exprs[expr] | 50 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
128 | } | 51 | use test_utils::{assert_eq_text, extract_offset}; |
129 | } | 52 | |
130 | 53 | use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; | |
131 | impl Index<PatId> for Body { | 54 | |
132 | type Output = Pat; | 55 | fn do_check(code: &str, expected: &[&str]) { |
133 | 56 | let (off, code) = extract_offset(code); | |
134 | fn index(&self, pat: PatId) -> &Pat { | 57 | let code = { |
135 | &self.pats[pat] | 58 | let mut buf = String::new(); |
136 | } | 59 | let off = u32::from(off) as usize; |
137 | } | 60 | buf.push_str(&code[..off]); |
138 | 61 | buf.push_str("marker"); | |
139 | impl BodySourceMap { | 62 | buf.push_str(&code[off..]); |
140 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { | 63 | buf |
141 | self.expr_map_back.get(expr).copied() | 64 | }; |
142 | } | 65 | |
143 | 66 | let (db, file_id) = TestDB::with_single_file(&code); | |
144 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | 67 | |
145 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | 68 | let file = db.parse(file_id).ok().unwrap(); |
146 | } | 69 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
147 | 70 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); | |
148 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { | 71 | |
149 | self.pat_map_back.get(pat).copied() | 72 | let scopes = analyzer.scopes(); |
150 | } | 73 | let expr_id = analyzer |
151 | 74 | .body_source_map() | |
152 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | 75 | .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) |
153 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | 76 | .unwrap(); |
154 | } | 77 | let scope = scopes.scope_for(expr_id); |
155 | 78 | ||
156 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | 79 | let actual = scopes |
157 | self.field_map[&(expr, field)] | 80 | .scope_chain(scope) |
158 | } | 81 | .flat_map(|scope| scopes.entries(scope)) |
159 | } | 82 | .map(|it| it.name().to_string()) |
160 | 83 | .collect::<Vec<_>>() | |
161 | #[derive(Debug, Clone, Eq, PartialEq)] | 84 | .join("\n"); |
162 | pub enum Literal { | 85 | let expected = expected.join("\n"); |
163 | String(String), | 86 | assert_eq_text!(&expected, &actual); |
164 | ByteString(Vec<u8>), | 87 | } |
165 | Char(char), | 88 | |
166 | Bool(bool), | 89 | #[test] |
167 | Int(u64, UncertainIntTy), | 90 | fn test_lambda_scope() { |
168 | Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq | 91 | do_check( |
169 | } | 92 | r" |
170 | 93 | fn quux(foo: i32) { | |
171 | #[derive(Debug, Clone, Eq, PartialEq)] | 94 | let f = |bar, baz: i32| { |
172 | pub enum Expr { | 95 | <|> |
173 | /// This is produced if syntax tree does not have a required expression piece. | 96 | }; |
174 | Missing, | 97 | }", |
175 | Path(Path), | 98 | &["bar", "baz", "foo"], |
176 | If { | 99 | ); |
177 | condition: ExprId, | 100 | } |
178 | then_branch: ExprId, | 101 | |
179 | else_branch: Option<ExprId>, | 102 | #[test] |
180 | }, | 103 | fn test_call_scope() { |
181 | Block { | 104 | do_check( |
182 | statements: Vec<Statement>, | 105 | r" |
183 | tail: Option<ExprId>, | 106 | fn quux() { |
184 | }, | 107 | f(|x| <|> ); |
185 | Loop { | 108 | }", |
186 | body: ExprId, | 109 | &["x"], |
187 | }, | 110 | ); |
188 | While { | 111 | } |
189 | condition: ExprId, | 112 | |
190 | body: ExprId, | 113 | #[test] |
191 | }, | 114 | fn test_method_call_scope() { |
192 | For { | 115 | do_check( |
193 | iterable: ExprId, | 116 | r" |
194 | pat: PatId, | 117 | fn quux() { |
195 | body: ExprId, | 118 | z.f(|x| <|> ); |
196 | }, | 119 | }", |
197 | Call { | 120 | &["x"], |
198 | callee: ExprId, | 121 | ); |
199 | args: Vec<ExprId>, | 122 | } |
200 | }, | 123 | |
201 | MethodCall { | 124 | #[test] |
202 | receiver: ExprId, | 125 | fn test_loop_scope() { |
203 | method_name: Name, | 126 | do_check( |
204 | args: Vec<ExprId>, | 127 | r" |
205 | generic_args: Option<GenericArgs>, | 128 | fn quux() { |
206 | }, | 129 | loop { |
207 | Match { | 130 | let x = (); |
208 | expr: ExprId, | 131 | <|> |
209 | arms: Vec<MatchArm>, | 132 | }; |
210 | }, | 133 | }", |
211 | Continue, | 134 | &["x"], |
212 | Break { | 135 | ); |
213 | expr: Option<ExprId>, | 136 | } |
214 | }, | 137 | |
215 | Return { | 138 | #[test] |
216 | expr: Option<ExprId>, | 139 | fn test_match() { |
217 | }, | 140 | do_check( |
218 | RecordLit { | 141 | r" |
219 | path: Option<Path>, | 142 | fn quux() { |
220 | fields: Vec<RecordLitField>, | 143 | match () { |
221 | spread: Option<ExprId>, | 144 | Some(x) => { |
222 | }, | 145 | <|> |
223 | Field { | ||
224 | expr: ExprId, | ||
225 | name: Name, | ||
226 | }, | ||
227 | Await { | ||
228 | expr: ExprId, | ||
229 | }, | ||
230 | Try { | ||
231 | expr: ExprId, | ||
232 | }, | ||
233 | TryBlock { | ||
234 | body: ExprId, | ||
235 | }, | ||
236 | Cast { | ||
237 | expr: ExprId, | ||
238 | type_ref: TypeRef, | ||
239 | }, | ||
240 | Ref { | ||
241 | expr: ExprId, | ||
242 | mutability: Mutability, | ||
243 | }, | ||
244 | Box { | ||
245 | expr: ExprId, | ||
246 | }, | ||
247 | UnaryOp { | ||
248 | expr: ExprId, | ||
249 | op: UnaryOp, | ||
250 | }, | ||
251 | BinaryOp { | ||
252 | lhs: ExprId, | ||
253 | rhs: ExprId, | ||
254 | op: Option<BinaryOp>, | ||
255 | }, | ||
256 | Index { | ||
257 | base: ExprId, | ||
258 | index: ExprId, | ||
259 | }, | ||
260 | Lambda { | ||
261 | args: Vec<PatId>, | ||
262 | arg_types: Vec<Option<TypeRef>>, | ||
263 | body: ExprId, | ||
264 | }, | ||
265 | Tuple { | ||
266 | exprs: Vec<ExprId>, | ||
267 | }, | ||
268 | Array(Array), | ||
269 | Literal(Literal), | ||
270 | } | ||
271 | |||
272 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
273 | pub enum BinaryOp { | ||
274 | LogicOp(LogicOp), | ||
275 | ArithOp(ArithOp), | ||
276 | CmpOp(CmpOp), | ||
277 | Assignment { op: Option<ArithOp> }, | ||
278 | } | ||
279 | |||
280 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
281 | pub enum LogicOp { | ||
282 | And, | ||
283 | Or, | ||
284 | } | ||
285 | |||
286 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
287 | pub enum CmpOp { | ||
288 | Eq { negated: bool }, | ||
289 | Ord { ordering: Ordering, strict: bool }, | ||
290 | } | ||
291 | |||
292 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
293 | pub enum Ordering { | ||
294 | Less, | ||
295 | Greater, | ||
296 | } | ||
297 | |||
298 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
299 | pub enum ArithOp { | ||
300 | Add, | ||
301 | Mul, | ||
302 | Sub, | ||
303 | Div, | ||
304 | Rem, | ||
305 | Shl, | ||
306 | Shr, | ||
307 | BitXor, | ||
308 | BitOr, | ||
309 | BitAnd, | ||
310 | } | ||
311 | |||
312 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | ||
313 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
314 | pub enum Array { | ||
315 | ElementList(Vec<ExprId>), | ||
316 | Repeat { initializer: ExprId, repeat: ExprId }, | ||
317 | } | ||
318 | |||
319 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
320 | pub struct MatchArm { | ||
321 | pub pats: Vec<PatId>, | ||
322 | pub guard: Option<ExprId>, | ||
323 | pub expr: ExprId, | ||
324 | } | ||
325 | |||
326 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
327 | pub struct RecordLitField { | ||
328 | pub name: Name, | ||
329 | pub expr: ExprId, | ||
330 | } | ||
331 | |||
332 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
333 | pub enum Statement { | ||
334 | Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, | ||
335 | Expr(ExprId), | ||
336 | } | ||
337 | |||
338 | impl Expr { | ||
339 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
340 | match self { | ||
341 | Expr::Missing => {} | ||
342 | Expr::Path(_) => {} | ||
343 | Expr::If { condition, then_branch, else_branch } => { | ||
344 | f(*condition); | ||
345 | f(*then_branch); | ||
346 | if let Some(else_branch) = else_branch { | ||
347 | f(*else_branch); | ||
348 | } | ||
349 | } | ||
350 | Expr::Block { statements, tail } => { | ||
351 | for stmt in statements { | ||
352 | match stmt { | ||
353 | Statement::Let { initializer, .. } => { | ||
354 | if let Some(expr) = initializer { | ||
355 | f(*expr); | ||
356 | } | ||
357 | } | ||
358 | Statement::Expr(e) => f(*e), | ||
359 | } | 146 | } |
147 | }; | ||
148 | }", | ||
149 | &["x"], | ||
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn test_shadow_variable() { | ||
155 | do_check( | ||
156 | r" | ||
157 | fn foo(x: String) { | ||
158 | let x : &str = &x<|>; | ||
159 | }", | ||
160 | &["x"], | ||
161 | ); | ||
162 | } | ||
163 | |||
164 | fn do_check_local_name(code: &str, expected_offset: u32) { | ||
165 | let (off, code) = extract_offset(code); | ||
166 | |||
167 | let (db, file_id) = TestDB::with_single_file(&code); | ||
168 | let file = db.parse(file_id).ok().unwrap(); | ||
169 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
170 | .expect("failed to find a name at the target offset"); | ||
171 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
172 | let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); | ||
173 | |||
174 | let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); | ||
175 | let local_name = | ||
176 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
177 | assert_eq!(local_name.range(), expected_name.syntax().text_range()); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn test_resolve_local_name() { | ||
182 | do_check_local_name( | ||
183 | r#" | ||
184 | fn foo(x: i32, y: u32) { | ||
185 | { | ||
186 | let z = x * 2; | ||
360 | } | 187 | } |
361 | if let Some(expr) = tail { | 188 | { |
362 | f(*expr); | 189 | let t = x<|> * 3; |
363 | } | ||
364 | } | ||
365 | Expr::TryBlock { body } => f(*body), | ||
366 | Expr::Loop { body } => f(*body), | ||
367 | Expr::While { condition, body } => { | ||
368 | f(*condition); | ||
369 | f(*body); | ||
370 | } | ||
371 | Expr::For { iterable, body, .. } => { | ||
372 | f(*iterable); | ||
373 | f(*body); | ||
374 | } | ||
375 | Expr::Call { callee, args } => { | ||
376 | f(*callee); | ||
377 | for arg in args { | ||
378 | f(*arg); | ||
379 | } | ||
380 | } | ||
381 | Expr::MethodCall { receiver, args, .. } => { | ||
382 | f(*receiver); | ||
383 | for arg in args { | ||
384 | f(*arg); | ||
385 | } | ||
386 | } | ||
387 | Expr::Match { expr, arms } => { | ||
388 | f(*expr); | ||
389 | for arm in arms { | ||
390 | f(arm.expr); | ||
391 | } | ||
392 | } | ||
393 | Expr::Continue => {} | ||
394 | Expr::Break { expr } | Expr::Return { expr } => { | ||
395 | if let Some(expr) = expr { | ||
396 | f(*expr); | ||
397 | } | 190 | } |
398 | } | 191 | }"#, |
399 | Expr::RecordLit { fields, spread, .. } => { | 192 | 21, |
400 | for field in fields { | 193 | ); |
401 | f(field.expr); | 194 | } |
195 | |||
196 | #[test] | ||
197 | fn test_resolve_local_name_declaration() { | ||
198 | do_check_local_name( | ||
199 | r#" | ||
200 | fn foo(x: String) { | ||
201 | let x : &str = &x<|>; | ||
202 | }"#, | ||
203 | 21, | ||
204 | ); | ||
205 | } | ||
206 | |||
207 | #[test] | ||
208 | fn test_resolve_local_name_shadow() { | ||
209 | do_check_local_name( | ||
210 | r" | ||
211 | fn foo(x: String) { | ||
212 | let x : &str = &x; | ||
213 | x<|> | ||
214 | } | ||
215 | ", | ||
216 | 53, | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn ref_patterns_contribute_bindings() { | ||
222 | do_check_local_name( | ||
223 | r" | ||
224 | fn foo() { | ||
225 | if let Some(&from) = bar() { | ||
226 | from<|>; | ||
402 | } | 227 | } |
403 | if let Some(expr) = spread { | ||
404 | f(*expr); | ||
405 | } | ||
406 | } | ||
407 | Expr::Lambda { body, .. } => { | ||
408 | f(*body); | ||
409 | } | 228 | } |
410 | Expr::BinaryOp { lhs, rhs, .. } => { | 229 | ", |
411 | f(*lhs); | 230 | 53, |
412 | f(*rhs); | 231 | ); |
413 | } | ||
414 | Expr::Index { base, index } => { | ||
415 | f(*base); | ||
416 | f(*index); | ||
417 | } | ||
418 | Expr::Field { expr, .. } | ||
419 | | Expr::Await { expr } | ||
420 | | Expr::Try { expr } | ||
421 | | Expr::Cast { expr, .. } | ||
422 | | Expr::Ref { expr, .. } | ||
423 | | Expr::UnaryOp { expr, .. } | ||
424 | | Expr::Box { expr } => { | ||
425 | f(*expr); | ||
426 | } | ||
427 | Expr::Tuple { exprs } => { | ||
428 | for expr in exprs { | ||
429 | f(*expr); | ||
430 | } | ||
431 | } | ||
432 | Expr::Array(a) => match a { | ||
433 | Array::ElementList(exprs) => { | ||
434 | for expr in exprs { | ||
435 | f(*expr); | ||
436 | } | ||
437 | } | ||
438 | Array::Repeat { initializer, repeat } => { | ||
439 | f(*initializer); | ||
440 | f(*repeat) | ||
441 | } | ||
442 | }, | ||
443 | Expr::Literal(_) => {} | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
449 | /// that this is not the final binding *mode* that we infer after type | ||
450 | /// inference. | ||
451 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
452 | pub enum BindingAnnotation { | ||
453 | /// No binding annotation given: this means that the final binding mode | ||
454 | /// will depend on whether we have skipped through a `&` reference | ||
455 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
456 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
457 | /// ultimately be inferred to be by-reference. | ||
458 | Unannotated, | ||
459 | |||
460 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
461 | Mutable, | ||
462 | |||
463 | /// Annotated as `ref`, like `ref x` | ||
464 | Ref, | ||
465 | |||
466 | /// Annotated as `ref mut x`. | ||
467 | RefMut, | ||
468 | } | ||
469 | |||
470 | impl BindingAnnotation { | ||
471 | fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
472 | match (is_mutable, is_ref) { | ||
473 | (true, true) => BindingAnnotation::RefMut, | ||
474 | (false, true) => BindingAnnotation::Ref, | ||
475 | (true, false) => BindingAnnotation::Mutable, | ||
476 | (false, false) => BindingAnnotation::Unannotated, | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | |||
481 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
482 | pub struct RecordFieldPat { | ||
483 | pub(crate) name: Name, | ||
484 | pub(crate) pat: PatId, | ||
485 | } | ||
486 | |||
487 | /// Close relative to rustc's hir::PatKind | ||
488 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
489 | pub enum Pat { | ||
490 | Missing, | ||
491 | Wild, | ||
492 | Tuple(Vec<PatId>), | ||
493 | Record { | ||
494 | path: Option<Path>, | ||
495 | args: Vec<RecordFieldPat>, | ||
496 | // FIXME: 'ellipsis' option | ||
497 | }, | ||
498 | Range { | ||
499 | start: ExprId, | ||
500 | end: ExprId, | ||
501 | }, | ||
502 | Slice { | ||
503 | prefix: Vec<PatId>, | ||
504 | rest: Option<PatId>, | ||
505 | suffix: Vec<PatId>, | ||
506 | }, | ||
507 | Path(Path), | ||
508 | Lit(ExprId), | ||
509 | Bind { | ||
510 | mode: BindingAnnotation, | ||
511 | name: Name, | ||
512 | subpat: Option<PatId>, | ||
513 | }, | ||
514 | TupleStruct { | ||
515 | path: Option<Path>, | ||
516 | args: Vec<PatId>, | ||
517 | }, | ||
518 | Ref { | ||
519 | pat: PatId, | ||
520 | mutability: Mutability, | ||
521 | }, | ||
522 | } | ||
523 | |||
524 | impl Pat { | ||
525 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | ||
526 | match self { | ||
527 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | ||
528 | Pat::Bind { subpat, .. } => { | ||
529 | subpat.iter().copied().for_each(f); | ||
530 | } | ||
531 | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { | ||
532 | args.iter().copied().for_each(f); | ||
533 | } | ||
534 | Pat::Ref { pat, .. } => f(*pat), | ||
535 | Pat::Slice { prefix, rest, suffix } => { | ||
536 | let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); | ||
537 | total_iter.copied().for_each(f); | ||
538 | } | ||
539 | Pat::Record { args, .. } => { | ||
540 | args.iter().map(|f| f.pat).for_each(f); | ||
541 | } | ||
542 | } | ||
543 | } | 232 | } |
544 | } | 233 | } |
545 | |||
546 | // Queries | ||
547 | pub(crate) fn body_with_source_map_query( | ||
548 | db: &impl HirDatabase, | ||
549 | def: DefWithBody, | ||
550 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
551 | let mut params = None; | ||
552 | |||
553 | let (file_id, body) = match def { | ||
554 | DefWithBody::Function(f) => { | ||
555 | let src = f.source(db); | ||
556 | params = src.ast.param_list(); | ||
557 | (src.file_id, src.ast.body().map(ast::Expr::from)) | ||
558 | } | ||
559 | DefWithBody::Const(c) => { | ||
560 | let src = c.source(db); | ||
561 | (src.file_id, src.ast.body()) | ||
562 | } | ||
563 | DefWithBody::Static(s) => { | ||
564 | let src = s.source(db); | ||
565 | (src.file_id, src.ast.body()) | ||
566 | } | ||
567 | }; | ||
568 | |||
569 | let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body); | ||
570 | (Arc::new(body), Arc::new(source_map)) | ||
571 | } | ||
572 | |||
573 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | ||
574 | db.body_with_source_map(def).0 | ||
575 | } | ||
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs deleted file mode 100644 index 6463dd65e..000000000 --- a/crates/ra_hir/src/expr/lower.rs +++ /dev/null | |||
@@ -1,647 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use hir_def::{path::GenericArgs, type_ref::TypeRef}; | ||
4 | use hir_expand::{ | ||
5 | hygiene::Hygiene, | ||
6 | name::{self, AsName, Name}, | ||
7 | }; | ||
8 | use ra_arena::Arena; | ||
9 | use ra_syntax::{ | ||
10 | ast::{ | ||
11 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, | ||
12 | TypeAscriptionOwner, | ||
13 | }, | ||
14 | AstNode, AstPtr, | ||
15 | }; | ||
16 | use test_utils::tested_by; | ||
17 | |||
18 | use crate::{ | ||
19 | db::HirDatabase, | ||
20 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
21 | AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, | ||
22 | Source, | ||
23 | }; | ||
24 | |||
25 | use super::{ | ||
26 | ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal, | ||
27 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, | ||
28 | }; | ||
29 | |||
30 | pub(super) fn lower( | ||
31 | db: &impl HirDatabase, | ||
32 | resolver: Resolver, | ||
33 | file_id: HirFileId, | ||
34 | owner: DefWithBody, | ||
35 | params: Option<ast::ParamList>, | ||
36 | body: Option<ast::Expr>, | ||
37 | ) -> (Body, BodySourceMap) { | ||
38 | ExprCollector { | ||
39 | resolver, | ||
40 | db, | ||
41 | original_file_id: file_id, | ||
42 | current_file_id: file_id, | ||
43 | source_map: BodySourceMap::default(), | ||
44 | body: Body { | ||
45 | owner, | ||
46 | exprs: Arena::default(), | ||
47 | pats: Arena::default(), | ||
48 | params: Vec::new(), | ||
49 | body_expr: ExprId((!0).into()), | ||
50 | }, | ||
51 | } | ||
52 | .collect(params, body) | ||
53 | } | ||
54 | |||
55 | struct ExprCollector<DB> { | ||
56 | db: DB, | ||
57 | resolver: Resolver, | ||
58 | // Expr collector expands macros along the way. original points to the file | ||
59 | // we started with, current points to the current macro expansion. source | ||
60 | // maps don't support macros yet, so we only record info into source map if | ||
61 | // current == original (see #1196) | ||
62 | original_file_id: HirFileId, | ||
63 | current_file_id: HirFileId, | ||
64 | |||
65 | body: Body, | ||
66 | source_map: BodySourceMap, | ||
67 | } | ||
68 | |||
69 | impl<'a, DB> ExprCollector<&'a DB> | ||
70 | where | ||
71 | DB: HirDatabase, | ||
72 | { | ||
73 | fn collect( | ||
74 | mut self, | ||
75 | param_list: Option<ast::ParamList>, | ||
76 | body: Option<ast::Expr>, | ||
77 | ) -> (Body, BodySourceMap) { | ||
78 | if let Some(param_list) = param_list { | ||
79 | if let Some(self_param) = param_list.self_param() { | ||
80 | let ptr = AstPtr::new(&self_param); | ||
81 | let param_pat = self.alloc_pat( | ||
82 | Pat::Bind { | ||
83 | name: name::SELF_PARAM, | ||
84 | mode: BindingAnnotation::Unannotated, | ||
85 | subpat: None, | ||
86 | }, | ||
87 | Either::B(ptr), | ||
88 | ); | ||
89 | self.body.params.push(param_pat); | ||
90 | } | ||
91 | |||
92 | for param in param_list.params() { | ||
93 | let pat = match param.pat() { | ||
94 | None => continue, | ||
95 | Some(pat) => pat, | ||
96 | }; | ||
97 | let param_pat = self.collect_pat(pat); | ||
98 | self.body.params.push(param_pat); | ||
99 | } | ||
100 | }; | ||
101 | |||
102 | self.body.body_expr = self.collect_expr_opt(body); | ||
103 | (self.body, self.source_map) | ||
104 | } | ||
105 | |||
106 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | ||
107 | let ptr = Either::A(ptr); | ||
108 | let id = self.body.exprs.alloc(expr); | ||
109 | if self.current_file_id == self.original_file_id { | ||
110 | self.source_map.expr_map.insert(ptr, id); | ||
111 | } | ||
112 | self.source_map | ||
113 | .expr_map_back | ||
114 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
115 | id | ||
116 | } | ||
117 | // desugared exprs don't have ptr, that's wrong and should be fixed | ||
118 | // somehow. | ||
119 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | ||
120 | self.body.exprs.alloc(expr) | ||
121 | } | ||
122 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | ||
123 | let ptr = Either::B(ptr); | ||
124 | let id = self.body.exprs.alloc(expr); | ||
125 | if self.current_file_id == self.original_file_id { | ||
126 | self.source_map.expr_map.insert(ptr, id); | ||
127 | } | ||
128 | self.source_map | ||
129 | .expr_map_back | ||
130 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
131 | id | ||
132 | } | ||
133 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | ||
134 | let id = self.body.pats.alloc(pat); | ||
135 | if self.current_file_id == self.original_file_id { | ||
136 | self.source_map.pat_map.insert(ptr, id); | ||
137 | } | ||
138 | self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
139 | id | ||
140 | } | ||
141 | |||
142 | fn empty_block(&mut self) -> ExprId { | ||
143 | let block = Expr::Block { statements: Vec::new(), tail: None }; | ||
144 | self.body.exprs.alloc(block) | ||
145 | } | ||
146 | |||
147 | fn missing_expr(&mut self) -> ExprId { | ||
148 | self.body.exprs.alloc(Expr::Missing) | ||
149 | } | ||
150 | |||
151 | fn missing_pat(&mut self) -> PatId { | ||
152 | self.body.pats.alloc(Pat::Missing) | ||
153 | } | ||
154 | |||
155 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | ||
156 | let syntax_ptr = AstPtr::new(&expr); | ||
157 | match expr { | ||
158 | ast::Expr::IfExpr(e) => { | ||
159 | let then_branch = self.collect_block_opt(e.then_branch()); | ||
160 | |||
161 | let else_branch = e.else_branch().map(|b| match b { | ||
162 | ast::ElseBranch::Block(it) => self.collect_block(it), | ||
163 | ast::ElseBranch::IfExpr(elif) => { | ||
164 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); | ||
165 | self.collect_expr(expr) | ||
166 | } | ||
167 | }); | ||
168 | |||
169 | let condition = match e.condition() { | ||
170 | None => self.missing_expr(), | ||
171 | Some(condition) => match condition.pat() { | ||
172 | None => self.collect_expr_opt(condition.expr()), | ||
173 | // if let -- desugar to match | ||
174 | Some(pat) => { | ||
175 | let pat = self.collect_pat(pat); | ||
176 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
177 | let placeholder_pat = self.missing_pat(); | ||
178 | let arms = vec![ | ||
179 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, | ||
180 | MatchArm { | ||
181 | pats: vec![placeholder_pat], | ||
182 | expr: else_branch.unwrap_or_else(|| self.empty_block()), | ||
183 | guard: None, | ||
184 | }, | ||
185 | ]; | ||
186 | return self | ||
187 | .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); | ||
188 | } | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | ||
193 | } | ||
194 | ast::Expr::TryBlockExpr(e) => { | ||
195 | let body = self.collect_block_opt(e.body()); | ||
196 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) | ||
197 | } | ||
198 | ast::Expr::BlockExpr(e) => self.collect_block(e), | ||
199 | ast::Expr::LoopExpr(e) => { | ||
200 | let body = self.collect_block_opt(e.loop_body()); | ||
201 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | ||
202 | } | ||
203 | ast::Expr::WhileExpr(e) => { | ||
204 | let body = self.collect_block_opt(e.loop_body()); | ||
205 | |||
206 | let condition = match e.condition() { | ||
207 | None => self.missing_expr(), | ||
208 | Some(condition) => match condition.pat() { | ||
209 | None => self.collect_expr_opt(condition.expr()), | ||
210 | // if let -- desugar to match | ||
211 | Some(pat) => { | ||
212 | tested_by!(infer_while_let); | ||
213 | let pat = self.collect_pat(pat); | ||
214 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
215 | let placeholder_pat = self.missing_pat(); | ||
216 | let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); | ||
217 | let arms = vec![ | ||
218 | MatchArm { pats: vec![pat], expr: body, guard: None }, | ||
219 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, | ||
220 | ]; | ||
221 | let match_expr = | ||
222 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | ||
223 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | ||
224 | } | ||
225 | }, | ||
226 | }; | ||
227 | |||
228 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | ||
229 | } | ||
230 | ast::Expr::ForExpr(e) => { | ||
231 | let iterable = self.collect_expr_opt(e.iterable()); | ||
232 | let pat = self.collect_pat_opt(e.pat()); | ||
233 | let body = self.collect_block_opt(e.loop_body()); | ||
234 | self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr) | ||
235 | } | ||
236 | ast::Expr::CallExpr(e) => { | ||
237 | let callee = self.collect_expr_opt(e.expr()); | ||
238 | let args = if let Some(arg_list) = e.arg_list() { | ||
239 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
240 | } else { | ||
241 | Vec::new() | ||
242 | }; | ||
243 | self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) | ||
244 | } | ||
245 | ast::Expr::MethodCallExpr(e) => { | ||
246 | let receiver = self.collect_expr_opt(e.expr()); | ||
247 | let args = if let Some(arg_list) = e.arg_list() { | ||
248 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
249 | } else { | ||
250 | Vec::new() | ||
251 | }; | ||
252 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
253 | let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast); | ||
254 | self.alloc_expr( | ||
255 | Expr::MethodCall { receiver, method_name, args, generic_args }, | ||
256 | syntax_ptr, | ||
257 | ) | ||
258 | } | ||
259 | ast::Expr::MatchExpr(e) => { | ||
260 | let expr = self.collect_expr_opt(e.expr()); | ||
261 | let arms = if let Some(match_arm_list) = e.match_arm_list() { | ||
262 | match_arm_list | ||
263 | .arms() | ||
264 | .map(|arm| MatchArm { | ||
265 | pats: arm.pats().map(|p| self.collect_pat(p)).collect(), | ||
266 | expr: self.collect_expr_opt(arm.expr()), | ||
267 | guard: arm | ||
268 | .guard() | ||
269 | .and_then(|guard| guard.expr()) | ||
270 | .map(|e| self.collect_expr(e)), | ||
271 | }) | ||
272 | .collect() | ||
273 | } else { | ||
274 | Vec::new() | ||
275 | }; | ||
276 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | ||
277 | } | ||
278 | ast::Expr::PathExpr(e) => { | ||
279 | let path = e | ||
280 | .path() | ||
281 | .and_then(|path| self.parse_path(path)) | ||
282 | .map(Expr::Path) | ||
283 | .unwrap_or(Expr::Missing); | ||
284 | self.alloc_expr(path, syntax_ptr) | ||
285 | } | ||
286 | ast::Expr::ContinueExpr(_e) => { | ||
287 | // FIXME: labels | ||
288 | self.alloc_expr(Expr::Continue, syntax_ptr) | ||
289 | } | ||
290 | ast::Expr::BreakExpr(e) => { | ||
291 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
292 | self.alloc_expr(Expr::Break { expr }, syntax_ptr) | ||
293 | } | ||
294 | ast::Expr::ParenExpr(e) => { | ||
295 | let inner = self.collect_expr_opt(e.expr()); | ||
296 | // make the paren expr point to the inner expression as well | ||
297 | self.source_map.expr_map.insert(Either::A(syntax_ptr), inner); | ||
298 | inner | ||
299 | } | ||
300 | ast::Expr::ReturnExpr(e) => { | ||
301 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
302 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | ||
303 | } | ||
304 | ast::Expr::RecordLit(e) => { | ||
305 | let path = e.path().and_then(|path| self.parse_path(path)); | ||
306 | let mut field_ptrs = Vec::new(); | ||
307 | let record_lit = if let Some(nfl) = e.record_field_list() { | ||
308 | let fields = nfl | ||
309 | .fields() | ||
310 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | ||
311 | .map(|field| RecordLitField { | ||
312 | name: field | ||
313 | .name_ref() | ||
314 | .map(|nr| nr.as_name()) | ||
315 | .unwrap_or_else(Name::missing), | ||
316 | expr: if let Some(e) = field.expr() { | ||
317 | self.collect_expr(e) | ||
318 | } else if let Some(nr) = field.name_ref() { | ||
319 | // field shorthand | ||
320 | self.alloc_expr_field_shorthand( | ||
321 | Expr::Path(Path::from_name_ref(&nr)), | ||
322 | AstPtr::new(&field), | ||
323 | ) | ||
324 | } else { | ||
325 | self.missing_expr() | ||
326 | }, | ||
327 | }) | ||
328 | .collect(); | ||
329 | let spread = nfl.spread().map(|s| self.collect_expr(s)); | ||
330 | Expr::RecordLit { path, fields, spread } | ||
331 | } else { | ||
332 | Expr::RecordLit { path, fields: Vec::new(), spread: None } | ||
333 | }; | ||
334 | |||
335 | let res = self.alloc_expr(record_lit, syntax_ptr); | ||
336 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | ||
337 | self.source_map.field_map.insert((res, i), ptr); | ||
338 | } | ||
339 | res | ||
340 | } | ||
341 | ast::Expr::FieldExpr(e) => { | ||
342 | let expr = self.collect_expr_opt(e.expr()); | ||
343 | let name = match e.field_access() { | ||
344 | Some(kind) => kind.as_name(), | ||
345 | _ => Name::missing(), | ||
346 | }; | ||
347 | self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) | ||
348 | } | ||
349 | ast::Expr::AwaitExpr(e) => { | ||
350 | let expr = self.collect_expr_opt(e.expr()); | ||
351 | self.alloc_expr(Expr::Await { expr }, syntax_ptr) | ||
352 | } | ||
353 | ast::Expr::TryExpr(e) => { | ||
354 | let expr = self.collect_expr_opt(e.expr()); | ||
355 | self.alloc_expr(Expr::Try { expr }, syntax_ptr) | ||
356 | } | ||
357 | ast::Expr::CastExpr(e) => { | ||
358 | let expr = self.collect_expr_opt(e.expr()); | ||
359 | let type_ref = TypeRef::from_ast_opt(e.type_ref()); | ||
360 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | ||
361 | } | ||
362 | ast::Expr::RefExpr(e) => { | ||
363 | let expr = self.collect_expr_opt(e.expr()); | ||
364 | let mutability = Mutability::from_mutable(e.is_mut()); | ||
365 | self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) | ||
366 | } | ||
367 | ast::Expr::PrefixExpr(e) => { | ||
368 | let expr = self.collect_expr_opt(e.expr()); | ||
369 | if let Some(op) = e.op_kind() { | ||
370 | self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) | ||
371 | } else { | ||
372 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
373 | } | ||
374 | } | ||
375 | ast::Expr::LambdaExpr(e) => { | ||
376 | let mut args = Vec::new(); | ||
377 | let mut arg_types = Vec::new(); | ||
378 | if let Some(pl) = e.param_list() { | ||
379 | for param in pl.params() { | ||
380 | let pat = self.collect_pat_opt(param.pat()); | ||
381 | let type_ref = param.ascribed_type().map(TypeRef::from_ast); | ||
382 | args.push(pat); | ||
383 | arg_types.push(type_ref); | ||
384 | } | ||
385 | } | ||
386 | let body = self.collect_expr_opt(e.body()); | ||
387 | self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr) | ||
388 | } | ||
389 | ast::Expr::BinExpr(e) => { | ||
390 | let lhs = self.collect_expr_opt(e.lhs()); | ||
391 | let rhs = self.collect_expr_opt(e.rhs()); | ||
392 | let op = e.op_kind().map(BinaryOp::from); | ||
393 | self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) | ||
394 | } | ||
395 | ast::Expr::TupleExpr(e) => { | ||
396 | let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); | ||
397 | self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) | ||
398 | } | ||
399 | ast::Expr::BoxExpr(e) => { | ||
400 | let expr = self.collect_expr_opt(e.expr()); | ||
401 | self.alloc_expr(Expr::Box { expr }, syntax_ptr) | ||
402 | } | ||
403 | |||
404 | ast::Expr::ArrayExpr(e) => { | ||
405 | let kind = e.kind(); | ||
406 | |||
407 | match kind { | ||
408 | ArrayExprKind::ElementList(e) => { | ||
409 | let exprs = e.map(|expr| self.collect_expr(expr)).collect(); | ||
410 | self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr) | ||
411 | } | ||
412 | ArrayExprKind::Repeat { initializer, repeat } => { | ||
413 | let initializer = self.collect_expr_opt(initializer); | ||
414 | let repeat = self.collect_expr_opt(repeat); | ||
415 | self.alloc_expr( | ||
416 | Expr::Array(Array::Repeat { initializer, repeat }), | ||
417 | syntax_ptr, | ||
418 | ) | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | ast::Expr::Literal(e) => { | ||
424 | let lit = match e.kind() { | ||
425 | LiteralKind::IntNumber { suffix } => { | ||
426 | let known_name = suffix | ||
427 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); | ||
428 | |||
429 | Literal::Int( | ||
430 | Default::default(), | ||
431 | known_name.unwrap_or(UncertainIntTy::Unknown), | ||
432 | ) | ||
433 | } | ||
434 | LiteralKind::FloatNumber { suffix } => { | ||
435 | let known_name = suffix | ||
436 | .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); | ||
437 | |||
438 | Literal::Float( | ||
439 | Default::default(), | ||
440 | known_name.unwrap_or(UncertainFloatTy::Unknown), | ||
441 | ) | ||
442 | } | ||
443 | LiteralKind::ByteString => Literal::ByteString(Default::default()), | ||
444 | LiteralKind::String => Literal::String(Default::default()), | ||
445 | LiteralKind::Byte => { | ||
446 | Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) | ||
447 | } | ||
448 | LiteralKind::Bool => Literal::Bool(Default::default()), | ||
449 | LiteralKind::Char => Literal::Char(Default::default()), | ||
450 | }; | ||
451 | self.alloc_expr(Expr::Literal(lit), syntax_ptr) | ||
452 | } | ||
453 | ast::Expr::IndexExpr(e) => { | ||
454 | let base = self.collect_expr_opt(e.base()); | ||
455 | let index = self.collect_expr_opt(e.index()); | ||
456 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) | ||
457 | } | ||
458 | |||
459 | // FIXME implement HIR for these: | ||
460 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
461 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
462 | ast::Expr::MacroCall(e) => { | ||
463 | let ast_id = AstId::new( | ||
464 | self.current_file_id, | ||
465 | self.db.ast_id_map(self.current_file_id).ast_id(&e), | ||
466 | ); | ||
467 | |||
468 | if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { | ||
469 | if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { | ||
470 | let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id }); | ||
471 | let file_id = call_id.as_file(MacroFileKind::Expr); | ||
472 | if let Some(node) = self.db.parse_or_expand(file_id) { | ||
473 | if let Some(expr) = ast::Expr::cast(node) { | ||
474 | log::debug!("macro expansion {:#?}", expr.syntax()); | ||
475 | let old_file_id = | ||
476 | std::mem::replace(&mut self.current_file_id, file_id); | ||
477 | let id = self.collect_expr(expr); | ||
478 | self.current_file_id = old_file_id; | ||
479 | return id; | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | // FIXME: Instead of just dropping the error from expansion | ||
485 | // report it | ||
486 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | ||
492 | if let Some(expr) = expr { | ||
493 | self.collect_expr(expr) | ||
494 | } else { | ||
495 | self.missing_expr() | ||
496 | } | ||
497 | } | ||
498 | |||
499 | fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId { | ||
500 | let syntax_node_ptr = AstPtr::new(&expr.clone().into()); | ||
501 | let block = match expr.block() { | ||
502 | Some(block) => block, | ||
503 | None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), | ||
504 | }; | ||
505 | let statements = block | ||
506 | .statements() | ||
507 | .map(|s| match s { | ||
508 | ast::Stmt::LetStmt(stmt) => { | ||
509 | let pat = self.collect_pat_opt(stmt.pat()); | ||
510 | let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); | ||
511 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | ||
512 | Statement::Let { pat, type_ref, initializer } | ||
513 | } | ||
514 | ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), | ||
515 | }) | ||
516 | .collect(); | ||
517 | let tail = block.expr().map(|e| self.collect_expr(e)); | ||
518 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) | ||
519 | } | ||
520 | |||
521 | fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { | ||
522 | if let Some(block) = expr { | ||
523 | self.collect_block(block) | ||
524 | } else { | ||
525 | self.missing_expr() | ||
526 | } | ||
527 | } | ||
528 | |||
529 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { | ||
530 | let pattern = match &pat { | ||
531 | ast::Pat::BindPat(bp) => { | ||
532 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
533 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); | ||
534 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | ||
535 | Pat::Bind { name, mode: annotation, subpat } | ||
536 | } | ||
537 | ast::Pat::TupleStructPat(p) => { | ||
538 | let path = p.path().and_then(|path| self.parse_path(path)); | ||
539 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | ||
540 | Pat::TupleStruct { path, args } | ||
541 | } | ||
542 | ast::Pat::RefPat(p) => { | ||
543 | let pat = self.collect_pat_opt(p.pat()); | ||
544 | let mutability = Mutability::from_mutable(p.is_mut()); | ||
545 | Pat::Ref { pat, mutability } | ||
546 | } | ||
547 | ast::Pat::PathPat(p) => { | ||
548 | let path = p.path().and_then(|path| self.parse_path(path)); | ||
549 | path.map(Pat::Path).unwrap_or(Pat::Missing) | ||
550 | } | ||
551 | ast::Pat::TuplePat(p) => { | ||
552 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | ||
553 | Pat::Tuple(args) | ||
554 | } | ||
555 | ast::Pat::PlaceholderPat(_) => Pat::Wild, | ||
556 | ast::Pat::RecordPat(p) => { | ||
557 | let path = p.path().and_then(|path| self.parse_path(path)); | ||
558 | let record_field_pat_list = | ||
559 | p.record_field_pat_list().expect("every struct should have a field list"); | ||
560 | let mut fields: Vec<_> = record_field_pat_list | ||
561 | .bind_pats() | ||
562 | .filter_map(|bind_pat| { | ||
563 | let ast_pat = | ||
564 | ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat"); | ||
565 | let pat = self.collect_pat(ast_pat); | ||
566 | let name = bind_pat.name()?.as_name(); | ||
567 | Some(RecordFieldPat { name, pat }) | ||
568 | }) | ||
569 | .collect(); | ||
570 | let iter = record_field_pat_list.record_field_pats().filter_map(|f| { | ||
571 | let ast_pat = f.pat()?; | ||
572 | let pat = self.collect_pat(ast_pat); | ||
573 | let name = f.name()?.as_name(); | ||
574 | Some(RecordFieldPat { name, pat }) | ||
575 | }); | ||
576 | fields.extend(iter); | ||
577 | |||
578 | Pat::Record { path, args: fields } | ||
579 | } | ||
580 | |||
581 | // FIXME: implement | ||
582 | ast::Pat::DotDotPat(_) => Pat::Missing, | ||
583 | ast::Pat::BoxPat(_) => Pat::Missing, | ||
584 | ast::Pat::LiteralPat(_) => Pat::Missing, | ||
585 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, | ||
586 | }; | ||
587 | let ptr = AstPtr::new(&pat); | ||
588 | self.alloc_pat(pattern, Either::A(ptr)) | ||
589 | } | ||
590 | |||
591 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { | ||
592 | if let Some(pat) = pat { | ||
593 | self.collect_pat(pat) | ||
594 | } else { | ||
595 | self.missing_pat() | ||
596 | } | ||
597 | } | ||
598 | |||
599 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | ||
600 | let hygiene = Hygiene::new(self.db, self.current_file_id); | ||
601 | Path::from_src(path, &hygiene) | ||
602 | } | ||
603 | } | ||
604 | |||
605 | impl From<ast::BinOp> for BinaryOp { | ||
606 | fn from(ast_op: ast::BinOp) -> Self { | ||
607 | match ast_op { | ||
608 | ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or), | ||
609 | ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And), | ||
610 | ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), | ||
611 | ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), | ||
612 | ast::BinOp::LesserEqualTest => { | ||
613 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }) | ||
614 | } | ||
615 | ast::BinOp::GreaterEqualTest => { | ||
616 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }) | ||
617 | } | ||
618 | ast::BinOp::LesserTest => { | ||
619 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }) | ||
620 | } | ||
621 | ast::BinOp::GreaterTest => { | ||
622 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }) | ||
623 | } | ||
624 | ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add), | ||
625 | ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul), | ||
626 | ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub), | ||
627 | ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div), | ||
628 | ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem), | ||
629 | ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl), | ||
630 | ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr), | ||
631 | ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor), | ||
632 | ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr), | ||
633 | ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd), | ||
634 | ast::BinOp::Assignment => BinaryOp::Assignment { op: None }, | ||
635 | ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) }, | ||
636 | ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) }, | ||
637 | ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, | ||
638 | ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, | ||
639 | ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, | ||
640 | ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, | ||
641 | ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, | ||
642 | ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, | ||
643 | ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, | ||
644 | ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, | ||
645 | } | ||
646 | } | ||
647 | } | ||
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs deleted file mode 100644 index 5a1eade2c..000000000 --- a/crates/ra_hir/src/expr/scope.rs +++ /dev/null | |||
@@ -1,354 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_arena::{impl_arena_id, Arena, RawId}; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use crate::{ | ||
9 | db::HirDatabase, | ||
10 | expr::{Body, Expr, ExprId, Pat, PatId, Statement}, | ||
11 | DefWithBody, Name, | ||
12 | }; | ||
13 | |||
14 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
15 | pub struct ScopeId(RawId); | ||
16 | impl_arena_id!(ScopeId); | ||
17 | |||
18 | #[derive(Debug, PartialEq, Eq)] | ||
19 | pub struct ExprScopes { | ||
20 | body: Arc<Body>, | ||
21 | scopes: Arena<ScopeId, ScopeData>, | ||
22 | scope_by_expr: FxHashMap<ExprId, ScopeId>, | ||
23 | } | ||
24 | |||
25 | #[derive(Debug, PartialEq, Eq)] | ||
26 | pub(crate) struct ScopeEntry { | ||
27 | name: Name, | ||
28 | pat: PatId, | ||
29 | } | ||
30 | |||
31 | impl ScopeEntry { | ||
32 | pub(crate) fn name(&self) -> &Name { | ||
33 | &self.name | ||
34 | } | ||
35 | |||
36 | pub(crate) fn pat(&self) -> PatId { | ||
37 | self.pat | ||
38 | } | ||
39 | } | ||
40 | |||
41 | #[derive(Debug, PartialEq, Eq)] | ||
42 | pub(crate) struct ScopeData { | ||
43 | parent: Option<ScopeId>, | ||
44 | entries: Vec<ScopeEntry>, | ||
45 | } | ||
46 | |||
47 | impl ExprScopes { | ||
48 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { | ||
49 | let body = db.body_hir(def); | ||
50 | let res = ExprScopes::new(body); | ||
51 | Arc::new(res) | ||
52 | } | ||
53 | |||
54 | fn new(body: Arc<Body>) -> ExprScopes { | ||
55 | let mut scopes = ExprScopes { | ||
56 | body: body.clone(), | ||
57 | scopes: Arena::default(), | ||
58 | scope_by_expr: FxHashMap::default(), | ||
59 | }; | ||
60 | let root = scopes.root_scope(); | ||
61 | scopes.add_params_bindings(root, body.params()); | ||
62 | compute_expr_scopes(body.body_expr(), &body, &mut scopes, root); | ||
63 | scopes | ||
64 | } | ||
65 | |||
66 | pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
67 | &self.scopes[scope].entries | ||
68 | } | ||
69 | |||
70 | pub(crate) fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { | ||
71 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | ||
72 | } | ||
73 | |||
74 | pub(crate) fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
75 | self.scope_by_expr.get(&expr).copied() | ||
76 | } | ||
77 | |||
78 | pub(crate) fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> { | ||
79 | &self.scope_by_expr | ||
80 | } | ||
81 | |||
82 | fn root_scope(&mut self) -> ScopeId { | ||
83 | self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) | ||
84 | } | ||
85 | |||
86 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
87 | self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) | ||
88 | } | ||
89 | |||
90 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | ||
91 | match &body[pat] { | ||
92 | Pat::Bind { name, .. } => { | ||
93 | // bind can have a sub pattern, but it's actually not allowed | ||
94 | // to bind to things in there | ||
95 | let entry = ScopeEntry { name: name.clone(), pat }; | ||
96 | self.scopes[scope].entries.push(entry) | ||
97 | } | ||
98 | p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), | ||
99 | } | ||
100 | } | ||
101 | |||
102 | fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { | ||
103 | let body = Arc::clone(&self.body); | ||
104 | params.iter().for_each(|pat| self.add_bindings(&body, scope, *pat)); | ||
105 | } | ||
106 | |||
107 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | ||
108 | self.scope_by_expr.insert(node, scope); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | fn compute_block_scopes( | ||
113 | statements: &[Statement], | ||
114 | tail: Option<ExprId>, | ||
115 | body: &Body, | ||
116 | scopes: &mut ExprScopes, | ||
117 | mut scope: ScopeId, | ||
118 | ) { | ||
119 | for stmt in statements { | ||
120 | match stmt { | ||
121 | Statement::Let { pat, initializer, .. } => { | ||
122 | if let Some(expr) = initializer { | ||
123 | scopes.set_scope(*expr, scope); | ||
124 | compute_expr_scopes(*expr, body, scopes, scope); | ||
125 | } | ||
126 | scope = scopes.new_scope(scope); | ||
127 | scopes.add_bindings(body, scope, *pat); | ||
128 | } | ||
129 | Statement::Expr(expr) => { | ||
130 | scopes.set_scope(*expr, scope); | ||
131 | compute_expr_scopes(*expr, body, scopes, scope); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | if let Some(expr) = tail { | ||
136 | compute_expr_scopes(expr, body, scopes, scope); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | ||
141 | scopes.set_scope(expr, scope); | ||
142 | match &body[expr] { | ||
143 | Expr::Block { statements, tail } => { | ||
144 | compute_block_scopes(&statements, *tail, body, scopes, scope); | ||
145 | } | ||
146 | Expr::For { iterable, pat, body: body_expr } => { | ||
147 | compute_expr_scopes(*iterable, body, scopes, scope); | ||
148 | let scope = scopes.new_scope(scope); | ||
149 | scopes.add_bindings(body, scope, *pat); | ||
150 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
151 | } | ||
152 | Expr::Lambda { args, body: body_expr, .. } => { | ||
153 | let scope = scopes.new_scope(scope); | ||
154 | scopes.add_params_bindings(scope, &args); | ||
155 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
156 | } | ||
157 | Expr::Match { expr, arms } => { | ||
158 | compute_expr_scopes(*expr, body, scopes, scope); | ||
159 | for arm in arms { | ||
160 | let scope = scopes.new_scope(scope); | ||
161 | for pat in &arm.pats { | ||
162 | scopes.add_bindings(body, scope, *pat); | ||
163 | } | ||
164 | scopes.set_scope(arm.expr, scope); | ||
165 | compute_expr_scopes(arm.expr, body, scopes, scope); | ||
166 | } | ||
167 | } | ||
168 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), | ||
169 | }; | ||
170 | } | ||
171 | |||
172 | #[cfg(test)] | ||
173 | mod tests { | ||
174 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
175 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
176 | use test_utils::{assert_eq_text, extract_offset}; | ||
177 | |||
178 | use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; | ||
179 | |||
180 | fn do_check(code: &str, expected: &[&str]) { | ||
181 | let (off, code) = extract_offset(code); | ||
182 | let code = { | ||
183 | let mut buf = String::new(); | ||
184 | let off = u32::from(off) as usize; | ||
185 | buf.push_str(&code[..off]); | ||
186 | buf.push_str("marker"); | ||
187 | buf.push_str(&code[off..]); | ||
188 | buf | ||
189 | }; | ||
190 | |||
191 | let (db, file_id) = TestDB::with_single_file(&code); | ||
192 | let file = db.parse(file_id).ok().unwrap(); | ||
193 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | ||
194 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); | ||
195 | |||
196 | let scopes = analyzer.scopes(); | ||
197 | let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap(); | ||
198 | let scope = scopes.scope_for(expr_id); | ||
199 | |||
200 | let actual = scopes | ||
201 | .scope_chain(scope) | ||
202 | .flat_map(|scope| scopes.entries(scope)) | ||
203 | .map(|it| it.name().to_string()) | ||
204 | .collect::<Vec<_>>() | ||
205 | .join("\n"); | ||
206 | let expected = expected.join("\n"); | ||
207 | assert_eq_text!(&expected, &actual); | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn test_lambda_scope() { | ||
212 | do_check( | ||
213 | r" | ||
214 | fn quux(foo: i32) { | ||
215 | let f = |bar, baz: i32| { | ||
216 | <|> | ||
217 | }; | ||
218 | }", | ||
219 | &["bar", "baz", "foo"], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn test_call_scope() { | ||
225 | do_check( | ||
226 | r" | ||
227 | fn quux() { | ||
228 | f(|x| <|> ); | ||
229 | }", | ||
230 | &["x"], | ||
231 | ); | ||
232 | } | ||
233 | |||
234 | #[test] | ||
235 | fn test_method_call_scope() { | ||
236 | do_check( | ||
237 | r" | ||
238 | fn quux() { | ||
239 | z.f(|x| <|> ); | ||
240 | }", | ||
241 | &["x"], | ||
242 | ); | ||
243 | } | ||
244 | |||
245 | #[test] | ||
246 | fn test_loop_scope() { | ||
247 | do_check( | ||
248 | r" | ||
249 | fn quux() { | ||
250 | loop { | ||
251 | let x = (); | ||
252 | <|> | ||
253 | }; | ||
254 | }", | ||
255 | &["x"], | ||
256 | ); | ||
257 | } | ||
258 | |||
259 | #[test] | ||
260 | fn test_match() { | ||
261 | do_check( | ||
262 | r" | ||
263 | fn quux() { | ||
264 | match () { | ||
265 | Some(x) => { | ||
266 | <|> | ||
267 | } | ||
268 | }; | ||
269 | }", | ||
270 | &["x"], | ||
271 | ); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn test_shadow_variable() { | ||
276 | do_check( | ||
277 | r" | ||
278 | fn foo(x: String) { | ||
279 | let x : &str = &x<|>; | ||
280 | }", | ||
281 | &["x"], | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | fn do_check_local_name(code: &str, expected_offset: u32) { | ||
286 | let (off, code) = extract_offset(code); | ||
287 | |||
288 | let (db, file_id) = TestDB::with_single_file(&code); | ||
289 | let file = db.parse(file_id).ok().unwrap(); | ||
290 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
291 | .expect("failed to find a name at the target offset"); | ||
292 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
293 | let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); | ||
294 | |||
295 | let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); | ||
296 | let local_name = | ||
297 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
298 | assert_eq!(local_name.range(), expected_name.syntax().text_range()); | ||
299 | } | ||
300 | |||
301 | #[test] | ||
302 | fn test_resolve_local_name() { | ||
303 | do_check_local_name( | ||
304 | r#" | ||
305 | fn foo(x: i32, y: u32) { | ||
306 | { | ||
307 | let z = x * 2; | ||
308 | } | ||
309 | { | ||
310 | let t = x<|> * 3; | ||
311 | } | ||
312 | }"#, | ||
313 | 21, | ||
314 | ); | ||
315 | } | ||
316 | |||
317 | #[test] | ||
318 | fn test_resolve_local_name_declaration() { | ||
319 | do_check_local_name( | ||
320 | r#" | ||
321 | fn foo(x: String) { | ||
322 | let x : &str = &x<|>; | ||
323 | }"#, | ||
324 | 21, | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn test_resolve_local_name_shadow() { | ||
330 | do_check_local_name( | ||
331 | r" | ||
332 | fn foo(x: String) { | ||
333 | let x : &str = &x; | ||
334 | x<|> | ||
335 | } | ||
336 | ", | ||
337 | 53, | ||
338 | ); | ||
339 | } | ||
340 | |||
341 | #[test] | ||
342 | fn ref_patterns_contribute_bindings() { | ||
343 | do_check_local_name( | ||
344 | r" | ||
345 | fn foo() { | ||
346 | if let Some(&from) = bar() { | ||
347 | from<|>; | ||
348 | } | ||
349 | } | ||
350 | ", | ||
351 | 53, | ||
352 | ); | ||
353 | } | ||
354 | } | ||
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index 089dbc908..9633ef586 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs | |||
@@ -3,9 +3,9 @@ | |||
3 | //! It's unclear if we need this long-term, but it's definitelly useful while we | 3 | //! It's unclear if we need this long-term, but it's definitelly useful while we |
4 | //! are splitting the hir. | 4 | //! are splitting the hir. |
5 | 5 | ||
6 | use hir_def::{AdtId, EnumVariantId, ModuleDefId}; | 6 | use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; |
7 | 7 | ||
8 | use crate::{Adt, EnumVariant, ModuleDef}; | 8 | use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; |
9 | 9 | ||
10 | macro_rules! from_id { | 10 | macro_rules! from_id { |
11 | ($(($id:path, $ty:path)),*) => {$( | 11 | ($(($id:path, $ty:path)),*) => {$( |
@@ -61,3 +61,13 @@ impl From<ModuleDefId> for ModuleDef { | |||
61 | } | 61 | } |
62 | } | 62 | } |
63 | } | 63 | } |
64 | |||
65 | impl From<DefWithBody> for DefWithBodyId { | ||
66 | fn from(def: DefWithBody) -> Self { | ||
67 | match def { | ||
68 | DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id), | ||
69 | DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), | ||
70 | DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), | ||
71 | } | ||
72 | } | ||
73 | } | ||
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index c95d2cdd0..9793af858 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -2,13 +2,17 @@ | |||
2 | 2 | ||
3 | use hir_def::{StructId, StructOrUnionId, UnionId}; | 3 | use hir_def::{StructId, StructOrUnionId, UnionId}; |
4 | use hir_expand::name::AsName; | 4 | use hir_expand::name::AsName; |
5 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | ||
7 | match_ast, | ||
8 | }; | ||
6 | 9 | ||
7 | use crate::{ | 10 | use crate::{ |
8 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
9 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
10 | AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, | 13 | AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, |
11 | ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, | 14 | ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, |
15 | Union, VariantDef, | ||
12 | }; | 16 | }; |
13 | 17 | ||
14 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -126,6 +130,27 @@ impl FromSource for StructField { | |||
126 | } | 130 | } |
127 | } | 131 | } |
128 | 132 | ||
133 | impl Local { | ||
134 | pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { | ||
135 | let file_id = src.file_id; | ||
136 | let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| { | ||
137 | let res = match_ast! { | ||
138 | match it { | ||
139 | ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() }, | ||
140 | ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() }, | ||
141 | ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() }, | ||
142 | _ => return None, | ||
143 | } | ||
144 | }; | ||
145 | Some(res) | ||
146 | })?; | ||
147 | let source_map = parent.body_source_map(db); | ||
148 | let src = src.map(ast::Pat::from); | ||
149 | let pat_id = source_map.node_pat(src.as_ref())?; | ||
150 | Some(Local { parent, pat_id }) | ||
151 | } | ||
152 | } | ||
153 | |||
129 | impl Module { | 154 | impl Module { |
130 | pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { | 155 | pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { |
131 | let src_parent = Source { | 156 | let src_parent = Source { |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 131f6c797..5ba847d35 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -39,7 +39,7 @@ mod ty; | |||
39 | mod impl_block; | 39 | mod impl_block; |
40 | mod expr; | 40 | mod expr; |
41 | mod lang_item; | 41 | mod lang_item; |
42 | mod generics; | 42 | pub mod generics; |
43 | mod resolve; | 43 | mod resolve; |
44 | pub mod diagnostics; | 44 | pub mod diagnostics; |
45 | mod util; | 45 | mod util; |
@@ -65,18 +65,20 @@ pub use crate::{ | |||
65 | docs::{DocDef, Docs, Documentation}, | 65 | docs::{DocDef, Docs, Documentation}, |
66 | src::{HasBodySource, HasSource}, | 66 | src::{HasBodySource, HasSource}, |
67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
68 | EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, | 68 | EnumVariant, FieldSource, FnData, Function, GenericParam, HasBody, Local, MacroDef, Module, |
69 | ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, | 69 | ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, |
70 | }, | 70 | }, |
71 | expr::ExprScopes, | 71 | expr::ExprScopes, |
72 | from_source::FromSource, | 72 | from_source::FromSource, |
73 | generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, | 73 | generics::GenericDef, |
74 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, | 74 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, |
75 | impl_block::ImplBlock, | 75 | impl_block::ImplBlock, |
76 | resolve::ScopeDef, | 76 | resolve::ScopeDef, |
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | ty::{ | 78 | ty::{ |
79 | display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 79 | display::HirDisplay, |
80 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, | ||
81 | ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | ||
80 | }, | 82 | }, |
81 | }; | 83 | }; |
82 | 84 | ||
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 0d4fa5b67..0f754eb9c 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -5,6 +5,5 @@ test_utils::marks!( | |||
5 | type_var_cycles_resolve_as_possible | 5 | type_var_cycles_resolve_as_possible |
6 | type_var_resolves_to_int_var | 6 | type_var_resolves_to_int_var |
7 | match_ergonomics_ref | 7 | match_ergonomics_ref |
8 | infer_while_let | ||
9 | coerce_merge_fail_fallback | 8 | coerce_merge_fail_fallback |
10 | ); | 9 | ); |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index b932b0c8c..2f3e12eb8 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -13,10 +13,7 @@ use rustc_hash::FxHashSet; | |||
13 | use crate::{ | 13 | use crate::{ |
14 | code_model::Crate, | 14 | code_model::Crate, |
15 | db::{DefDatabase, HirDatabase}, | 15 | db::{DefDatabase, HirDatabase}, |
16 | expr::{ | 16 | expr::{ExprScopes, PatId, ScopeId}, |
17 | scope::{ExprScopes, ScopeId}, | ||
18 | PatId, | ||
19 | }, | ||
20 | generics::GenericParams, | 17 | generics::GenericParams, |
21 | impl_block::ImplBlock, | 18 | impl_block::ImplBlock, |
22 | Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, | 19 | Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 66cb4b357..ca40e3b54 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -7,8 +7,11 @@ | |||
7 | //! purely for "IDE needs". | 7 | //! purely for "IDE needs". |
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use hir_def::path::known; | 10 | use hir_def::{ |
11 | use hir_expand::name::AsName; | 11 | expr::{ExprId, PatId}, |
12 | path::known, | ||
13 | }; | ||
14 | use hir_expand::{name::AsName, Source}; | ||
12 | use ra_db::FileId; | 15 | use ra_db::FileId; |
13 | use ra_syntax::{ | 16 | use ra_syntax::{ |
14 | ast::{self, AstNode}, | 17 | ast::{self, AstNode}, |
@@ -20,16 +23,12 @@ use rustc_hash::FxHashSet; | |||
20 | 23 | ||
21 | use crate::{ | 24 | use crate::{ |
22 | db::HirDatabase, | 25 | db::HirDatabase, |
23 | expr::{ | 26 | expr::{self, BodySourceMap, ExprScopes, ScopeId}, |
24 | self, | ||
25 | scope::{ExprScopes, ScopeId}, | ||
26 | BodySourceMap, | ||
27 | }, | ||
28 | ids::LocationCtx, | 27 | ids::LocationCtx, |
29 | resolve::{ScopeDef, TypeNs, ValueNs}, | 28 | resolve::{ScopeDef, TypeNs, ValueNs}, |
30 | ty::method_resolution::{self, implements_trait}, | 29 | ty::method_resolution::{self, implements_trait}, |
31 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, | 30 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, GenericParam, HasBody, |
32 | MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, | 31 | HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, |
33 | }; | 32 | }; |
34 | 33 | ||
35 | fn try_get_resolver_for_node( | 34 | fn try_get_resolver_for_node( |
@@ -93,7 +92,10 @@ fn def_with_body_from_child_node( | |||
93 | /// original source files. It should not be used inside the HIR itself. | 92 | /// original source files. It should not be used inside the HIR itself. |
94 | #[derive(Debug)] | 93 | #[derive(Debug)] |
95 | pub struct SourceAnalyzer { | 94 | pub struct SourceAnalyzer { |
95 | // FIXME: this doesn't handle macros at all | ||
96 | file_id: FileId, | ||
96 | resolver: Resolver, | 97 | resolver: Resolver, |
98 | body_owner: Option<DefWithBody>, | ||
97 | body_source_map: Option<Arc<BodySourceMap>>, | 99 | body_source_map: Option<Arc<BodySourceMap>>, |
98 | infer: Option<Arc<crate::ty::InferenceResult>>, | 100 | infer: Option<Arc<crate::ty::InferenceResult>>, |
99 | scopes: Option<Arc<crate::expr::ExprScopes>>, | 101 | scopes: Option<Arc<crate::expr::ExprScopes>>, |
@@ -104,9 +106,9 @@ pub enum PathResolution { | |||
104 | /// An item | 106 | /// An item |
105 | Def(crate::ModuleDef), | 107 | Def(crate::ModuleDef), |
106 | /// A local binding (only value namespace) | 108 | /// A local binding (only value namespace) |
107 | LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>), | 109 | Local(Local), |
108 | /// A generic parameter | 110 | /// A generic parameter |
109 | GenericParam(u32), | 111 | GenericParam(GenericParam), |
110 | SelfType(crate::ImplBlock), | 112 | SelfType(crate::ImplBlock), |
111 | Macro(MacroDef), | 113 | Macro(MacroDef), |
112 | AssocItem(crate::AssocItem), | 114 | AssocItem(crate::AssocItem), |
@@ -144,17 +146,19 @@ impl SourceAnalyzer { | |||
144 | let def_with_body = def_with_body_from_child_node(db, file_id, node); | 146 | let def_with_body = def_with_body_from_child_node(db, file_id, node); |
145 | if let Some(def) = def_with_body { | 147 | if let Some(def) = def_with_body { |
146 | let source_map = def.body_source_map(db); | 148 | let source_map = def.body_source_map(db); |
147 | let scopes = db.expr_scopes(def); | 149 | let scopes = def.expr_scopes(db); |
148 | let scope = match offset { | 150 | let scope = match offset { |
149 | None => scope_for(&scopes, &source_map, &node), | 151 | None => scope_for(&scopes, &source_map, file_id.into(), &node), |
150 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), | 152 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), |
151 | }; | 153 | }; |
152 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | 154 | let resolver = expr::resolver_for_scope(db, def, scope); |
153 | SourceAnalyzer { | 155 | SourceAnalyzer { |
154 | resolver, | 156 | resolver, |
157 | body_owner: Some(def), | ||
155 | body_source_map: Some(source_map), | 158 | body_source_map: Some(source_map), |
156 | infer: Some(def.infer(db)), | 159 | infer: Some(def.infer(db)), |
157 | scopes: Some(scopes), | 160 | scopes: Some(scopes), |
161 | file_id, | ||
158 | } | 162 | } |
159 | } else { | 163 | } else { |
160 | SourceAnalyzer { | 164 | SourceAnalyzer { |
@@ -162,20 +166,32 @@ impl SourceAnalyzer { | |||
162 | .ancestors() | 166 | .ancestors() |
163 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) | 167 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) |
164 | .unwrap_or_default(), | 168 | .unwrap_or_default(), |
169 | body_owner: None, | ||
165 | body_source_map: None, | 170 | body_source_map: None, |
166 | infer: None, | 171 | infer: None, |
167 | scopes: None, | 172 | scopes: None, |
173 | file_id, | ||
168 | } | 174 | } |
169 | } | 175 | } |
170 | } | 176 | } |
171 | 177 | ||
178 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { | ||
179 | let src = Source { file_id: self.file_id.into(), ast: expr }; | ||
180 | self.body_source_map.as_ref()?.node_expr(src) | ||
181 | } | ||
182 | |||
183 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { | ||
184 | let src = Source { file_id: self.file_id.into(), ast: pat }; | ||
185 | self.body_source_map.as_ref()?.node_pat(src) | ||
186 | } | ||
187 | |||
172 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { | 188 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { |
173 | let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; | 189 | let expr_id = self.expr_id(expr)?; |
174 | Some(self.infer.as_ref()?[expr_id].clone()) | 190 | Some(self.infer.as_ref()?[expr_id].clone()) |
175 | } | 191 | } |
176 | 192 | ||
177 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { | 193 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { |
178 | let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; | 194 | let pat_id = self.pat_id(pat)?; |
179 | Some(self.infer.as_ref()?[pat_id].clone()) | 195 | Some(self.infer.as_ref()?[pat_id].clone()) |
180 | } | 196 | } |
181 | 197 | ||
@@ -188,22 +204,22 @@ impl SourceAnalyzer { | |||
188 | } | 204 | } |
189 | 205 | ||
190 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 206 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
191 | let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; | 207 | let expr_id = self.expr_id(&call.clone().into())?; |
192 | self.infer.as_ref()?.method_resolution(expr_id) | 208 | self.infer.as_ref()?.method_resolution(expr_id) |
193 | } | 209 | } |
194 | 210 | ||
195 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | 211 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { |
196 | let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; | 212 | let expr_id = self.expr_id(&field.clone().into())?; |
197 | self.infer.as_ref()?.field_resolution(expr_id) | 213 | self.infer.as_ref()?.field_resolution(expr_id) |
198 | } | 214 | } |
199 | 215 | ||
200 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { | 216 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { |
201 | let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; | 217 | let expr_id = self.expr_id(&record_lit.clone().into())?; |
202 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) | 218 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) |
203 | } | 219 | } |
204 | 220 | ||
205 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { | 221 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { |
206 | let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; | 222 | let pat_id = self.pat_id(&record_pat.clone().into())?; |
207 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) | 223 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) |
208 | } | 224 | } |
209 | 225 | ||
@@ -224,7 +240,10 @@ impl SourceAnalyzer { | |||
224 | ) -> Option<PathResolution> { | 240 | ) -> Option<PathResolution> { |
225 | let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { | 241 | let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { |
226 | TypeNs::SelfType(it) => PathResolution::SelfType(it), | 242 | TypeNs::SelfType(it) => PathResolution::SelfType(it), |
227 | TypeNs::GenericParam(it) => PathResolution::GenericParam(it), | 243 | TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { |
244 | parent: self.resolver.generic_def().unwrap(), | ||
245 | idx, | ||
246 | }), | ||
228 | TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()), | 247 | TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()), |
229 | TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), | 248 | TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), |
230 | TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), | 249 | TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), |
@@ -233,16 +252,9 @@ impl SourceAnalyzer { | |||
233 | }); | 252 | }); |
234 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { | 253 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { |
235 | let res = match val { | 254 | let res = match val { |
236 | ValueNs::LocalBinding(it) => { | 255 | ValueNs::LocalBinding(pat_id) => { |
237 | // We get a `PatId` from resolver, but it actually can only | 256 | let var = Local { parent: self.body_owner?, pat_id }; |
238 | // point at `BindPat`, and not at the arbitrary pattern. | 257 | PathResolution::Local(var) |
239 | let pat_ptr = self | ||
240 | .body_source_map | ||
241 | .as_ref()? | ||
242 | .pat_syntax(it)? | ||
243 | .ast // FIXME: ignoring file_id here is definitelly wrong | ||
244 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); | ||
245 | PathResolution::LocalBinding(pat_ptr) | ||
246 | } | 258 | } |
247 | ValueNs::Function(it) => PathResolution::Def(it.into()), | 259 | ValueNs::Function(it) => PathResolution::Def(it.into()), |
248 | ValueNs::Const(it) => PathResolution::Def(it.into()), | 260 | ValueNs::Const(it) => PathResolution::Def(it.into()), |
@@ -265,13 +277,13 @@ impl SourceAnalyzer { | |||
265 | 277 | ||
266 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 278 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { |
267 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 279 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
268 | let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; | 280 | let expr_id = self.expr_id(&path_expr.into())?; |
269 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 281 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { |
270 | return Some(PathResolution::AssocItem(assoc)); | 282 | return Some(PathResolution::AssocItem(assoc)); |
271 | } | 283 | } |
272 | } | 284 | } |
273 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | 285 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { |
274 | let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; | 286 | let pat_id = self.pat_id(&path_pat.into())?; |
275 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | 287 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { |
276 | return Some(PathResolution::AssocItem(assoc)); | 288 | return Some(PathResolution::AssocItem(assoc)); |
277 | } | 289 | } |
@@ -286,7 +298,7 @@ impl SourceAnalyzer { | |||
286 | let name = name_ref.as_name(); | 298 | let name = name_ref.as_name(); |
287 | let source_map = self.body_source_map.as_ref()?; | 299 | let source_map = self.body_source_map.as_ref()?; |
288 | let scopes = self.scopes.as_ref()?; | 300 | let scopes = self.scopes.as_ref()?; |
289 | let scope = scope_for(scopes, source_map, name_ref.syntax()); | 301 | let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); |
290 | let ret = scopes | 302 | let ret = scopes |
291 | .scope_chain(scope) | 303 | .scope_chain(scope) |
292 | .flat_map(|scope| scopes.entries(scope).iter()) | 304 | .flat_map(|scope| scopes.entries(scope).iter()) |
@@ -419,11 +431,12 @@ impl SourceAnalyzer { | |||
419 | fn scope_for( | 431 | fn scope_for( |
420 | scopes: &ExprScopes, | 432 | scopes: &ExprScopes, |
421 | source_map: &BodySourceMap, | 433 | source_map: &BodySourceMap, |
434 | file_id: HirFileId, | ||
422 | node: &SyntaxNode, | 435 | node: &SyntaxNode, |
423 | ) -> Option<ScopeId> { | 436 | ) -> Option<ScopeId> { |
424 | node.ancestors() | 437 | node.ancestors() |
425 | .filter_map(ast::Expr::cast) | 438 | .filter_map(ast::Expr::cast) |
426 | .filter_map(|it| source_map.node_expr(&it)) | 439 | .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) |
427 | .find_map(|it| scopes.scope_for(it)) | 440 | .find_map(|it| scopes.scope_for(it)) |
428 | } | 441 | } |
429 | 442 | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index cd2ac0e8b..ff6030ac4 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -17,8 +17,11 @@ use std::sync::Arc; | |||
17 | use std::{fmt, iter, mem}; | 17 | use std::{fmt, iter, mem}; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | db::HirDatabase, expr::ExprId, util::make_mut_slice, Adt, Crate, DefWithBody, GenericParams, | 20 | db::HirDatabase, |
21 | HasGenericParams, Mutability, Name, Trait, TypeAlias, | 21 | expr::ExprId, |
22 | generics::{GenericParams, HasGenericParams}, | ||
23 | util::make_mut_slice, | ||
24 | Adt, Crate, DefWithBody, FloatTy, IntTy, Mutability, Name, Trait, TypeAlias, Uncertain, | ||
22 | }; | 25 | }; |
23 | use display::{HirDisplay, HirFormatter}; | 26 | use display::{HirDisplay, HirFormatter}; |
24 | 27 | ||
@@ -44,10 +47,10 @@ pub enum TypeCtor { | |||
44 | Char, | 47 | Char, |
45 | 48 | ||
46 | /// A primitive integer type. For example, `i32`. | 49 | /// A primitive integer type. For example, `i32`. |
47 | Int(primitive::UncertainIntTy), | 50 | Int(Uncertain<IntTy>), |
48 | 51 | ||
49 | /// A primitive floating-point type. For example, `f64`. | 52 | /// A primitive floating-point type. For example, `f64`. |
50 | Float(primitive::UncertainFloatTy), | 53 | Float(Uncertain<FloatTy>), |
51 | 54 | ||
52 | /// Structures, enumerations and unions. | 55 | /// Structures, enumerations and unions. |
53 | Adt(Adt), | 56 | Adt(Adt), |
@@ -342,10 +345,7 @@ impl Substs { | |||
342 | ) | 345 | ) |
343 | } | 346 | } |
344 | 347 | ||
345 | pub fn build_for_def( | 348 | pub fn build_for_def(db: &impl HirDatabase, def: impl HasGenericParams) -> SubstsBuilder { |
346 | db: &impl HirDatabase, | ||
347 | def: impl crate::HasGenericParams, | ||
348 | ) -> SubstsBuilder { | ||
349 | let params = def.generic_params(db); | 349 | let params = def.generic_params(db); |
350 | let param_count = params.count_params_including_parent(); | 350 | let param_count = params.count_params_including_parent(); |
351 | Substs::builder(param_count) | 351 | Substs::builder(param_count) |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 3645ee831..872a4517d 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -9,7 +9,7 @@ use hir_expand::name; | |||
9 | use log::{info, warn}; | 9 | use log::{info, warn}; |
10 | 10 | ||
11 | use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; | 11 | use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, HasGenericParams, Resolver}; | 12 | use crate::{db::HirDatabase, generics::HasGenericParams, Resolver}; |
13 | 13 | ||
14 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 14 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
15 | 15 | ||
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 2370e8d4f..c35378cc4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -31,10 +31,10 @@ use ra_prof::profile; | |||
31 | use test_utils::tested_by; | 31 | use test_utils::tested_by; |
32 | 32 | ||
33 | use super::{ | 33 | use super::{ |
34 | lower, primitive, | 34 | lower, |
35 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 35 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
36 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, | 36 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, |
37 | TypeCtor, TypeWalk, | 37 | TypeCtor, TypeWalk, Uncertain, |
38 | }; | 38 | }; |
39 | use crate::{ | 39 | use crate::{ |
40 | adt::VariantDef, | 40 | adt::VariantDef, |
@@ -43,7 +43,8 @@ use crate::{ | |||
43 | expr::{BindingAnnotation, Body, ExprId, PatId}, | 43 | expr::{BindingAnnotation, Body, ExprId, PatId}, |
44 | resolve::{Resolver, TypeNs}, | 44 | resolve::{Resolver, TypeNs}, |
45 | ty::infer::diagnostics::InferenceDiagnostic, | 45 | ty::infer::diagnostics::InferenceDiagnostic, |
46 | Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Path, StructField, | 46 | Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, HasBody, IntTy, Path, |
47 | StructField, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | macro_rules! ty_app { | 50 | macro_rules! ty_app { |
@@ -64,9 +65,8 @@ mod coerce; | |||
64 | /// The entry point of type inference. | 65 | /// The entry point of type inference. |
65 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 66 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
66 | let _p = profile("infer_query"); | 67 | let _p = profile("infer_query"); |
67 | let body = def.body(db); | ||
68 | let resolver = def.resolver(db); | 68 | let resolver = def.resolver(db); |
69 | let mut ctx = InferenceContext::new(db, body, resolver); | 69 | let mut ctx = InferenceContext::new(db, def, resolver); |
70 | 70 | ||
71 | match def { | 71 | match def { |
72 | DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), | 72 | DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), |
@@ -187,6 +187,7 @@ impl Index<PatId> for InferenceResult { | |||
187 | #[derive(Clone, Debug)] | 187 | #[derive(Clone, Debug)] |
188 | struct InferenceContext<'a, D: HirDatabase> { | 188 | struct InferenceContext<'a, D: HirDatabase> { |
189 | db: &'a D, | 189 | db: &'a D, |
190 | owner: DefWithBody, | ||
190 | body: Arc<Body>, | 191 | body: Arc<Body>, |
191 | resolver: Resolver, | 192 | resolver: Resolver, |
192 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 193 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
@@ -204,7 +205,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
204 | } | 205 | } |
205 | 206 | ||
206 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 207 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
207 | fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { | 208 | fn new(db: &'a D, owner: DefWithBody, resolver: Resolver) -> Self { |
208 | InferenceContext { | 209 | InferenceContext { |
209 | result: InferenceResult::default(), | 210 | result: InferenceResult::default(), |
210 | var_unification_table: InPlaceUnificationTable::new(), | 211 | var_unification_table: InPlaceUnificationTable::new(), |
@@ -213,7 +214,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
213 | trait_env: lower::trait_env(db, &resolver), | 214 | trait_env: lower::trait_env(db, &resolver), |
214 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | 215 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), |
215 | db, | 216 | db, |
216 | body, | 217 | owner, |
218 | body: owner.body(db), | ||
217 | resolver, | 219 | resolver, |
218 | } | 220 | } |
219 | } | 221 | } |
@@ -357,14 +359,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
357 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | 359 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { |
358 | match ty { | 360 | match ty { |
359 | Ty::Unknown => self.new_type_var(), | 361 | Ty::Unknown => self.new_type_var(), |
360 | Ty::Apply(ApplicationTy { | 362 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { |
361 | ctor: TypeCtor::Int(primitive::UncertainIntTy::Unknown), | 363 | self.new_integer_var() |
362 | .. | 364 | } |
363 | }) => self.new_integer_var(), | 365 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { |
364 | Ty::Apply(ApplicationTy { | 366 | self.new_float_var() |
365 | ctor: TypeCtor::Float(primitive::UncertainFloatTy::Unknown), | 367 | } |
366 | .. | ||
367 | }) => self.new_float_var(), | ||
368 | _ => ty, | 368 | _ => ty, |
369 | } | 369 | } |
370 | } | 370 | } |
@@ -683,12 +683,8 @@ impl InferTy { | |||
683 | fn fallback_value(self) -> Ty { | 683 | fn fallback_value(self) -> Ty { |
684 | match self { | 684 | match self { |
685 | InferTy::TypeVar(..) => Ty::Unknown, | 685 | InferTy::TypeVar(..) => Ty::Unknown, |
686 | InferTy::IntVar(..) => { | 686 | InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), |
687 | Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(primitive::IntTy::i32()))) | 687 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), |
688 | } | ||
689 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float( | ||
690 | primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()), | ||
691 | )), | ||
692 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), | 688 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), |
693 | } | 689 | } |
694 | } | 690 | } |
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 4af1d65ee..5e68a1678 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::path::{GenericArg, GenericArgs}; | 6 | use hir_def::{ |
7 | builtin_type::Signedness, | ||
8 | path::{GenericArg, GenericArgs}, | ||
9 | }; | ||
7 | use hir_expand::name; | 10 | use hir_expand::name; |
8 | 11 | ||
9 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 12 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; |
@@ -12,8 +15,9 @@ use crate::{ | |||
12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | 15 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, |
13 | generics::{GenericParams, HasGenericParams}, | 16 | generics::{GenericParams, HasGenericParams}, |
14 | ty::{ | 17 | ty::{ |
15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, | 18 | autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace, |
16 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 19 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, |
20 | Uncertain, | ||
17 | }, | 21 | }, |
18 | Adt, Name, | 22 | Adt, Name, |
19 | }; | 23 | }; |
@@ -130,10 +134,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
130 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 134 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, |
131 | Substs(sig_tys.into()), | 135 | Substs(sig_tys.into()), |
132 | ); | 136 | ); |
133 | let closure_ty = Ty::apply_one( | 137 | let closure_ty = |
134 | TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, | 138 | Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); |
135 | sig_ty, | ||
136 | ); | ||
137 | 139 | ||
138 | // Eagerly try to relate the closure type with the expected | 140 | // Eagerly try to relate the closure type with the expected |
139 | // type, otherwise we often won't have enough information to | 141 | // type, otherwise we often won't have enough information to |
@@ -184,7 +186,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
184 | } | 186 | } |
185 | Expr::Path(p) => { | 187 | Expr::Path(p) => { |
186 | // FIXME this could be more efficient... | 188 | // FIXME this could be more efficient... |
187 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); | 189 | let resolver = expr::resolver_for_expr(self.db, self.owner, tgt_expr); |
188 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | 190 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
189 | } | 191 | } |
190 | Expr::Continue => Ty::simple(TypeCtor::Never), | 192 | Expr::Continue => Ty::simple(TypeCtor::Never), |
@@ -339,13 +341,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
339 | UnaryOp::Neg => { | 341 | UnaryOp::Neg => { |
340 | match &inner_ty { | 342 | match &inner_ty { |
341 | Ty::Apply(a_ty) => match a_ty.ctor { | 343 | Ty::Apply(a_ty) => match a_ty.ctor { |
342 | TypeCtor::Int(primitive::UncertainIntTy::Unknown) | 344 | TypeCtor::Int(Uncertain::Unknown) |
343 | | TypeCtor::Int(primitive::UncertainIntTy::Known( | 345 | | TypeCtor::Int(Uncertain::Known(IntTy { |
344 | primitive::IntTy { | 346 | signedness: Signedness::Signed, |
345 | signedness: primitive::Signedness::Signed, | 347 | .. |
346 | .. | 348 | })) |
347 | }, | ||
348 | )) | ||
349 | | TypeCtor::Float(..) => inner_ty, | 349 | | TypeCtor::Float(..) => inner_ty, |
350 | _ => Ty::Unknown, | 350 | _ => Ty::Unknown, |
351 | }, | 351 | }, |
@@ -430,9 +430,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
430 | ); | 430 | ); |
431 | self.infer_expr( | 431 | self.infer_expr( |
432 | *repeat, | 432 | *repeat, |
433 | &Expectation::has_type(Ty::simple(TypeCtor::Int( | 433 | &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( |
434 | primitive::UncertainIntTy::Known(primitive::IntTy::usize()), | 434 | IntTy::usize(), |
435 | ))), | 435 | )))), |
436 | ); | 436 | ); |
437 | } | 437 | } |
438 | } | 438 | } |
@@ -445,15 +445,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
445 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) | 445 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) |
446 | } | 446 | } |
447 | Literal::ByteString(..) => { | 447 | Literal::ByteString(..) => { |
448 | let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known( | 448 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); |
449 | primitive::IntTy::u8(), | ||
450 | ))); | ||
451 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); | 449 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); |
452 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) | 450 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) |
453 | } | 451 | } |
454 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | 452 | Literal::Char(..) => Ty::simple(TypeCtor::Char), |
455 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int(*ty)), | 453 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), |
456 | Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float(*ty)), | 454 | Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), |
457 | }, | 455 | }, |
458 | }; | 456 | }; |
459 | // use a new type variable if we got Ty::Unknown here | 457 | // use a new type variable if we got Ty::Unknown here |
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 865ced5a1..31ca675aa 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -5,9 +5,10 @@ use hir_def::path::PathSegment; | |||
5 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 5 | use super::{ExprOrPatId, InferenceContext, TraitRef}; |
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | generics::HasGenericParams, | ||
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 9 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk}, | 10 | ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk}, |
10 | AssocItem, Container, HasGenericParams, Name, Path, | 11 | AssocItem, Container, Name, Path, |
11 | }; | 12 | }; |
12 | 13 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 14 | 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 1fed5025e..de3c56097 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -9,7 +9,7 @@ use std::iter; | |||
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use hir_def::{ | 11 | use hir_def::{ |
12 | builtin_type::BuiltinType, | 12 | builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType}, |
13 | path::{GenericArg, PathSegment}, | 13 | path::{GenericArg, PathSegment}, |
14 | type_ref::{TypeBound, TypeRef}, | 14 | type_ref::{TypeBound, TypeRef}, |
15 | }; | 15 | }; |
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | generics::{GenericDef, WherePredicate}, | 25 | generics::{GenericDef, WherePredicate}, |
26 | resolve::{Resolver, TypeNs}, | 26 | resolve::{Resolver, TypeNs}, |
27 | ty::{ | 27 | ty::{ |
28 | primitive::{FloatTy, IntTy}, | 28 | primitive::{FloatTy, IntTy, Uncertain}, |
29 | Adt, | 29 | Adt, |
30 | }, | 30 | }, |
31 | util::make_mut_slice, | 31 | util::make_mut_slice, |
@@ -657,13 +657,41 @@ fn type_for_builtin(def: BuiltinType) -> Ty { | |||
657 | BuiltinType::Char => TypeCtor::Char, | 657 | BuiltinType::Char => TypeCtor::Char, |
658 | BuiltinType::Bool => TypeCtor::Bool, | 658 | BuiltinType::Bool => TypeCtor::Bool, |
659 | BuiltinType::Str => TypeCtor::Str, | 659 | BuiltinType::Str => TypeCtor::Str, |
660 | BuiltinType::Int { signedness, bitness } => { | 660 | BuiltinType::Int(t) => TypeCtor::Int(IntTy::from(t).into()), |
661 | TypeCtor::Int(IntTy { signedness, bitness }.into()) | 661 | BuiltinType::Float(t) => TypeCtor::Float(FloatTy::from(t).into()), |
662 | } | ||
663 | BuiltinType::Float { bitness } => TypeCtor::Float(FloatTy { bitness }.into()), | ||
664 | }) | 662 | }) |
665 | } | 663 | } |
666 | 664 | ||
665 | impl From<BuiltinInt> for IntTy { | ||
666 | fn from(t: BuiltinInt) -> Self { | ||
667 | IntTy { signedness: t.signedness, bitness: t.bitness } | ||
668 | } | ||
669 | } | ||
670 | |||
671 | impl From<BuiltinFloat> for FloatTy { | ||
672 | fn from(t: BuiltinFloat) -> Self { | ||
673 | FloatTy { bitness: t.bitness } | ||
674 | } | ||
675 | } | ||
676 | |||
677 | impl From<Option<BuiltinInt>> for Uncertain<IntTy> { | ||
678 | fn from(t: Option<BuiltinInt>) -> Self { | ||
679 | match t { | ||
680 | None => Uncertain::Unknown, | ||
681 | Some(t) => Uncertain::Known(t.into()), | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | |||
686 | impl From<Option<BuiltinFloat>> for Uncertain<FloatTy> { | ||
687 | fn from(t: Option<BuiltinFloat>) -> Self { | ||
688 | match t { | ||
689 | None => Uncertain::Unknown, | ||
690 | Some(t) => Uncertain::Known(t.into()), | ||
691 | } | ||
692 | } | ||
693 | } | ||
694 | |||
667 | fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { | 695 | fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { |
668 | let struct_data = db.struct_data(def.id.into()); | 696 | let struct_data = db.struct_data(def.id.into()); |
669 | let fields = match struct_data.variant_data.fields() { | 697 | let fields = match struct_data.variant_data.fields() { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8c3d32d09..eb5ca6769 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -8,16 +8,17 @@ use arrayvec::ArrayVec; | |||
8 | use hir_def::CrateModuleId; | 8 | use hir_def::CrateModuleId; |
9 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
10 | 10 | ||
11 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | ||
12 | use crate::{ | 11 | use crate::{ |
13 | db::HirDatabase, | 12 | db::HirDatabase, |
14 | impl_block::{ImplBlock, ImplId}, | 13 | impl_block::{ImplBlock, ImplId}, |
15 | resolve::Resolver, | 14 | resolve::Resolver, |
16 | ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, | 15 | ty::primitive::{FloatBitness, Uncertain}, |
17 | ty::{Ty, TypeCtor}, | 16 | ty::{Ty, TypeCtor}, |
18 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, | 17 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, |
19 | }; | 18 | }; |
20 | 19 | ||
20 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | ||
21 | |||
21 | /// This is used as a key for indexing impls. | 22 | /// This is used as a key for indexing impls. |
22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 23 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
23 | pub enum TyFingerprint { | 24 | pub enum TyFingerprint { |
@@ -140,14 +141,12 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV | |||
140 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), | 141 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), |
141 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), | 142 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), |
142 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), | 143 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), |
143 | TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness { | 144 | TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { |
144 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | 145 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) |
145 | FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), | 146 | FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), |
146 | FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), | 147 | FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), |
147 | }, | 148 | }, |
148 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | 149 | TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()), |
149 | lang_item_crate!(db, cur_crate, i.ty_to_string()) | ||
150 | } | ||
151 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), | 150 | TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), |
152 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), | 151 | TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), |
153 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), | 152 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), |
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 1749752f1..47789db87 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs | |||
@@ -4,44 +4,38 @@ use std::fmt; | |||
4 | 4 | ||
5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; | 5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; |
6 | 6 | ||
7 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 7 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] |
8 | pub enum UncertainIntTy { | 8 | pub enum Uncertain<T> { |
9 | Unknown, | 9 | Unknown, |
10 | Known(IntTy), | 10 | Known(T), |
11 | } | 11 | } |
12 | 12 | ||
13 | impl From<IntTy> for UncertainIntTy { | 13 | impl From<IntTy> for Uncertain<IntTy> { |
14 | fn from(ty: IntTy) -> Self { | 14 | fn from(ty: IntTy) -> Self { |
15 | UncertainIntTy::Known(ty) | 15 | Uncertain::Known(ty) |
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
19 | impl fmt::Display for UncertainIntTy { | 19 | impl fmt::Display for Uncertain<IntTy> { |
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
21 | match *self { | 21 | match *self { |
22 | UncertainIntTy::Unknown => write!(f, "{{integer}}"), | 22 | Uncertain::Unknown => write!(f, "{{integer}}"), |
23 | UncertainIntTy::Known(ty) => write!(f, "{}", ty), | 23 | Uncertain::Known(ty) => write!(f, "{}", ty), |
24 | } | 24 | } |
25 | } | 25 | } |
26 | } | 26 | } |
27 | 27 | ||
28 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 28 | impl From<FloatTy> for Uncertain<FloatTy> { |
29 | pub enum UncertainFloatTy { | ||
30 | Unknown, | ||
31 | Known(FloatTy), | ||
32 | } | ||
33 | |||
34 | impl From<FloatTy> for UncertainFloatTy { | ||
35 | fn from(ty: FloatTy) -> Self { | 29 | fn from(ty: FloatTy) -> Self { |
36 | UncertainFloatTy::Known(ty) | 30 | Uncertain::Known(ty) |
37 | } | 31 | } |
38 | } | 32 | } |
39 | 33 | ||
40 | impl fmt::Display for UncertainFloatTy { | 34 | impl fmt::Display for Uncertain<FloatTy> { |
41 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
42 | match *self { | 36 | match *self { |
43 | UncertainFloatTy::Unknown => write!(f, "{{float}}"), | 37 | Uncertain::Unknown => write!(f, "{{float}}"), |
44 | UncertainFloatTy::Known(ty) => write!(f, "{}", ty), | 38 | Uncertain::Known(ty) => write!(f, "{}", ty), |
45 | } | 39 | } |
46 | } | 40 | } |
47 | } | 41 | } |
@@ -129,24 +123,6 @@ impl IntTy { | |||
129 | (Signedness::Unsigned, IntBitness::X128) => "u128", | 123 | (Signedness::Unsigned, IntBitness::X128) => "u128", |
130 | } | 124 | } |
131 | } | 125 | } |
132 | |||
133 | pub(crate) fn from_suffix(suffix: &str) -> Option<IntTy> { | ||
134 | match suffix { | ||
135 | "isize" => Some(IntTy::isize()), | ||
136 | "i8" => Some(IntTy::i8()), | ||
137 | "i16" => Some(IntTy::i16()), | ||
138 | "i32" => Some(IntTy::i32()), | ||
139 | "i64" => Some(IntTy::i64()), | ||
140 | "i128" => Some(IntTy::i128()), | ||
141 | "usize" => Some(IntTy::usize()), | ||
142 | "u8" => Some(IntTy::u8()), | ||
143 | "u16" => Some(IntTy::u16()), | ||
144 | "u32" => Some(IntTy::u32()), | ||
145 | "u64" => Some(IntTy::u64()), | ||
146 | "u128" => Some(IntTy::u128()), | ||
147 | _ => None, | ||
148 | } | ||
149 | } | ||
150 | } | 126 | } |
151 | 127 | ||
152 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | 128 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] |
@@ -181,12 +157,4 @@ impl FloatTy { | |||
181 | FloatBitness::X64 => "f64", | 157 | FloatBitness::X64 => "f64", |
182 | } | 158 | } |
183 | } | 159 | } |
184 | |||
185 | pub(crate) fn from_suffix(suffix: &str) -> Option<FloatTy> { | ||
186 | match suffix { | ||
187 | "f32" => Some(FloatTy::f32()), | ||
188 | "f64" => Some(FloatTy::f64()), | ||
189 | _ => None, | ||
190 | } | ||
191 | } | ||
192 | } | 160 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index e56b9356e..8863c3608 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -222,7 +222,6 @@ mod collections { | |||
222 | 222 | ||
223 | #[test] | 223 | #[test] |
224 | fn infer_while_let() { | 224 | fn infer_while_let() { |
225 | covers!(infer_while_let); | ||
226 | let (db, pos) = TestDB::with_position( | 225 | let (db, pos) = TestDB::with_position( |
227 | r#" | 226 | r#" |
228 | //- /main.rs | 227 | //- /main.rs |
@@ -4810,3 +4809,22 @@ fn no_such_field_diagnostics() { | |||
4810 | "### | 4809 | "### |
4811 | ); | 4810 | ); |
4812 | } | 4811 | } |
4812 | |||
4813 | #[test] | ||
4814 | fn infer_builtin_macros_line() { | ||
4815 | assert_snapshot!( | ||
4816 | infer(r#" | ||
4817 | #[rustc_builtin_macro] | ||
4818 | macro_rules! line {() => {}} | ||
4819 | |||
4820 | fn main() { | ||
4821 | let x = line!(); | ||
4822 | } | ||
4823 | "#), | ||
4824 | @r###" | ||
4825 | ![0; 1) '6': i32 | ||
4826 | [64; 88) '{ ...!(); }': () | ||
4827 | [74; 75) 'x': i32 | ||
4828 | "### | ||
4829 | ); | ||
4830 | } | ||
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index c694952f3..75351c17d 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -16,13 +16,13 @@ use ra_db::salsa::{InternId, InternKey}; | |||
16 | use super::{Canonical, ChalkContext, Impl, Obligation}; | 16 | use super::{Canonical, ChalkContext, Impl, Obligation}; |
17 | use crate::{ | 17 | use crate::{ |
18 | db::HirDatabase, | 18 | db::HirDatabase, |
19 | generics::GenericDef, | 19 | generics::{GenericDef, HasGenericParams}, |
20 | ty::display::HirDisplay, | 20 | ty::display::HirDisplay, |
21 | ty::{ | 21 | ty::{ |
22 | ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 22 | ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
23 | TypeWalk, | 23 | TypeWalk, |
24 | }, | 24 | }, |
25 | AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, | 25 | AssocItem, Crate, HasBody, ImplBlock, Trait, TypeAlias, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// This represents a trait whose name we could not resolve. | 28 | /// This represents a trait whose name we could not resolve. |
@@ -714,7 +714,7 @@ fn closure_fn_trait_impl_datum( | |||
714 | let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; | 714 | let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; |
715 | let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait | 715 | let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait |
716 | 716 | ||
717 | let num_args: u16 = match &db.body_hir(data.def)[data.expr] { | 717 | let num_args: u16 = match &data.def.body(db)[data.expr] { |
718 | crate::expr::Expr::Lambda { args, .. } => args.len() as u16, | 718 | crate::expr::Expr::Lambda { args, .. } => args.len() as u16, |
719 | _ => { | 719 | _ => { |
720 | log::warn!("closure for closure type {:?} not found", data); | 720 | log::warn!("closure for closure type {:?} not found", data); |