diff options
author | Seivan Heidari <[email protected]> | 2019-11-12 18:04:54 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-12 18:04:54 +0000 |
commit | 0525778a3ad590492b51cc11085d815f9bb8f92b (patch) | |
tree | 56096932b19861ab86c9564717f88cf7cd86d023 | |
parent | 11755f3eff87cd8ee0af7961377e0ae3ffea5050 (diff) | |
parent | 3322d65addd9ec61b8c5bc055803f6549946da8b (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
24 files changed, 842 insertions, 679 deletions
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs index 1bee3eb99..51d953f6e 100644 --- a/crates/ra_cfg/src/lib.rs +++ b/crates/ra_cfg/src/lib.rs | |||
@@ -1,11 +1,12 @@ | |||
1 | //! ra_cfg defines conditional compiling options, `cfg` attibute parser and evaluator | 1 | //! ra_cfg defines conditional compiling options, `cfg` attibute parser and evaluator |
2 | |||
3 | mod cfg_expr; | ||
4 | |||
2 | use std::iter::IntoIterator; | 5 | use std::iter::IntoIterator; |
3 | 6 | ||
4 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
5 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
6 | 9 | ||
7 | mod cfg_expr; | ||
8 | |||
9 | pub use cfg_expr::{parse_cfg, CfgExpr}; | 10 | pub use cfg_expr::{parse_cfg, CfgExpr}; |
10 | 11 | ||
11 | /// Configuration options used for conditional compilition on items with `cfg` attributes. | 12 | /// Configuration options used for conditional compilition on items with `cfg` attributes. |
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index f5dd59f84..ee883b615 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::str::FromStr; | ||
3 | use std::sync::Arc; | 4 | use std::sync::Arc; |
4 | 5 | ||
5 | use ra_cfg::CfgOptions; | 6 | use ra_cfg::CfgOptions; |
@@ -164,7 +165,7 @@ fn parse_meta(meta: &str) -> ParsedMeta { | |||
164 | match key { | 165 | match key { |
165 | "crate" => krate = Some(value.to_string()), | 166 | "crate" => krate = Some(value.to_string()), |
166 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | 167 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), |
167 | "edition" => edition = Edition::from_string(&value), | 168 | "edition" => edition = Edition::from_str(&value).unwrap(), |
168 | "cfg" => { | 169 | "cfg" => { |
169 | for key in value.split(',') { | 170 | for key in value.split(',') { |
170 | match split1(key, '=') { | 171 | match split1(key, '=') { |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 60f7dc881..c0d95a13f 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -13,6 +13,7 @@ use ra_syntax::SmolStr; | |||
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | use crate::{RelativePath, RelativePathBuf}; | 15 | use crate::{RelativePath, RelativePathBuf}; |
16 | use std::str::FromStr; | ||
16 | 17 | ||
17 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 18 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
18 | /// messy and system-dependent, so most of the code should work directly with | 19 | /// messy and system-dependent, so most of the code should work directly with |
@@ -97,12 +98,18 @@ pub enum Edition { | |||
97 | Edition2015, | 98 | Edition2015, |
98 | } | 99 | } |
99 | 100 | ||
100 | impl Edition { | 101 | #[derive(Debug)] |
101 | //FIXME: replace with FromStr with proper error handling | 102 | pub struct ParseEditionError { |
102 | pub fn from_string(s: &str) -> Edition { | 103 | pub msg: String, |
104 | } | ||
105 | |||
106 | impl FromStr for Edition { | ||
107 | type Err = ParseEditionError; | ||
108 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
103 | match s { | 109 | match s { |
104 | "2015" => Edition::Edition2015, | 110 | "2015" => Ok(Edition::Edition2015), |
105 | "2018" | _ => Edition::Edition2018, | 111 | "2018" => Ok(Edition::Edition2018), |
112 | _ => Err(ParseEditionError { msg: format!("unknown edition: {}", s) }), | ||
106 | } | 113 | } |
107 | } | 114 | } |
108 | } | 115 | } |
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index e22ac9753..a30ed4cbb 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | //! This crate provides some utilities for indenting rust code. | 1 | //! This crate provides some utilities for indenting rust code. |
2 | //! | 2 | |
3 | use std::iter::successors; | ||
4 | |||
3 | use itertools::Itertools; | 5 | use itertools::Itertools; |
4 | use ra_syntax::{ | 6 | use ra_syntax::{ |
5 | ast::{self, AstNode, AstToken}, | 7 | ast::{self, AstNode, AstToken}, |
@@ -7,7 +9,6 @@ use ra_syntax::{ | |||
7 | SyntaxKind::*, | 9 | SyntaxKind::*, |
8 | SyntaxNode, SyntaxToken, T, | 10 | SyntaxNode, SyntaxToken, T, |
9 | }; | 11 | }; |
10 | use std::iter::successors; | ||
11 | 12 | ||
12 | pub fn reindent(text: &str, indent: &str) -> String { | 13 | pub fn reindent(text: &str, indent: &str) -> String { |
13 | let indent = format!("\n{}", indent); | 14 | let indent = format!("\n{}", indent); |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 5a0bd0c19..2fd4ccb10 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -550,7 +550,7 @@ where | |||
550 | } | 550 | } |
551 | 551 | ||
552 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 552 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
553 | db.body_hir(self.into()) | 553 | db.body(self.into()) |
554 | } | 554 | } |
555 | 555 | ||
556 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 556 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
@@ -564,7 +564,7 @@ impl HasBody for DefWithBody { | |||
564 | } | 564 | } |
565 | 565 | ||
566 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 566 | fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
567 | db.body_hir(self) | 567 | db.body(self) |
568 | } | 568 | } |
569 | 569 | ||
570 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 570 | fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
@@ -666,7 +666,7 @@ impl Function { | |||
666 | } | 666 | } |
667 | 667 | ||
668 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { | 668 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { |
669 | db.body_hir(self.into()) | 669 | db.body(self.into()) |
670 | } | 670 | } |
671 | 671 | ||
672 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | 672 | pub fn ty(self, db: &impl HirDatabase) -> Ty { |
@@ -1079,7 +1079,7 @@ pub struct Local { | |||
1079 | 1079 | ||
1080 | impl Local { | 1080 | impl Local { |
1081 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | 1081 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { |
1082 | let body = db.body_hir(self.parent); | 1082 | let body = db.body(self.parent); |
1083 | match &body[self.pat_id] { | 1083 | match &body[self.pat_id] { |
1084 | Pat::Bind { name, .. } => Some(name.clone()), | 1084 | Pat::Bind { name, .. } => Some(name.clone()), |
1085 | _ => None, | 1085 | _ => None, |
@@ -1091,7 +1091,7 @@ impl Local { | |||
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | pub fn is_mut(self, db: &impl HirDatabase) -> bool { | 1093 | pub fn is_mut(self, db: &impl HirDatabase) -> bool { |
1094 | let body = db.body_hir(self.parent); | 1094 | let body = db.body(self.parent); |
1095 | match &body[self.pat_id] { | 1095 | match &body[self.pat_id] { |
1096 | Pat::Bind { mode, .. } => match mode { | 1096 | Pat::Bind { mode, .. } => match mode { |
1097 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | 1097 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 75c322c99..9ac811232 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -8,6 +8,7 @@ use ra_syntax::SmolStr; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | debug::HirDebugDatabase, | 10 | debug::HirDebugDatabase, |
11 | expr::{Body, BodySourceMap}, | ||
11 | generics::{GenericDef, GenericParams}, | 12 | generics::{GenericDef, GenericParams}, |
12 | ids, | 13 | ids, |
13 | impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, | 14 | impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, |
@@ -113,13 +114,10 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
113 | fn generic_defaults(&self, def: GenericDef) -> Substs; | 114 | fn generic_defaults(&self, def: GenericDef) -> Substs; |
114 | 115 | ||
115 | #[salsa::invoke(crate::expr::body_with_source_map_query)] | 116 | #[salsa::invoke(crate::expr::body_with_source_map_query)] |
116 | fn body_with_source_map( | 117 | fn body_with_source_map(&self, def: DefWithBody) -> (Arc<Body>, Arc<BodySourceMap>); |
117 | &self, | ||
118 | def: DefWithBody, | ||
119 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); | ||
120 | 118 | ||
121 | #[salsa::invoke(crate::expr::body_hir_query)] | 119 | #[salsa::invoke(crate::expr::body_query)] |
122 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; | 120 | fn body(&self, def: DefWithBody) -> Arc<Body>; |
123 | 121 | ||
124 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 122 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
125 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 123 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 6e23197a4..82955fa55 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1,549 +1,24 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub(crate) mod lower; | ||
4 | pub(crate) mod scope; | 3 | pub(crate) mod scope; |
5 | pub(crate) mod validation; | 4 | pub(crate) mod validation; |
6 | 5 | ||
7 | use std::{ops::Index, sync::Arc}; | 6 | use std::sync::Arc; |
8 | 7 | ||
9 | use hir_def::{ | ||
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}; | 8 | use ra_syntax::{ast, AstPtr}; |
15 | use rustc_hash::FxHashMap; | ||
16 | 9 | ||
17 | use crate::{ | 10 | use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; |
18 | db::HirDatabase, | ||
19 | ty::primitive::{UncertainFloatTy, UncertainIntTy}, | ||
20 | DefWithBody, Either, HasSource, Name, Path, Resolver, Source, | ||
21 | }; | ||
22 | 11 | ||
23 | pub use self::scope::ExprScopes; | 12 | pub use self::scope::ExprScopes; |
24 | 13 | ||
25 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 14 | pub use hir_def::{ |
26 | pub struct ExprId(RawId); | 15 | body::{Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource}, |
27 | impl_arena_id!(ExprId); | 16 | expr::{ |
28 | 17 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | |
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 18 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, |
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 | |||
54 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
55 | type PatSource = Source<PatPtr>; | ||
56 | |||
57 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
58 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
59 | /// expression containing it; but for type inference etc., we want to operate on | ||
60 | /// a structure that is agnostic to the actual positions of expressions in the | ||
61 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
62 | /// | ||
63 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
64 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
65 | /// both the HirFileId and the position inside the file. However, we only store | ||
66 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
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 | |||
99 | // needs arbitrary_self_types to be a method... or maybe move to the def? | ||
100 | pub(crate) fn resolver_for_expr( | ||
101 | body: Arc<Body>, | ||
102 | db: &impl HirDatabase, | ||
103 | expr_id: ExprId, | ||
104 | ) -> Resolver { | ||
105 | let scopes = db.expr_scopes(body.owner); | ||
106 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) | ||
107 | } | ||
108 | |||
109 | pub(crate) fn resolver_for_scope( | ||
110 | body: Arc<Body>, | ||
111 | db: &impl HirDatabase, | ||
112 | scope_id: Option<scope::ScopeId>, | ||
113 | ) -> Resolver { | ||
114 | let mut r = body.owner.resolver(db); | ||
115 | let scopes = db.expr_scopes(body.owner); | ||
116 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | ||
117 | for scope in scope_chain.into_iter().rev() { | ||
118 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | ||
119 | } | ||
120 | r | ||
121 | } | ||
122 | |||
123 | impl Index<ExprId> for Body { | ||
124 | type Output = Expr; | ||
125 | |||
126 | fn index(&self, expr: ExprId) -> &Expr { | ||
127 | &self.exprs[expr] | ||
128 | } | ||
129 | } | ||
130 | |||
131 | impl Index<PatId> for Body { | ||
132 | type Output = Pat; | ||
133 | |||
134 | fn index(&self, pat: PatId) -> &Pat { | ||
135 | &self.pats[pat] | ||
136 | } | ||
137 | } | ||
138 | |||
139 | impl BodySourceMap { | ||
140 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { | ||
141 | self.expr_map_back.get(expr).copied() | ||
142 | } | ||
143 | |||
144 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | ||
145 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
146 | } | ||
147 | |||
148 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { | ||
149 | self.pat_map_back.get(pat).copied() | ||
150 | } | ||
151 | |||
152 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
153 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
154 | } | ||
155 | |||
156 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | ||
157 | self.field_map[&(expr, field)] | ||
158 | } | ||
159 | } | ||
160 | |||
161 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
162 | pub enum Literal { | ||
163 | String(String), | ||
164 | ByteString(Vec<u8>), | ||
165 | Char(char), | ||
166 | Bool(bool), | ||
167 | Int(u64, UncertainIntTy), | ||
168 | Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq | ||
169 | } | ||
170 | |||
171 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
172 | pub enum Expr { | ||
173 | /// This is produced if syntax tree does not have a required expression piece. | ||
174 | Missing, | ||
175 | Path(Path), | ||
176 | If { | ||
177 | condition: ExprId, | ||
178 | then_branch: ExprId, | ||
179 | else_branch: Option<ExprId>, | ||
180 | }, | ||
181 | Block { | ||
182 | statements: Vec<Statement>, | ||
183 | tail: Option<ExprId>, | ||
184 | }, | ||
185 | Loop { | ||
186 | body: ExprId, | ||
187 | }, | ||
188 | While { | ||
189 | condition: ExprId, | ||
190 | body: ExprId, | ||
191 | }, | ||
192 | For { | ||
193 | iterable: ExprId, | ||
194 | pat: PatId, | ||
195 | body: ExprId, | ||
196 | }, | ||
197 | Call { | ||
198 | callee: ExprId, | ||
199 | args: Vec<ExprId>, | ||
200 | }, | ||
201 | MethodCall { | ||
202 | receiver: ExprId, | ||
203 | method_name: Name, | ||
204 | args: Vec<ExprId>, | ||
205 | generic_args: Option<GenericArgs>, | ||
206 | }, | ||
207 | Match { | ||
208 | expr: ExprId, | ||
209 | arms: Vec<MatchArm>, | ||
210 | }, | ||
211 | Continue, | ||
212 | Break { | ||
213 | expr: Option<ExprId>, | ||
214 | }, | ||
215 | Return { | ||
216 | expr: Option<ExprId>, | ||
217 | }, | ||
218 | RecordLit { | ||
219 | path: Option<Path>, | ||
220 | fields: Vec<RecordLitField>, | ||
221 | spread: Option<ExprId>, | ||
222 | }, | ||
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 | }, | 19 | }, |
240 | Ref { | 20 | }; |
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 | } | ||
360 | } | ||
361 | if let Some(expr) = tail { | ||
362 | f(*expr); | ||
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 | } | ||
398 | } | ||
399 | Expr::RecordLit { fields, spread, .. } => { | ||
400 | for field in fields { | ||
401 | f(field.expr); | ||
402 | } | ||
403 | if let Some(expr) = spread { | ||
404 | f(*expr); | ||
405 | } | ||
406 | } | ||
407 | Expr::Lambda { body, .. } => { | ||
408 | f(*body); | ||
409 | } | ||
410 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
411 | f(*lhs); | ||
412 | f(*rhs); | ||
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 | } | ||
544 | } | ||
545 | 21 | ||
546 | // Queries | ||
547 | pub(crate) fn body_with_source_map_query( | 22 | pub(crate) fn body_with_source_map_query( |
548 | db: &impl HirDatabase, | 23 | db: &impl HirDatabase, |
549 | def: DefWithBody, | 24 | def: DefWithBody, |
@@ -565,11 +40,35 @@ pub(crate) fn body_with_source_map_query( | |||
565 | (src.file_id, src.ast.body()) | 40 | (src.file_id, src.ast.body()) |
566 | } | 41 | } |
567 | }; | 42 | }; |
568 | 43 | let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id); | |
569 | let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body); | 44 | let (body, source_map) = Body::new(db, resolver, file_id, params, body); |
570 | (Arc::new(body), Arc::new(source_map)) | 45 | (Arc::new(body), Arc::new(source_map)) |
571 | } | 46 | } |
572 | 47 | ||
573 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | 48 | pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { |
574 | db.body_with_source_map(def).0 | 49 | db.body_with_source_map(def).0 |
575 | } | 50 | } |
51 | |||
52 | // needs arbitrary_self_types to be a method... or maybe move to the def? | ||
53 | pub(crate) fn resolver_for_expr( | ||
54 | db: &impl HirDatabase, | ||
55 | owner: DefWithBody, | ||
56 | expr_id: ExprId, | ||
57 | ) -> Resolver { | ||
58 | let scopes = db.expr_scopes(owner); | ||
59 | resolver_for_scope(db, owner, scopes.scope_for(expr_id)) | ||
60 | } | ||
61 | |||
62 | pub(crate) fn resolver_for_scope( | ||
63 | db: &impl HirDatabase, | ||
64 | owner: DefWithBody, | ||
65 | scope_id: Option<scope::ScopeId>, | ||
66 | ) -> Resolver { | ||
67 | let mut r = owner.resolver(db); | ||
68 | let scopes = db.expr_scopes(owner); | ||
69 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | ||
70 | for scope in scope_chain.into_iter().rev() { | ||
71 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | ||
72 | } | ||
73 | r | ||
74 | } | ||
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index daf8d8d07..0e49a28d6 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -46,7 +46,7 @@ pub(crate) struct ScopeData { | |||
46 | 46 | ||
47 | impl ExprScopes { | 47 | impl ExprScopes { |
48 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { | 48 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { |
49 | let body = db.body_hir(def); | 49 | let body = db.body(def); |
50 | let res = ExprScopes::new(body); | 50 | let res = ExprScopes::new(body); |
51 | Arc::new(res) | 51 | Arc::new(res) |
52 | } | 52 | } |
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/source_binder.rs b/crates/ra_hir/src/source_binder.rs index fe4211819..f28e9c931 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -150,7 +150,7 @@ impl SourceAnalyzer { | |||
150 | None => scope_for(&scopes, &source_map, &node), | 150 | None => scope_for(&scopes, &source_map, &node), |
151 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), | 151 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), |
152 | }; | 152 | }; |
153 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | 153 | let resolver = expr::resolver_for_scope(db, def, scope); |
154 | SourceAnalyzer { | 154 | SourceAnalyzer { |
155 | resolver, | 155 | resolver, |
156 | body_owner: Some(def), | 156 | body_owner: Some(def), |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 2370e8d4f..f17c6c614 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -43,7 +43,7 @@ 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, FnData, Function, Path, StructField, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | macro_rules! ty_app { | 49 | macro_rules! ty_app { |
@@ -64,9 +64,8 @@ mod coerce; | |||
64 | /// The entry point of type inference. | 64 | /// The entry point of type inference. |
65 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 65 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
66 | let _p = profile("infer_query"); | 66 | let _p = profile("infer_query"); |
67 | let body = def.body(db); | ||
68 | let resolver = def.resolver(db); | 67 | let resolver = def.resolver(db); |
69 | let mut ctx = InferenceContext::new(db, body, resolver); | 68 | let mut ctx = InferenceContext::new(db, def, resolver); |
70 | 69 | ||
71 | match def { | 70 | match def { |
72 | DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), | 71 | DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), |
@@ -187,6 +186,7 @@ impl Index<PatId> for InferenceResult { | |||
187 | #[derive(Clone, Debug)] | 186 | #[derive(Clone, Debug)] |
188 | struct InferenceContext<'a, D: HirDatabase> { | 187 | struct InferenceContext<'a, D: HirDatabase> { |
189 | db: &'a D, | 188 | db: &'a D, |
189 | owner: DefWithBody, | ||
190 | body: Arc<Body>, | 190 | body: Arc<Body>, |
191 | resolver: Resolver, | 191 | resolver: Resolver, |
192 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 192 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
@@ -204,7 +204,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
204 | } | 204 | } |
205 | 205 | ||
206 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 206 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
207 | fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { | 207 | fn new(db: &'a D, owner: DefWithBody, resolver: Resolver) -> Self { |
208 | InferenceContext { | 208 | InferenceContext { |
209 | result: InferenceResult::default(), | 209 | result: InferenceResult::default(), |
210 | var_unification_table: InPlaceUnificationTable::new(), | 210 | var_unification_table: InPlaceUnificationTable::new(), |
@@ -213,7 +213,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
213 | trait_env: lower::trait_env(db, &resolver), | 213 | trait_env: lower::trait_env(db, &resolver), |
214 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | 214 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), |
215 | db, | 215 | db, |
216 | body, | 216 | owner, |
217 | body: db.body(owner), | ||
217 | resolver, | 218 | resolver, |
218 | } | 219 | } |
219 | } | 220 | } |
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 4af1d65ee..c6802487a 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -130,10 +130,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
130 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 130 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, |
131 | Substs(sig_tys.into()), | 131 | Substs(sig_tys.into()), |
132 | ); | 132 | ); |
133 | let closure_ty = Ty::apply_one( | 133 | let closure_ty = |
134 | TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, | 134 | Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); |
135 | sig_ty, | ||
136 | ); | ||
137 | 135 | ||
138 | // Eagerly try to relate the closure type with the expected | 136 | // Eagerly try to relate the closure type with the expected |
139 | // type, otherwise we often won't have enough information to | 137 | // type, otherwise we often won't have enough information to |
@@ -184,7 +182,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
184 | } | 182 | } |
185 | Expr::Path(p) => { | 183 | Expr::Path(p) => { |
186 | // FIXME this could be more efficient... | 184 | // FIXME this could be more efficient... |
187 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); | 185 | 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) | 186 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
189 | } | 187 | } |
190 | Expr::Continue => Ty::simple(TypeCtor::Never), | 188 | Expr::Continue => Ty::simple(TypeCtor::Never), |
@@ -452,8 +450,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
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/lower.rs b/crates/ra_hir/src/ty/lower.rs index 1fed5025e..1832fcf50 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, UncertainFloatTy, UncertainIntTy}, |
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 UncertainIntTy { | ||
678 | fn from(t: Option<BuiltinInt>) -> Self { | ||
679 | match t { | ||
680 | None => UncertainIntTy::Unknown, | ||
681 | Some(t) => UncertainIntTy::Known(t.into()), | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | |||
686 | impl From<Option<BuiltinFloat>> for UncertainFloatTy { | ||
687 | fn from(t: Option<BuiltinFloat>) -> Self { | ||
688 | match t { | ||
689 | None => UncertainFloatTy::Unknown, | ||
690 | Some(t) => UncertainFloatTy::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/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 1749752f1..7362de4c3 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs | |||
@@ -129,24 +129,6 @@ impl IntTy { | |||
129 | (Signedness::Unsigned, IntBitness::X128) => "u128", | 129 | (Signedness::Unsigned, IntBitness::X128) => "u128", |
130 | } | 130 | } |
131 | } | 131 | } |
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 | } | 132 | } |
151 | 133 | ||
152 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | 134 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] |
@@ -181,12 +163,4 @@ impl FloatTy { | |||
181 | FloatBitness::X64 => "f64", | 163 | FloatBitness::X64 => "f64", |
182 | } | 164 | } |
183 | } | 165 | } |
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 | } | 166 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 896bf2924..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 |
@@ -4825,7 +4824,7 @@ fn main() { | |||
4825 | @r###" | 4824 | @r###" |
4826 | ![0; 1) '6': i32 | 4825 | ![0; 1) '6': i32 |
4827 | [64; 88) '{ ...!(); }': () | 4826 | [64; 88) '{ ...!(); }': () |
4828 | [74; 75) 'x': i32 | 4827 | [74; 75) 'x': i32 |
4829 | "### | 4828 | "### |
4830 | ); | 4829 | ); |
4831 | } | 4830 | } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 14c54b9fb..de322dd52 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -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 &db.body(data.def)[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); |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs new file mode 100644 index 000000000..ac8f8261b --- /dev/null +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -0,0 +1,144 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | mod lower; | ||
3 | |||
4 | use std::{ops::Index, sync::Arc}; | ||
5 | |||
6 | use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; | ||
7 | use ra_arena::{map::ArenaMap, Arena}; | ||
8 | use ra_syntax::{ast, AstPtr}; | ||
9 | use rustc_hash::FxHashMap; | ||
10 | |||
11 | use crate::{ | ||
12 | db::DefDatabase2, | ||
13 | expr::{Expr, ExprId, Pat, PatId}, | ||
14 | nameres::CrateDefMap, | ||
15 | path::Path, | ||
16 | ModuleId, | ||
17 | }; | ||
18 | |||
19 | pub struct MacroResolver { | ||
20 | crate_def_map: Arc<CrateDefMap>, | ||
21 | module: ModuleId, | ||
22 | } | ||
23 | |||
24 | impl MacroResolver { | ||
25 | pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { | ||
26 | MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } | ||
27 | } | ||
28 | |||
29 | pub(crate) fn resolve_path_as_macro( | ||
30 | &self, | ||
31 | db: &impl DefDatabase2, | ||
32 | path: &Path, | ||
33 | ) -> Option<MacroDefId> { | ||
34 | self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /// The body of an item (function, const etc.). | ||
39 | #[derive(Debug, Eq, PartialEq)] | ||
40 | pub struct Body { | ||
41 | exprs: Arena<ExprId, Expr>, | ||
42 | pats: Arena<PatId, Pat>, | ||
43 | /// The patterns for the function's parameters. While the parameter types are | ||
44 | /// part of the function signature, the patterns are not (they don't change | ||
45 | /// the external type of the function). | ||
46 | /// | ||
47 | /// If this `Body` is for the body of a constant, this will just be | ||
48 | /// empty. | ||
49 | params: Vec<PatId>, | ||
50 | /// The `ExprId` of the actual body expression. | ||
51 | body_expr: ExprId, | ||
52 | } | ||
53 | |||
54 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
55 | pub type ExprSource = Source<ExprPtr>; | ||
56 | |||
57 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
58 | pub type PatSource = Source<PatPtr>; | ||
59 | |||
60 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
61 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
62 | /// expression containing it; but for type inference etc., we want to operate on | ||
63 | /// a structure that is agnostic to the actual positions of expressions in the | ||
64 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
65 | /// | ||
66 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
67 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
68 | /// both the HirFileId and the position inside the file. However, we only store | ||
69 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
70 | /// this properly for macros. | ||
71 | #[derive(Default, Debug, Eq, PartialEq)] | ||
72 | pub struct BodySourceMap { | ||
73 | expr_map: FxHashMap<ExprPtr, ExprId>, | ||
74 | expr_map_back: ArenaMap<ExprId, ExprSource>, | ||
75 | pat_map: FxHashMap<PatPtr, PatId>, | ||
76 | pat_map_back: ArenaMap<PatId, PatSource>, | ||
77 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | ||
78 | } | ||
79 | |||
80 | impl Body { | ||
81 | pub fn new( | ||
82 | db: &impl DefDatabase2, | ||
83 | resolver: MacroResolver, | ||
84 | file_id: HirFileId, | ||
85 | params: Option<ast::ParamList>, | ||
86 | body: Option<ast::Expr>, | ||
87 | ) -> (Body, BodySourceMap) { | ||
88 | lower::lower(db, resolver, file_id, params, body) | ||
89 | } | ||
90 | |||
91 | pub fn params(&self) -> &[PatId] { | ||
92 | &self.params | ||
93 | } | ||
94 | |||
95 | pub fn body_expr(&self) -> ExprId { | ||
96 | self.body_expr | ||
97 | } | ||
98 | |||
99 | pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> { | ||
100 | self.exprs.iter() | ||
101 | } | ||
102 | |||
103 | pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> { | ||
104 | self.pats.iter() | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl Index<ExprId> for Body { | ||
109 | type Output = Expr; | ||
110 | |||
111 | fn index(&self, expr: ExprId) -> &Expr { | ||
112 | &self.exprs[expr] | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl Index<PatId> for Body { | ||
117 | type Output = Pat; | ||
118 | |||
119 | fn index(&self, pat: PatId) -> &Pat { | ||
120 | &self.pats[pat] | ||
121 | } | ||
122 | } | ||
123 | |||
124 | impl BodySourceMap { | ||
125 | pub fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { | ||
126 | self.expr_map_back.get(expr).copied() | ||
127 | } | ||
128 | |||
129 | pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | ||
130 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
131 | } | ||
132 | |||
133 | pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { | ||
134 | self.pat_map_back.get(pat).copied() | ||
135 | } | ||
136 | |||
137 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
138 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
139 | } | ||
140 | |||
141 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | ||
142 | self.field_map[&(expr, field)] | ||
143 | } | ||
144 | } | ||
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 6463dd65e..2aa863c9e 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -1,9 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir_def::{path::GenericArgs, type_ref::TypeRef}; | ||
4 | use hir_expand::{ | 3 | use hir_expand::{ |
4 | either::Either, | ||
5 | hygiene::Hygiene, | 5 | hygiene::Hygiene, |
6 | name::{self, AsName, Name}, | 6 | name::{self, AsName, Name}, |
7 | AstId, HirFileId, MacroCallLoc, MacroFileKind, Source, | ||
7 | }; | 8 | }; |
8 | use ra_arena::Arena; | 9 | use ra_arena::Arena; |
9 | use ra_syntax::{ | 10 | use ra_syntax::{ |
@@ -13,25 +14,24 @@ use ra_syntax::{ | |||
13 | }, | 14 | }, |
14 | AstNode, AstPtr, | 15 | AstNode, AstPtr, |
15 | }; | 16 | }; |
16 | use test_utils::tested_by; | ||
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | db::HirDatabase, | 19 | body::{Body, BodySourceMap, MacroResolver, PatPtr}, |
20 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
21 | AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, | 21 | db::DefDatabase2, |
22 | Source, | 22 | expr::{ |
23 | }; | 23 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
24 | 24 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | |
25 | use super::{ | 25 | }, |
26 | ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal, | 26 | path::GenericArgs, |
27 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, | 27 | path::Path, |
28 | type_ref::{Mutability, TypeRef}, | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | pub(super) fn lower( | 31 | pub(super) fn lower( |
31 | db: &impl HirDatabase, | 32 | db: &impl DefDatabase2, |
32 | resolver: Resolver, | 33 | resolver: MacroResolver, |
33 | file_id: HirFileId, | 34 | file_id: HirFileId, |
34 | owner: DefWithBody, | ||
35 | params: Option<ast::ParamList>, | 35 | params: Option<ast::ParamList>, |
36 | body: Option<ast::Expr>, | 36 | body: Option<ast::Expr>, |
37 | ) -> (Body, BodySourceMap) { | 37 | ) -> (Body, BodySourceMap) { |
@@ -42,11 +42,10 @@ pub(super) fn lower( | |||
42 | current_file_id: file_id, | 42 | current_file_id: file_id, |
43 | source_map: BodySourceMap::default(), | 43 | source_map: BodySourceMap::default(), |
44 | body: Body { | 44 | body: Body { |
45 | owner, | ||
46 | exprs: Arena::default(), | 45 | exprs: Arena::default(), |
47 | pats: Arena::default(), | 46 | pats: Arena::default(), |
48 | params: Vec::new(), | 47 | params: Vec::new(), |
49 | body_expr: ExprId((!0).into()), | 48 | body_expr: ExprId::dummy(), |
50 | }, | 49 | }, |
51 | } | 50 | } |
52 | .collect(params, body) | 51 | .collect(params, body) |
@@ -54,11 +53,7 @@ pub(super) fn lower( | |||
54 | 53 | ||
55 | struct ExprCollector<DB> { | 54 | struct ExprCollector<DB> { |
56 | db: DB, | 55 | db: DB, |
57 | resolver: Resolver, | 56 | resolver: MacroResolver, |
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, | 57 | original_file_id: HirFileId, |
63 | current_file_id: HirFileId, | 58 | current_file_id: HirFileId, |
64 | 59 | ||
@@ -68,7 +63,7 @@ struct ExprCollector<DB> { | |||
68 | 63 | ||
69 | impl<'a, DB> ExprCollector<&'a DB> | 64 | impl<'a, DB> ExprCollector<&'a DB> |
70 | where | 65 | where |
71 | DB: HirDatabase, | 66 | DB: DefDatabase2, |
72 | { | 67 | { |
73 | fn collect( | 68 | fn collect( |
74 | mut self, | 69 | mut self, |
@@ -209,7 +204,6 @@ where | |||
209 | None => self.collect_expr_opt(condition.expr()), | 204 | None => self.collect_expr_opt(condition.expr()), |
210 | // if let -- desugar to match | 205 | // if let -- desugar to match |
211 | Some(pat) => { | 206 | Some(pat) => { |
212 | tested_by!(infer_while_let); | ||
213 | let pat = self.collect_pat(pat); | 207 | let pat = self.collect_pat(pat); |
214 | let match_expr = self.collect_expr_opt(condition.expr()); | 208 | let match_expr = self.collect_expr_opt(condition.expr()); |
215 | let placeholder_pat = self.missing_pat(); | 209 | let placeholder_pat = self.missing_pat(); |
@@ -423,28 +417,18 @@ where | |||
423 | ast::Expr::Literal(e) => { | 417 | ast::Expr::Literal(e) => { |
424 | let lit = match e.kind() { | 418 | let lit = match e.kind() { |
425 | LiteralKind::IntNumber { suffix } => { | 419 | LiteralKind::IntNumber { suffix } => { |
426 | let known_name = suffix | 420 | let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it)); |
427 | .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); | ||
428 | 421 | ||
429 | Literal::Int( | 422 | Literal::Int(Default::default(), known_name) |
430 | Default::default(), | ||
431 | known_name.unwrap_or(UncertainIntTy::Unknown), | ||
432 | ) | ||
433 | } | 423 | } |
434 | LiteralKind::FloatNumber { suffix } => { | 424 | LiteralKind::FloatNumber { suffix } => { |
435 | let known_name = suffix | 425 | let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it)); |
436 | .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); | ||
437 | 426 | ||
438 | Literal::Float( | 427 | Literal::Float(Default::default(), known_name) |
439 | Default::default(), | ||
440 | known_name.unwrap_or(UncertainFloatTy::Unknown), | ||
441 | ) | ||
442 | } | 428 | } |
443 | LiteralKind::ByteString => Literal::ByteString(Default::default()), | 429 | LiteralKind::ByteString => Literal::ByteString(Default::default()), |
444 | LiteralKind::String => Literal::String(Default::default()), | 430 | LiteralKind::String => Literal::String(Default::default()), |
445 | LiteralKind::Byte => { | 431 | LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)), |
446 | Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) | ||
447 | } | ||
448 | LiteralKind::Bool => Literal::Bool(Default::default()), | 432 | LiteralKind::Bool => Literal::Bool(Default::default()), |
449 | LiteralKind::Char => Literal::Char(Default::default()), | 433 | LiteralKind::Char => Literal::Char(Default::default()), |
450 | }; | 434 | }; |
@@ -467,7 +451,7 @@ where | |||
467 | 451 | ||
468 | if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { | 452 | 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) { | 453 | 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 }); | 454 | let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id }); |
471 | let file_id = call_id.as_file(MacroFileKind::Expr); | 455 | let file_id = call_id.as_file(MacroFileKind::Expr); |
472 | if let Some(node) = self.db.parse_or_expand(file_id) { | 456 | if let Some(node) = self.db.parse_or_expand(file_id) { |
473 | if let Some(expr) = ast::Expr::cast(node) { | 457 | if let Some(expr) = ast::Expr::cast(node) { |
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs index 2ec0c83fe..5e8157144 100644 --- a/crates/ra_hir_def/src/builtin_type.rs +++ b/crates/ra_hir_def/src/builtin_type.rs | |||
@@ -30,12 +30,23 @@ pub enum FloatBitness { | |||
30 | } | 30 | } |
31 | 31 | ||
32 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 32 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
33 | pub struct BuiltinInt { | ||
34 | pub signedness: Signedness, | ||
35 | pub bitness: IntBitness, | ||
36 | } | ||
37 | |||
38 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
39 | pub struct BuiltinFloat { | ||
40 | pub bitness: FloatBitness, | ||
41 | } | ||
42 | |||
43 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
33 | pub enum BuiltinType { | 44 | pub enum BuiltinType { |
34 | Char, | 45 | Char, |
35 | Bool, | 46 | Bool, |
36 | Str, | 47 | Str, |
37 | Int { signedness: Signedness, bitness: IntBitness }, | 48 | Int(BuiltinInt), |
38 | Float { bitness: FloatBitness }, | 49 | Float(BuiltinFloat), |
39 | } | 50 | } |
40 | 51 | ||
41 | impl BuiltinType { | 52 | impl BuiltinType { |
@@ -45,22 +56,22 @@ impl BuiltinType { | |||
45 | (name::BOOL, BuiltinType::Bool), | 56 | (name::BOOL, BuiltinType::Bool), |
46 | (name::STR, BuiltinType::Str ), | 57 | (name::STR, BuiltinType::Str ), |
47 | 58 | ||
48 | (name::ISIZE, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::Xsize }), | 59 | (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), |
49 | (name::I8, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X8 }), | 60 | (name::I8, BuiltinType::Int(BuiltinInt::I8)), |
50 | (name::I16, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X16 }), | 61 | (name::I16, BuiltinType::Int(BuiltinInt::I16)), |
51 | (name::I32, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X32 }), | 62 | (name::I32, BuiltinType::Int(BuiltinInt::I32)), |
52 | (name::I64, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X64 }), | 63 | (name::I64, BuiltinType::Int(BuiltinInt::I64)), |
53 | (name::I128, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X128 }), | 64 | (name::I128, BuiltinType::Int(BuiltinInt::I128)), |
54 | 65 | ||
55 | (name::USIZE, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }), | 66 | (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), |
56 | (name::U8, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }), | 67 | (name::U8, BuiltinType::Int(BuiltinInt::U8)), |
57 | (name::U16, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }), | 68 | (name::U16, BuiltinType::Int(BuiltinInt::U16)), |
58 | (name::U32, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }), | 69 | (name::U32, BuiltinType::Int(BuiltinInt::U32)), |
59 | (name::U64, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }), | 70 | (name::U64, BuiltinType::Int(BuiltinInt::U64)), |
60 | (name::U128, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }), | 71 | (name::U128, BuiltinType::Int(BuiltinInt::U128)), |
61 | 72 | ||
62 | (name::F32, BuiltinType::Float { bitness: FloatBitness::X32 }), | 73 | (name::F32, BuiltinType::Float(BuiltinFloat::F32)), |
63 | (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }), | 74 | (name::F64, BuiltinType::Float(BuiltinFloat::F64)), |
64 | ]; | 75 | ]; |
65 | } | 76 | } |
66 | 77 | ||
@@ -70,7 +81,7 @@ impl fmt::Display for BuiltinType { | |||
70 | BuiltinType::Char => "char", | 81 | BuiltinType::Char => "char", |
71 | BuiltinType::Bool => "bool", | 82 | BuiltinType::Bool => "bool", |
72 | BuiltinType::Str => "str", | 83 | BuiltinType::Str => "str", |
73 | BuiltinType::Int { signedness, bitness } => match (signedness, bitness) { | 84 | BuiltinType::Int(BuiltinInt { signedness, bitness }) => match (signedness, bitness) { |
74 | (Signedness::Signed, IntBitness::Xsize) => "isize", | 85 | (Signedness::Signed, IntBitness::Xsize) => "isize", |
75 | (Signedness::Signed, IntBitness::X8) => "i8", | 86 | (Signedness::Signed, IntBitness::X8) => "i8", |
76 | (Signedness::Signed, IntBitness::X16) => "i16", | 87 | (Signedness::Signed, IntBitness::X16) => "i16", |
@@ -85,7 +96,7 @@ impl fmt::Display for BuiltinType { | |||
85 | (Signedness::Unsigned, IntBitness::X64) => "u64", | 96 | (Signedness::Unsigned, IntBitness::X64) => "u64", |
86 | (Signedness::Unsigned, IntBitness::X128) => "u128", | 97 | (Signedness::Unsigned, IntBitness::X128) => "u128", |
87 | }, | 98 | }, |
88 | BuiltinType::Float { bitness } => match bitness { | 99 | BuiltinType::Float(BuiltinFloat { bitness }) => match bitness { |
89 | FloatBitness::X32 => "f32", | 100 | FloatBitness::X32 => "f32", |
90 | FloatBitness::X64 => "f64", | 101 | FloatBitness::X64 => "f64", |
91 | }, | 102 | }, |
@@ -93,3 +104,57 @@ impl fmt::Display for BuiltinType { | |||
93 | f.write_str(type_name) | 104 | f.write_str(type_name) |
94 | } | 105 | } |
95 | } | 106 | } |
107 | |||
108 | #[rustfmt::skip] | ||
109 | impl BuiltinInt { | ||
110 | pub const ISIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize }; | ||
111 | pub const I8 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 }; | ||
112 | pub const I16 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 }; | ||
113 | pub const I32 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 }; | ||
114 | pub const I64 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 }; | ||
115 | pub const I128 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 }; | ||
116 | |||
117 | pub const USIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }; | ||
118 | pub const U8 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }; | ||
119 | pub const U16 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }; | ||
120 | pub const U32 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }; | ||
121 | pub const U64 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }; | ||
122 | pub const U128 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }; | ||
123 | |||
124 | |||
125 | pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> { | ||
126 | let res = match suffix { | ||
127 | "isize" => Self::ISIZE, | ||
128 | "i8" => Self::I8, | ||
129 | "i16" => Self::I16, | ||
130 | "i32" => Self::I32, | ||
131 | "i64" => Self::I64, | ||
132 | "i128" => Self::I128, | ||
133 | |||
134 | "usize" => Self::USIZE, | ||
135 | "u8" => Self::U8, | ||
136 | "u16" => Self::U16, | ||
137 | "u32" => Self::U32, | ||
138 | "u64" => Self::U64, | ||
139 | "u128" => Self::U128, | ||
140 | |||
141 | _ => return None, | ||
142 | }; | ||
143 | Some(res) | ||
144 | } | ||
145 | } | ||
146 | |||
147 | #[rustfmt::skip] | ||
148 | impl BuiltinFloat { | ||
149 | pub const F32: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X32 }; | ||
150 | pub const F64: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X64 }; | ||
151 | |||
152 | pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> { | ||
153 | let res = match suffix { | ||
154 | "f32" => BuiltinFloat::F32, | ||
155 | "f64" => BuiltinFloat::F64, | ||
156 | _ => return None, | ||
157 | }; | ||
158 | Some(res) | ||
159 | } | ||
160 | } | ||
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs new file mode 100644 index 000000000..04c1d8f69 --- /dev/null +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -0,0 +1,421 @@ | |||
1 | //! This module describes hir-level representation of expressions. | ||
2 | //! | ||
3 | //! This representaion is: | ||
4 | //! | ||
5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish | ||
6 | //! between different `1` in `1 + 1`. | ||
7 | //! 2. Independent of syntax. Though syntactic provenance information can be | ||
8 | //! attached separately via id-based side map. | ||
9 | //! 3. Unresolved. Paths are stored as sequences of names, and not as defs the | ||
10 | //! names refer to. | ||
11 | //! 4. Desugared. There's no `if let`. | ||
12 | //! | ||
13 | //! See also a neighboring `body` module. | ||
14 | |||
15 | use hir_expand::name::Name; | ||
16 | use ra_arena::{impl_arena_id, RawId}; | ||
17 | |||
18 | use crate::{ | ||
19 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
20 | path::{GenericArgs, Path}, | ||
21 | type_ref::{Mutability, TypeRef}, | ||
22 | }; | ||
23 | |||
24 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
25 | pub struct ExprId(RawId); | ||
26 | impl_arena_id!(ExprId); | ||
27 | |||
28 | impl ExprId { | ||
29 | pub fn dummy() -> ExprId { | ||
30 | ExprId((!0).into()) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
35 | pub struct PatId(RawId); | ||
36 | impl_arena_id!(PatId); | ||
37 | |||
38 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
39 | pub enum Literal { | ||
40 | String(String), | ||
41 | ByteString(Vec<u8>), | ||
42 | Char(char), | ||
43 | Bool(bool), | ||
44 | Int(u64, Option<BuiltinInt>), | ||
45 | Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq | ||
46 | } | ||
47 | |||
48 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
49 | pub enum Expr { | ||
50 | /// This is produced if syntax tree does not have a required expression piece. | ||
51 | Missing, | ||
52 | Path(Path), | ||
53 | If { | ||
54 | condition: ExprId, | ||
55 | then_branch: ExprId, | ||
56 | else_branch: Option<ExprId>, | ||
57 | }, | ||
58 | Block { | ||
59 | statements: Vec<Statement>, | ||
60 | tail: Option<ExprId>, | ||
61 | }, | ||
62 | Loop { | ||
63 | body: ExprId, | ||
64 | }, | ||
65 | While { | ||
66 | condition: ExprId, | ||
67 | body: ExprId, | ||
68 | }, | ||
69 | For { | ||
70 | iterable: ExprId, | ||
71 | pat: PatId, | ||
72 | body: ExprId, | ||
73 | }, | ||
74 | Call { | ||
75 | callee: ExprId, | ||
76 | args: Vec<ExprId>, | ||
77 | }, | ||
78 | MethodCall { | ||
79 | receiver: ExprId, | ||
80 | method_name: Name, | ||
81 | args: Vec<ExprId>, | ||
82 | generic_args: Option<GenericArgs>, | ||
83 | }, | ||
84 | Match { | ||
85 | expr: ExprId, | ||
86 | arms: Vec<MatchArm>, | ||
87 | }, | ||
88 | Continue, | ||
89 | Break { | ||
90 | expr: Option<ExprId>, | ||
91 | }, | ||
92 | Return { | ||
93 | expr: Option<ExprId>, | ||
94 | }, | ||
95 | RecordLit { | ||
96 | path: Option<Path>, | ||
97 | fields: Vec<RecordLitField>, | ||
98 | spread: Option<ExprId>, | ||
99 | }, | ||
100 | Field { | ||
101 | expr: ExprId, | ||
102 | name: Name, | ||
103 | }, | ||
104 | Await { | ||
105 | expr: ExprId, | ||
106 | }, | ||
107 | Try { | ||
108 | expr: ExprId, | ||
109 | }, | ||
110 | TryBlock { | ||
111 | body: ExprId, | ||
112 | }, | ||
113 | Cast { | ||
114 | expr: ExprId, | ||
115 | type_ref: TypeRef, | ||
116 | }, | ||
117 | Ref { | ||
118 | expr: ExprId, | ||
119 | mutability: Mutability, | ||
120 | }, | ||
121 | Box { | ||
122 | expr: ExprId, | ||
123 | }, | ||
124 | UnaryOp { | ||
125 | expr: ExprId, | ||
126 | op: UnaryOp, | ||
127 | }, | ||
128 | BinaryOp { | ||
129 | lhs: ExprId, | ||
130 | rhs: ExprId, | ||
131 | op: Option<BinaryOp>, | ||
132 | }, | ||
133 | Index { | ||
134 | base: ExprId, | ||
135 | index: ExprId, | ||
136 | }, | ||
137 | Lambda { | ||
138 | args: Vec<PatId>, | ||
139 | arg_types: Vec<Option<TypeRef>>, | ||
140 | body: ExprId, | ||
141 | }, | ||
142 | Tuple { | ||
143 | exprs: Vec<ExprId>, | ||
144 | }, | ||
145 | Array(Array), | ||
146 | Literal(Literal), | ||
147 | } | ||
148 | |||
149 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
150 | pub enum BinaryOp { | ||
151 | LogicOp(LogicOp), | ||
152 | ArithOp(ArithOp), | ||
153 | CmpOp(CmpOp), | ||
154 | Assignment { op: Option<ArithOp> }, | ||
155 | } | ||
156 | |||
157 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
158 | pub enum LogicOp { | ||
159 | And, | ||
160 | Or, | ||
161 | } | ||
162 | |||
163 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
164 | pub enum CmpOp { | ||
165 | Eq { negated: bool }, | ||
166 | Ord { ordering: Ordering, strict: bool }, | ||
167 | } | ||
168 | |||
169 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
170 | pub enum Ordering { | ||
171 | Less, | ||
172 | Greater, | ||
173 | } | ||
174 | |||
175 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
176 | pub enum ArithOp { | ||
177 | Add, | ||
178 | Mul, | ||
179 | Sub, | ||
180 | Div, | ||
181 | Rem, | ||
182 | Shl, | ||
183 | Shr, | ||
184 | BitXor, | ||
185 | BitOr, | ||
186 | BitAnd, | ||
187 | } | ||
188 | |||
189 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | ||
190 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
191 | pub enum Array { | ||
192 | ElementList(Vec<ExprId>), | ||
193 | Repeat { initializer: ExprId, repeat: ExprId }, | ||
194 | } | ||
195 | |||
196 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
197 | pub struct MatchArm { | ||
198 | pub pats: Vec<PatId>, | ||
199 | pub guard: Option<ExprId>, | ||
200 | pub expr: ExprId, | ||
201 | } | ||
202 | |||
203 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
204 | pub struct RecordLitField { | ||
205 | pub name: Name, | ||
206 | pub expr: ExprId, | ||
207 | } | ||
208 | |||
209 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
210 | pub enum Statement { | ||
211 | Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, | ||
212 | Expr(ExprId), | ||
213 | } | ||
214 | |||
215 | impl Expr { | ||
216 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
217 | match self { | ||
218 | Expr::Missing => {} | ||
219 | Expr::Path(_) => {} | ||
220 | Expr::If { condition, then_branch, else_branch } => { | ||
221 | f(*condition); | ||
222 | f(*then_branch); | ||
223 | if let Some(else_branch) = else_branch { | ||
224 | f(*else_branch); | ||
225 | } | ||
226 | } | ||
227 | Expr::Block { statements, tail } => { | ||
228 | for stmt in statements { | ||
229 | match stmt { | ||
230 | Statement::Let { initializer, .. } => { | ||
231 | if let Some(expr) = initializer { | ||
232 | f(*expr); | ||
233 | } | ||
234 | } | ||
235 | Statement::Expr(e) => f(*e), | ||
236 | } | ||
237 | } | ||
238 | if let Some(expr) = tail { | ||
239 | f(*expr); | ||
240 | } | ||
241 | } | ||
242 | Expr::TryBlock { body } => f(*body), | ||
243 | Expr::Loop { body } => f(*body), | ||
244 | Expr::While { condition, body } => { | ||
245 | f(*condition); | ||
246 | f(*body); | ||
247 | } | ||
248 | Expr::For { iterable, body, .. } => { | ||
249 | f(*iterable); | ||
250 | f(*body); | ||
251 | } | ||
252 | Expr::Call { callee, args } => { | ||
253 | f(*callee); | ||
254 | for arg in args { | ||
255 | f(*arg); | ||
256 | } | ||
257 | } | ||
258 | Expr::MethodCall { receiver, args, .. } => { | ||
259 | f(*receiver); | ||
260 | for arg in args { | ||
261 | f(*arg); | ||
262 | } | ||
263 | } | ||
264 | Expr::Match { expr, arms } => { | ||
265 | f(*expr); | ||
266 | for arm in arms { | ||
267 | f(arm.expr); | ||
268 | } | ||
269 | } | ||
270 | Expr::Continue => {} | ||
271 | Expr::Break { expr } | Expr::Return { expr } => { | ||
272 | if let Some(expr) = expr { | ||
273 | f(*expr); | ||
274 | } | ||
275 | } | ||
276 | Expr::RecordLit { fields, spread, .. } => { | ||
277 | for field in fields { | ||
278 | f(field.expr); | ||
279 | } | ||
280 | if let Some(expr) = spread { | ||
281 | f(*expr); | ||
282 | } | ||
283 | } | ||
284 | Expr::Lambda { body, .. } => { | ||
285 | f(*body); | ||
286 | } | ||
287 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
288 | f(*lhs); | ||
289 | f(*rhs); | ||
290 | } | ||
291 | Expr::Index { base, index } => { | ||
292 | f(*base); | ||
293 | f(*index); | ||
294 | } | ||
295 | Expr::Field { expr, .. } | ||
296 | | Expr::Await { expr } | ||
297 | | Expr::Try { expr } | ||
298 | | Expr::Cast { expr, .. } | ||
299 | | Expr::Ref { expr, .. } | ||
300 | | Expr::UnaryOp { expr, .. } | ||
301 | | Expr::Box { expr } => { | ||
302 | f(*expr); | ||
303 | } | ||
304 | Expr::Tuple { exprs } => { | ||
305 | for expr in exprs { | ||
306 | f(*expr); | ||
307 | } | ||
308 | } | ||
309 | Expr::Array(a) => match a { | ||
310 | Array::ElementList(exprs) => { | ||
311 | for expr in exprs { | ||
312 | f(*expr); | ||
313 | } | ||
314 | } | ||
315 | Array::Repeat { initializer, repeat } => { | ||
316 | f(*initializer); | ||
317 | f(*repeat) | ||
318 | } | ||
319 | }, | ||
320 | Expr::Literal(_) => {} | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | |||
325 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
326 | /// that this is not the final binding *mode* that we infer after type | ||
327 | /// inference. | ||
328 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
329 | pub enum BindingAnnotation { | ||
330 | /// No binding annotation given: this means that the final binding mode | ||
331 | /// will depend on whether we have skipped through a `&` reference | ||
332 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
333 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
334 | /// ultimately be inferred to be by-reference. | ||
335 | Unannotated, | ||
336 | |||
337 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
338 | Mutable, | ||
339 | |||
340 | /// Annotated as `ref`, like `ref x` | ||
341 | Ref, | ||
342 | |||
343 | /// Annotated as `ref mut x`. | ||
344 | RefMut, | ||
345 | } | ||
346 | |||
347 | impl BindingAnnotation { | ||
348 | pub fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
349 | match (is_mutable, is_ref) { | ||
350 | (true, true) => BindingAnnotation::RefMut, | ||
351 | (false, true) => BindingAnnotation::Ref, | ||
352 | (true, false) => BindingAnnotation::Mutable, | ||
353 | (false, false) => BindingAnnotation::Unannotated, | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
359 | pub struct RecordFieldPat { | ||
360 | pub name: Name, | ||
361 | pub pat: PatId, | ||
362 | } | ||
363 | |||
364 | /// Close relative to rustc's hir::PatKind | ||
365 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
366 | pub enum Pat { | ||
367 | Missing, | ||
368 | Wild, | ||
369 | Tuple(Vec<PatId>), | ||
370 | Record { | ||
371 | path: Option<Path>, | ||
372 | args: Vec<RecordFieldPat>, | ||
373 | // FIXME: 'ellipsis' option | ||
374 | }, | ||
375 | Range { | ||
376 | start: ExprId, | ||
377 | end: ExprId, | ||
378 | }, | ||
379 | Slice { | ||
380 | prefix: Vec<PatId>, | ||
381 | rest: Option<PatId>, | ||
382 | suffix: Vec<PatId>, | ||
383 | }, | ||
384 | Path(Path), | ||
385 | Lit(ExprId), | ||
386 | Bind { | ||
387 | mode: BindingAnnotation, | ||
388 | name: Name, | ||
389 | subpat: Option<PatId>, | ||
390 | }, | ||
391 | TupleStruct { | ||
392 | path: Option<Path>, | ||
393 | args: Vec<PatId>, | ||
394 | }, | ||
395 | Ref { | ||
396 | pat: PatId, | ||
397 | mutability: Mutability, | ||
398 | }, | ||
399 | } | ||
400 | |||
401 | impl Pat { | ||
402 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | ||
403 | match self { | ||
404 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | ||
405 | Pat::Bind { subpat, .. } => { | ||
406 | subpat.iter().copied().for_each(f); | ||
407 | } | ||
408 | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { | ||
409 | args.iter().copied().for_each(f); | ||
410 | } | ||
411 | Pat::Ref { pat, .. } => f(*pat), | ||
412 | Pat::Slice { prefix, rest, suffix } => { | ||
413 | let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); | ||
414 | total_iter.copied().for_each(f); | ||
415 | } | ||
416 | Pat::Record { args, .. } => { | ||
417 | args.iter().map(|f| f.pat).for_each(f); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 239317efe..4a758bb83 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -14,6 +14,8 @@ pub mod type_ref; | |||
14 | pub mod builtin_type; | 14 | pub mod builtin_type; |
15 | pub mod adt; | 15 | pub mod adt; |
16 | pub mod diagnostics; | 16 | pub mod diagnostics; |
17 | pub mod expr; | ||
18 | pub mod body; | ||
17 | 19 | ||
18 | #[cfg(test)] | 20 | #[cfg(test)] |
19 | mod test_db; | 21 | mod test_db; |
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 4416421ae..010b45141 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs | |||
@@ -276,7 +276,7 @@ impl RootDatabase { | |||
276 | 276 | ||
277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); | 277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); |
278 | self.query(hir::db::InferQuery).sweep(sweep); | 278 | self.query(hir::db::InferQuery).sweep(sweep); |
279 | self.query(hir::db::BodyHirQuery).sweep(sweep); | 279 | self.query(hir::db::BodyQuery).sweep(sweep); |
280 | } | 280 | } |
281 | 281 | ||
282 | pub(crate) fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { | 282 | pub(crate) fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { |
@@ -333,7 +333,7 @@ impl RootDatabase { | |||
333 | hir::db::GenericPredicatesQuery | 333 | hir::db::GenericPredicatesQuery |
334 | hir::db::GenericDefaultsQuery | 334 | hir::db::GenericDefaultsQuery |
335 | hir::db::BodyWithSourceMapQuery | 335 | hir::db::BodyWithSourceMapQuery |
336 | hir::db::BodyHirQuery | 336 | hir::db::BodyQuery |
337 | hir::db::ImplsInCrateQuery | 337 | hir::db::ImplsInCrateQuery |
338 | hir::db::ImplsForTraitQuery | 338 | hir::db::ImplsForTraitQuery |
339 | hir::db::AssociatedTyDataQuery | 339 | hir::db::AssociatedTyDataQuery |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 28dadea9d..cf88911b7 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::path::{Path, PathBuf}; | 3 | use std::path::{Path, PathBuf}; |
4 | use std::str::FromStr; | ||
4 | 5 | ||
5 | use cargo_metadata::{CargoOpt, MetadataCommand}; | 6 | use cargo_metadata::{CargoOpt, MetadataCommand}; |
6 | use ra_arena::{impl_arena_id, Arena, RawId}; | 7 | use ra_arena::{impl_arena_id, Arena, RawId}; |
@@ -140,18 +141,21 @@ impl CargoWorkspace { | |||
140 | let ws_members = &meta.workspace_members; | 141 | let ws_members = &meta.workspace_members; |
141 | 142 | ||
142 | for meta_pkg in meta.packages { | 143 | for meta_pkg in meta.packages { |
143 | let is_member = ws_members.contains(&meta_pkg.id); | 144 | let cargo_metadata::Package { id, edition, name, manifest_path, .. } = meta_pkg; |
145 | let is_member = ws_members.contains(&id); | ||
146 | let edition = Edition::from_str(&edition) | ||
147 | .map_err(|e| (format!("metadata for package {} failed: {}", &name, e.msg)))?; | ||
144 | let pkg = packages.alloc(PackageData { | 148 | let pkg = packages.alloc(PackageData { |
145 | name: meta_pkg.name, | 149 | name, |
146 | manifest: meta_pkg.manifest_path.clone(), | 150 | manifest: manifest_path, |
147 | targets: Vec::new(), | 151 | targets: Vec::new(), |
148 | is_member, | 152 | is_member, |
149 | edition: Edition::from_string(&meta_pkg.edition), | 153 | edition, |
150 | dependencies: Vec::new(), | 154 | dependencies: Vec::new(), |
151 | features: Vec::new(), | 155 | features: Vec::new(), |
152 | }); | 156 | }); |
153 | let pkg_data = &mut packages[pkg]; | 157 | let pkg_data = &mut packages[pkg]; |
154 | pkg_by_id.insert(meta_pkg.id.clone(), pkg); | 158 | pkg_by_id.insert(id, pkg); |
155 | for meta_tgt in meta_pkg.targets { | 159 | for meta_tgt in meta_pkg.targets { |
156 | let tgt = targets.alloc(TargetData { | 160 | let tgt = targets.alloc(TargetData { |
157 | pkg, | 161 | pkg, |
diff --git a/xtask/tests/tidy-tests/docs.rs b/xtask/tests/tidy-tests/docs.rs index 227937f46..141219860 100644 --- a/xtask/tests/tidy-tests/docs.rs +++ b/xtask/tests/tidy-tests/docs.rs | |||
@@ -1,10 +1,6 @@ | |||
1 | use std::fs; | 1 | use std::{collections::HashMap, fs, io::prelude::*, io::BufReader, path::Path}; |
2 | use std::io::prelude::*; | ||
3 | use std::io::BufReader; | ||
4 | use std::path::Path; | ||
5 | 2 | ||
6 | use walkdir::{DirEntry, WalkDir}; | 3 | use walkdir::{DirEntry, WalkDir}; |
7 | |||
8 | use xtask::project_root; | 4 | use xtask::project_root; |
9 | 5 | ||
10 | fn is_exclude_dir(p: &Path) -> bool { | 6 | fn is_exclude_dir(p: &Path) -> bool { |
@@ -37,6 +33,7 @@ fn no_docs_comments() { | |||
37 | let crates = project_root().join("crates"); | 33 | let crates = project_root().join("crates"); |
38 | let iter = WalkDir::new(crates); | 34 | let iter = WalkDir::new(crates); |
39 | let mut missing_docs = Vec::new(); | 35 | let mut missing_docs = Vec::new(); |
36 | let mut contains_fixme = Vec::new(); | ||
40 | for f in iter.into_iter().filter_entry(|e| !is_hidden(e)) { | 37 | for f in iter.into_iter().filter_entry(|e| !is_hidden(e)) { |
41 | let f = f.unwrap(); | 38 | let f = f.unwrap(); |
42 | if f.file_type().is_dir() { | 39 | if f.file_type().is_dir() { |
@@ -54,7 +51,12 @@ fn no_docs_comments() { | |||
54 | let mut reader = BufReader::new(fs::File::open(f.path()).unwrap()); | 51 | let mut reader = BufReader::new(fs::File::open(f.path()).unwrap()); |
55 | let mut line = String::new(); | 52 | let mut line = String::new(); |
56 | reader.read_line(&mut line).unwrap(); | 53 | reader.read_line(&mut line).unwrap(); |
57 | if !line.starts_with("//!") { | 54 | |
55 | if line.starts_with("//!") { | ||
56 | if line.contains("FIXME") { | ||
57 | contains_fixme.push(f.path().to_path_buf()) | ||
58 | } | ||
59 | } else { | ||
58 | missing_docs.push(f.path().display().to_string()); | 60 | missing_docs.push(f.path().display().to_string()); |
59 | } | 61 | } |
60 | } | 62 | } |
@@ -65,4 +67,39 @@ fn no_docs_comments() { | |||
65 | missing_docs.join("\n") | 67 | missing_docs.join("\n") |
66 | ) | 68 | ) |
67 | } | 69 | } |
70 | |||
71 | let whitelist = [ | ||
72 | "ra_batch", | ||
73 | "ra_cli", | ||
74 | "ra_db", | ||
75 | "ra_hir", | ||
76 | "ra_hir_expand", | ||
77 | "ra_hir_def", | ||
78 | "ra_ide_api", | ||
79 | "ra_lsp_server", | ||
80 | "ra_mbe", | ||
81 | "ra_parser", | ||
82 | "ra_prof", | ||
83 | "ra_project_model", | ||
84 | "ra_syntax", | ||
85 | "ra_text_edit", | ||
86 | "ra_tt", | ||
87 | ]; | ||
88 | |||
89 | let mut has_fixmes = whitelist.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>(); | ||
90 | 'outer: for path in contains_fixme { | ||
91 | for krate in whitelist.iter() { | ||
92 | if path.components().any(|it| it.as_os_str() == *krate) { | ||
93 | has_fixmes.insert(krate, true); | ||
94 | continue 'outer; | ||
95 | } | ||
96 | } | ||
97 | panic!("FIXME doc in a fully-documented crate: {}", path.display()) | ||
98 | } | ||
99 | |||
100 | for (krate, has_fixme) in has_fixmes.iter() { | ||
101 | if !has_fixme { | ||
102 | panic!("crate {} is fully documented, remove it from the white list", krate) | ||
103 | } | ||
104 | } | ||
68 | } | 105 | } |