aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-07 00:11:13 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-07 00:11:13 +0000
commitc69bb8a7e737e09c667f9e343d0f1d3e4c13b8f7 (patch)
treed3d006919d15d6a26ff1a8091cf1e5341842c1aa
parent3c945ceb5e0dc287139de0589cc9a4b285911f17 (diff)
parentd618b1f2ce25db8817d1649d7ec7720594789067 (diff)
Merge #446
446: Use HIR Expr for type inference r=flodiebold a=flodiebold Now we can reuse the type inference inside a function when typing whitespace etc. :) The order of the lines in the type tests changed a bit, which I'm not sure why, but there are no actual changes in the inference results. Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_analysis/src/completion/complete_dot.rs10
-rw-r--r--crates/ra_analysis/src/hover.rs9
-rw-r--r--crates/ra_arena/src/lib.rs2
-rw-r--r--crates/ra_arena/src/map.rs70
-rw-r--r--crates/ra_hir/src/expr.rs47
-rw-r--r--crates/ra_hir/src/ty.rs546
-rw-r--r--crates/ra_hir/src/ty/tests.rs39
-rw-r--r--crates/ra_hir/src/ty/tests/data/backwards.txt (renamed from crates/ra_hir/src/ty/tests/data/0006_backwards.txt)30
-rw-r--r--crates/ra_hir/src/ty/tests/data/basics.txt (renamed from crates/ra_hir/src/ty/tests/data/0001_basics.txt)16
-rw-r--r--crates/ra_hir/src/ty/tests/data/boolean_op.txt (renamed from crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt)48
-rw-r--r--crates/ra_hir/src/ty/tests/data/let.txt (renamed from crates/ra_hir/src/ty/tests/data/0002_let.txt)6
-rw-r--r--crates/ra_hir/src/ty/tests/data/paths.txt (renamed from crates/ra_hir/src/ty/tests/data/0003_paths.txt)4
-rw-r--r--crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt (renamed from crates/ra_hir/src/ty/tests/data/0005_refs.txt)32
-rw-r--r--crates/ra_hir/src/ty/tests/data/self.txt (renamed from crates/ra_hir/src/ty/tests/data/0007_self.txt)4
-rw-r--r--crates/ra_hir/src/ty/tests/data/struct.txt (renamed from crates/ra_hir/src/ty/tests/data/0004_struct.txt)22
15 files changed, 459 insertions, 426 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs
index 031d8b98f..54ce1b638 100644
--- a/crates/ra_analysis/src/completion/complete_dot.rs
+++ b/crates/ra_analysis/src/completion/complete_dot.rs
@@ -1,4 +1,3 @@
1use ra_syntax::ast::AstNode;
2use hir::{Ty, Def}; 1use hir::{Ty, Def};
3 2
4use crate::Cancelable; 3use crate::Cancelable;
@@ -11,11 +10,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca
11 _ => return Ok(()), 10 _ => return Ok(()),
12 }; 11 };
13 let infer_result = function.infer(ctx.db)?; 12 let infer_result = function.infer(ctx.db)?;
14 let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) { 13 let syntax_mapping = function.body_syntax_mapping(ctx.db)?;
15 ty 14 let expr = match syntax_mapping.node_expr(receiver) {
16 } else { 15 Some(expr) => expr,
17 return Ok(()); 16 None => return Ok(()),
18 }; 17 };
18 let receiver_ty = infer_result[expr].clone();
19 if !ctx.is_method_call { 19 if !ctx.is_method_call {
20 complete_fields(acc, ctx, receiver_ty)?; 20 complete_fields(acc, ctx, receiver_ty)?;
21 } 21 }
diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs
index ba1fb9beb..06632df4f 100644
--- a/crates/ra_analysis/src/hover.rs
+++ b/crates/ra_analysis/src/hover.rs
@@ -64,7 +64,14 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option
64 parent_fn 64 parent_fn
65 )?); 65 )?);
66 let infer = function.infer(db)?; 66 let infer = function.infer(db)?;
67 Ok(infer.type_of_node(node).map(|t| t.to_string())) 67 let syntax_mapping = function.body_syntax_mapping(db)?;
68 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) {
69 Ok(Some(infer[expr].to_string()))
70 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) {
71 Ok(Some(infer[pat].to_string()))
72 } else {
73 Ok(None)
74 }
68} 75}
69 76
70// FIXME: this should not really use navigation target. Rather, approximatelly 77// FIXME: this should not really use navigation target. Rather, approximatelly
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index a5eeb4118..040977dc4 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -6,6 +6,8 @@ use std::{
6 ops::{Index, IndexMut}, 6 ops::{Index, IndexMut},
7}; 7};
8 8
9pub mod map;
10
9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct RawId(u32); 12pub struct RawId(u32);
11 13
diff --git a/crates/ra_arena/src/map.rs b/crates/ra_arena/src/map.rs
new file mode 100644
index 000000000..2f09d677f
--- /dev/null
+++ b/crates/ra_arena/src/map.rs
@@ -0,0 +1,70 @@
1//! A map from arena IDs to some other type. Space requirement is O(highest ID).
2
3use std::marker::PhantomData;
4
5use super::ArenaId;
6
7/// A map from arena IDs to some other type. Space requirement is O(highest ID).
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct ArenaMap<ID, T> {
10 v: Vec<Option<T>>,
11 _ty: PhantomData<ID>,
12}
13
14impl<ID: ArenaId, T> ArenaMap<ID, T> {
15 pub fn insert(&mut self, id: ID, t: T) {
16 let idx = Self::to_idx(id);
17 if self.v.capacity() <= idx {
18 self.v.reserve(idx + 1 - self.v.capacity());
19 }
20 if self.v.len() <= idx {
21 while self.v.len() <= idx {
22 self.v.push(None);
23 }
24 }
25 self.v[idx] = Some(t);
26 }
27
28 pub fn get(&self, id: ID) -> Option<&T> {
29 self.v.get(Self::to_idx(id)).and_then(|it| it.as_ref())
30 }
31
32 pub fn values(&self) -> impl Iterator<Item = &T> {
33 self.v.iter().filter_map(|o| o.as_ref())
34 }
35
36 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
37 self.v.iter_mut().filter_map(|o| o.as_mut())
38 }
39
40 pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> {
41 self.v
42 .iter()
43 .enumerate()
44 .filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
45 }
46
47 fn to_idx(id: ID) -> usize {
48 u32::from(id.into_raw()) as usize
49 }
50
51 fn from_idx(idx: usize) -> ID {
52 ID::from_raw((idx as u32).into())
53 }
54}
55
56impl<ID: ArenaId, T> std::ops::Index<ID> for ArenaMap<ID, T> {
57 type Output = T;
58 fn index(&self, id: ID) -> &T {
59 self.v[Self::to_idx(id)].as_ref().unwrap()
60 }
61}
62
63impl<ID, T> Default for ArenaMap<ID, T> {
64 fn default() -> Self {
65 ArenaMap {
66 v: Vec::new(),
67 _ty: PhantomData,
68 }
69 }
70}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 6866fc2ac..b0063cad2 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3 3
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5 5
6use ra_arena::{Arena, RawId, impl_arena_id}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_db::{LocalSyntaxPtr, Cancelable}; 7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; 8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
9 9
@@ -39,9 +39,9 @@ pub struct Body {
39pub struct BodySyntaxMapping { 39pub struct BodySyntaxMapping {
40 body: Arc<Body>, 40 body: Arc<Body>,
41 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>, 41 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
42 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>, 42 expr_syntax_mapping_back: ArenaMap<ExprId, LocalSyntaxPtr>,
43 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>, 43 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
44 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>, 44 pat_syntax_mapping_back: ArenaMap<PatId, LocalSyntaxPtr>,
45} 45}
46 46
47impl Body { 47impl Body {
@@ -72,17 +72,27 @@ impl Index<PatId> for Body {
72 72
73impl BodySyntaxMapping { 73impl BodySyntaxMapping {
74 pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> { 74 pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> {
75 self.expr_syntax_mapping_back.get(&expr).cloned() 75 self.expr_syntax_mapping_back.get(expr).cloned()
76 } 76 }
77 pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> { 77 pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> {
78 self.expr_syntax_mapping.get(&ptr).cloned() 78 self.expr_syntax_mapping.get(&ptr).cloned()
79 } 79 }
80 pub fn node_expr(&self, node: ast::Expr) -> Option<ExprId> {
81 self.expr_syntax_mapping
82 .get(&LocalSyntaxPtr::new(node.syntax()))
83 .cloned()
84 }
80 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> { 85 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
81 self.pat_syntax_mapping_back.get(&pat).cloned() 86 self.pat_syntax_mapping_back.get(pat).cloned()
82 } 87 }
83 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> { 88 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
84 self.pat_syntax_mapping.get(&ptr).cloned() 89 self.pat_syntax_mapping.get(&ptr).cloned()
85 } 90 }
91 pub fn node_pat(&self, node: ast::Pat) -> Option<PatId> {
92 self.pat_syntax_mapping
93 .get(&LocalSyntaxPtr::new(node.syntax()))
94 .cloned()
95 }
86 96
87 pub fn body(&self) -> &Arc<Body> { 97 pub fn body(&self) -> &Arc<Body> {
88 &self.body 98 &self.body
@@ -159,6 +169,11 @@ pub enum Expr {
159 expr: ExprId, 169 expr: ExprId,
160 op: Option<UnaryOp>, 170 op: Option<UnaryOp>,
161 }, 171 },
172 BinaryOp {
173 lhs: ExprId,
174 rhs: ExprId,
175 op: Option<BinaryOp>,
176 },
162 Lambda { 177 Lambda {
163 args: Vec<PatId>, 178 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>, 179 arg_types: Vec<Option<TypeRef>>,
@@ -166,7 +181,8 @@ pub enum Expr {
166 }, 181 },
167} 182}
168 183
169pub type UnaryOp = ast::PrefixOp; 184pub use ra_syntax::ast::PrefixOp as UnaryOp;
185pub use ra_syntax::ast::BinOp as BinaryOp;
170 186
171#[derive(Debug, Clone, Eq, PartialEq)] 187#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct MatchArm { 188pub struct MatchArm {
@@ -266,6 +282,10 @@ impl Expr {
266 Expr::Lambda { body, .. } => { 282 Expr::Lambda { body, .. } => {
267 f(*body); 283 f(*body);
268 } 284 }
285 Expr::BinaryOp { lhs, rhs, .. } => {
286 f(*lhs);
287 f(*rhs);
288 }
269 Expr::Field { expr, .. } 289 Expr::Field { expr, .. }
270 | Expr::Try { expr } 290 | Expr::Try { expr }
271 | Expr::Cast { expr, .. } 291 | Expr::Cast { expr, .. }
@@ -314,9 +334,9 @@ struct ExprCollector {
314 exprs: Arena<ExprId, Expr>, 334 exprs: Arena<ExprId, Expr>,
315 pats: Arena<PatId, Pat>, 335 pats: Arena<PatId, Pat>,
316 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>, 336 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
317 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>, 337 expr_syntax_mapping_back: ArenaMap<ExprId, LocalSyntaxPtr>,
318 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>, 338 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
319 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>, 339 pat_syntax_mapping_back: ArenaMap<PatId, LocalSyntaxPtr>,
320} 340}
321 341
322impl ExprCollector { 342impl ExprCollector {
@@ -325,9 +345,9 @@ impl ExprCollector {
325 exprs: Arena::default(), 345 exprs: Arena::default(),
326 pats: Arena::default(), 346 pats: Arena::default(),
327 expr_syntax_mapping: FxHashMap::default(), 347 expr_syntax_mapping: FxHashMap::default(),
328 expr_syntax_mapping_back: FxHashMap::default(), 348 expr_syntax_mapping_back: ArenaMap::default(),
329 pat_syntax_mapping: FxHashMap::default(), 349 pat_syntax_mapping: FxHashMap::default(),
330 pat_syntax_mapping_back: FxHashMap::default(), 350 pat_syntax_mapping_back: ArenaMap::default(),
331 } 351 }
332 } 352 }
333 353
@@ -586,6 +606,12 @@ impl ExprCollector {
586 syntax_ptr, 606 syntax_ptr,
587 ) 607 )
588 } 608 }
609 ast::Expr::BinExpr(e) => {
610 let lhs = self.collect_expr_opt(e.lhs());
611 let rhs = self.collect_expr_opt(e.rhs());
612 let op = e.op();
613 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
614 }
589 615
590 // TODO implement HIR for these: 616 // TODO implement HIR for these:
591 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 617 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -593,7 +619,6 @@ impl ExprCollector {
593 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 619 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
594 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 620 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
595 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 621 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
596 ast::Expr::BinExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
597 ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 622 ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
598 } 623 }
599 } 624 }
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index b685259d7..d57990cd2 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,25 +17,23 @@ mod primitive;
17#[cfg(test)] 17#[cfg(test)]
18mod tests; 18mod tests;
19 19
20use std::ops::Index;
20use std::sync::Arc; 21use std::sync::Arc;
21use std::{fmt, mem}; 22use std::{fmt, mem};
22 23
23use log; 24use log;
24use rustc_hash::FxHashMap;
25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; 25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError};
26use ra_arena::map::ArenaMap;
26 27
27use ra_db::{LocalSyntaxPtr, Cancelable}; 28use ra_db::Cancelable;
28use ra_syntax::{
29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp, BinOp},
30 SyntaxNodeRef
31};
32 29
33use crate::{ 30use crate::{
34 Def, DefId, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, 31 Def, DefId, Module, Function, Struct, Enum, Path, Name, ImplBlock,
32 FnSignature, FnScopes,
35 db::HirDatabase, 33 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 34 type_ref::{TypeRef, Mutability},
37 name::KnownName, 35 name::KnownName,
38 ScopesWithSyntaxMapping, 36 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement},
39}; 37};
40 38
41/// The ID of a type variable. 39/// The ID of a type variable.
@@ -82,9 +80,10 @@ impl UnifyValue for TypeVarValue {
82 match (value1, value2) { 80 match (value1, value2) {
83 // We should never equate two type variables, both of which have 81 // We should never equate two type variables, both of which have
84 // known types. Instead, we recursively equate those types. 82 // known types. Instead, we recursively equate those types.
85 (TypeVarValue::Known(..), TypeVarValue::Known(..)) => { 83 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
86 panic!("equating two type variables, both of which have known types") 84 "equating two type variables, both of which have known types: {:?} and {:?}",
87 } 85 t1, t2
86 ),
88 87
89 // If one side is known, prefer that one. 88 // If one side is known, prefer that one.
90 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), 89 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()),
@@ -321,26 +320,6 @@ impl Ty {
321 Ok(ty) 320 Ok(ty)
322 } 321 }
323 322
324 // TODO: These should not be necessary long-term, since everything will work on HIR
325 pub(crate) fn from_ast_opt(
326 db: &impl HirDatabase,
327 module: &Module,
328 impl_block: Option<&ImplBlock>,
329 node: Option<ast::TypeRef>,
330 ) -> Cancelable<Self> {
331 node.map(|n| Ty::from_ast(db, module, impl_block, n))
332 .unwrap_or(Ok(Ty::Unknown))
333 }
334
335 pub(crate) fn from_ast(
336 db: &impl HirDatabase,
337 module: &Module,
338 impl_block: Option<&ImplBlock>,
339 node: ast::TypeRef,
340 ) -> Cancelable<Self> {
341 Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
342 }
343
344 pub fn unit() -> Self { 323 pub fn unit() -> Self {
345 Ty::Tuple(Arc::new([])) 324 Ty::Tuple(Arc::new([]))
346 } 325 }
@@ -417,26 +396,18 @@ impl fmt::Display for Ty {
417// Functions returning declared types for items 396// Functions returning declared types for items
418 397
419/// Compute the declared type of a function. This should not need to look at the 398/// Compute the declared type of a function. This should not need to look at the
420/// function body (but currently uses the function AST, so does anyway - TODO). 399/// function body.
421fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 400fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
422 let syntax = f.syntax(db); 401 let signature = f.signature(db);
423 let module = f.module(db)?; 402 let module = f.module(db)?;
424 let impl_block = f.impl_block(db)?; 403 let impl_block = f.impl_block(db)?;
425 let node = syntax.borrowed();
426 // TODO we ignore type parameters for now 404 // TODO we ignore type parameters for now
427 let input = node 405 let input = signature
428 .param_list() 406 .args()
429 .map(|pl| { 407 .iter()
430 pl.params() 408 .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), tr))
431 .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref())) 409 .collect::<Cancelable<Vec<_>>>()?;
432 .collect() 410 let output = Ty::from_hir(db, &module, impl_block.as_ref(), signature.ret_type())?;
433 })
434 .unwrap_or_else(|| Ok(Vec::new()))?;
435 let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
436 Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
437 } else {
438 Ty::unit()
439 };
440 let sig = FnSig { input, output }; 411 let sig = FnSig { input, output };
441 Ok(Ty::FnPtr(Arc::new(sig))) 412 Ok(Ty::FnPtr(Arc::new(sig)))
442} 413}
@@ -499,16 +470,23 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
499/// The result of type inference: A mapping from expressions and patterns to types. 470/// The result of type inference: A mapping from expressions and patterns to types.
500#[derive(Clone, PartialEq, Eq, Debug)] 471#[derive(Clone, PartialEq, Eq, Debug)]
501pub struct InferenceResult { 472pub struct InferenceResult {
502 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 473 type_of_expr: ArenaMap<ExprId, Ty>,
474 type_of_pat: ArenaMap<PatId, Ty>,
503} 475}
504 476
505impl InferenceResult { 477impl Index<ExprId> for InferenceResult {
506 /// Returns the type of the given syntax node, if it was inferred. Will 478 type Output = Ty;
507 /// return `None` for syntax nodes not in the inferred function or not 479
508 /// pointing to an expression/pattern, `Some(Ty::Unknown)` for 480 fn index(&self, expr: ExprId) -> &Ty {
509 /// expressions/patterns that could not be inferred. 481 self.type_of_expr.get(expr).unwrap_or(&Ty::Unknown)
510 pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> { 482 }
511 self.type_of.get(&LocalSyntaxPtr::new(node)).cloned() 483}
484
485impl Index<PatId> for InferenceResult {
486 type Output = Ty;
487
488 fn index(&self, pat: PatId) -> &Ty {
489 self.type_of_pat.get(pat).unwrap_or(&Ty::Unknown)
512 } 490 }
513} 491}
514 492
@@ -516,44 +494,46 @@ impl InferenceResult {
516#[derive(Clone, Debug)] 494#[derive(Clone, Debug)]
517struct InferenceContext<'a, D: HirDatabase> { 495struct InferenceContext<'a, D: HirDatabase> {
518 db: &'a D, 496 db: &'a D,
519 scopes: ScopesWithSyntaxMapping, 497 body: Arc<Body>,
520 /// The self param for the current method, if it exists. 498 scopes: Arc<FnScopes>,
521 self_param: Option<LocalSyntaxPtr>,
522 module: Module, 499 module: Module,
523 impl_block: Option<ImplBlock>, 500 impl_block: Option<ImplBlock>,
524 var_unification_table: InPlaceUnificationTable<TypeVarId>, 501 var_unification_table: InPlaceUnificationTable<TypeVarId>,
525 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 502 type_of_expr: ArenaMap<ExprId, Ty>,
503 type_of_pat: ArenaMap<PatId, Ty>,
526 /// The return type of the function being inferred. 504 /// The return type of the function being inferred.
527 return_ty: Ty, 505 return_ty: Ty,
528} 506}
529 507
530// helper function that determines whether a binary operator 508// helper function that determines whether a binary operator
531// always returns a boolean 509// always returns a boolean
532fn is_boolean_operator(op: BinOp) -> bool { 510fn is_boolean_operator(op: BinaryOp) -> bool {
533 match op { 511 match op {
534 BinOp::BooleanOr 512 BinaryOp::BooleanOr
535 | BinOp::BooleanAnd 513 | BinaryOp::BooleanAnd
536 | BinOp::EqualityTest 514 | BinaryOp::EqualityTest
537 | BinOp::LesserEqualTest 515 | BinaryOp::LesserEqualTest
538 | BinOp::GreaterEqualTest 516 | BinaryOp::GreaterEqualTest
539 | BinOp::LesserTest 517 | BinaryOp::LesserTest
540 | BinOp::GreaterTest => true, 518 | BinaryOp::GreaterTest => true,
541 } 519 }
542} 520}
543 521
544impl<'a, D: HirDatabase> InferenceContext<'a, D> { 522impl<'a, D: HirDatabase> InferenceContext<'a, D> {
545 fn new( 523 fn new(
546 db: &'a D, 524 db: &'a D,
547 scopes: ScopesWithSyntaxMapping, 525 body: Arc<Body>,
526 scopes: Arc<FnScopes>,
548 module: Module, 527 module: Module,
549 impl_block: Option<ImplBlock>, 528 impl_block: Option<ImplBlock>,
550 ) -> Self { 529 ) -> Self {
551 InferenceContext { 530 InferenceContext {
552 type_of: FxHashMap::default(), 531 type_of_expr: ArenaMap::default(),
532 type_of_pat: ArenaMap::default(),
553 var_unification_table: InPlaceUnificationTable::new(), 533 var_unification_table: InPlaceUnificationTable::new(),
554 self_param: None, // set during parameter typing
555 return_ty: Ty::Unknown, // set in collect_fn_signature 534 return_ty: Ty::Unknown, // set in collect_fn_signature
556 db, 535 db,
536 body,
557 scopes, 537 scopes,
558 module, 538 module,
559 impl_block, 539 impl_block,
@@ -561,24 +541,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
561 } 541 }
562 542
563 fn resolve_all(mut self) -> InferenceResult { 543 fn resolve_all(mut self) -> InferenceResult {
564 let mut types = mem::replace(&mut self.type_of, FxHashMap::default()); 544 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default());
565 for ty in types.values_mut() { 545 for ty in expr_types.values_mut() {
546 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
547 *ty = resolved;
548 }
549 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default());
550 for ty in pat_types.values_mut() {
566 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 551 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
567 *ty = resolved; 552 *ty = resolved;
568 } 553 }
569 InferenceResult { type_of: types } 554 InferenceResult {
555 type_of_expr: expr_types,
556 type_of_pat: pat_types,
557 }
570 } 558 }
571 559
572 fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { 560 fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
573 self.type_of.insert(LocalSyntaxPtr::new(node), ty); 561 self.type_of_expr.insert(expr, ty);
574 } 562 }
575 563
576 fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { 564 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
577 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) 565 self.type_of_pat.insert(pat, ty);
578 } 566 }
579 567
580 fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> { 568 fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> {
581 Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref) 569 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)
582 } 570 }
583 571
584 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 572 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
@@ -673,23 +661,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
673 }) 661 })
674 } 662 }
675 663
676 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { 664 fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Cancelable<Option<Ty>> {
677 let ast_path = ctry!(expr.path()); 665 if path.is_ident() || path.is_self() {
678 let path = ctry!(Path::from_ast(ast_path));
679 if path.is_ident() {
680 // resolve locally 666 // resolve locally
681 let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); 667 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
682 if let Some(scope_entry) = self.scopes.resolve_local_name(name) { 668 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
683 let ty = ctry!(self.type_of.get(&scope_entry.ptr())); 669 let ty = ctry!(self.type_of_pat.get(scope_entry.pat()));
684 let ty = self.resolve_ty_as_possible(ty.clone()); 670 let ty = self.resolve_ty_as_possible(ty.clone());
685 return Ok(Some(ty)); 671 return Ok(Some(ty));
686 }; 672 };
687 } else if path.is_self() {
688 // resolve `self` param
689 let self_param = ctry!(self.self_param);
690 let ty = ctry!(self.type_of.get(&self_param));
691 let ty = self.resolve_ty_as_possible(ty.clone());
692 return Ok(Some(ty));
693 }; 673 };
694 674
695 // resolve in module 675 // resolve in module
@@ -699,8 +679,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
699 Ok(Some(ty)) 679 Ok(Some(ty))
700 } 680 }
701 681
702 fn resolve_variant(&self, path: Option<ast::Path>) -> Cancelable<(Ty, Option<DefId>)> { 682 fn resolve_variant(&self, path: Option<&Path>) -> Cancelable<(Ty, Option<DefId>)> {
703 let path = if let Some(path) = path.and_then(Path::from_ast) { 683 let path = if let Some(path) = path {
704 path 684 path
705 } else { 685 } else {
706 return Ok((Ty::Unknown, None)); 686 return Ok((Ty::Unknown, None));
@@ -719,74 +699,51 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
719 }) 699 })
720 } 700 }
721 701
722 fn infer_expr_opt( 702 fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Cancelable<Ty> {
723 &mut self, 703 let body = Arc::clone(&self.body); // avoid borrow checker problem
724 expr: Option<ast::Expr>, 704 let ty = match &body[expr] {
725 expected: &Expectation, 705 Expr::Missing => Ty::Unknown,
726 ) -> Cancelable<Ty> { 706 Expr::If {
727 if let Some(e) = expr { 707 condition,
728 self.infer_expr(e, expected) 708 then_branch,
729 } else { 709 else_branch,
730 Ok(Ty::Unknown) 710 } => {
731 } 711 // if let is desugared to match, so this is always simple if
732 } 712 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
733 713 let then_ty = self.infer_expr(*then_branch, expected)?;
734 fn infer_expr(&mut self, expr: ast::Expr, expected: &Expectation) -> Cancelable<Ty> { 714 if let Some(else_branch) = else_branch {
735 let ty = match expr { 715 self.infer_expr(*else_branch, expected)?;
736 ast::Expr::IfExpr(e) => {
737 if let Some(condition) = e.condition() {
738 let expected = if condition.pat().is_none() {
739 Expectation::has_type(Ty::Bool)
740 } else {
741 Expectation::none()
742 };
743 self.infer_expr_opt(condition.expr(), &expected)?;
744 // TODO write type for pat
745 };
746 let if_ty = self.infer_block_opt(e.then_branch(), expected)?;
747 if let Some(else_branch) = e.else_branch() {
748 self.infer_block(else_branch, expected)?;
749 } else { 716 } else {
750 // no else branch -> unit 717 // no else branch -> unit
751 self.unify(&expected.ty, &Ty::unit()); // actually coerce 718 self.unify(&expected.ty, &Ty::unit()); // actually coerce
752 } 719 }
753 if_ty 720 then_ty
754 } 721 }
755 ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block(), expected)?, 722 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?,
756 ast::Expr::LoopExpr(e) => { 723 Expr::Loop { body } => {
757 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?; 724 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
758 // TODO never, or the type of the break param 725 // TODO handle break with value
759 Ty::Unknown 726 Ty::Never
760 } 727 }
761 ast::Expr::WhileExpr(e) => { 728 Expr::While { condition, body } => {
762 if let Some(condition) = e.condition() { 729 // while let is desugared to a match loop, so this is always simple while
763 let expected = if condition.pat().is_none() { 730 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
764 Expectation::has_type(Ty::Bool) 731 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
765 } else {
766 Expectation::none()
767 };
768 self.infer_expr_opt(condition.expr(), &expected)?;
769 // TODO write type for pat
770 };
771 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
772 // TODO always unit?
773 Ty::unit() 732 Ty::unit()
774 } 733 }
775 ast::Expr::ForExpr(e) => { 734 Expr::For { iterable, body, .. } => {
776 let _iterable_ty = self.infer_expr_opt(e.iterable(), &Expectation::none()); 735 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
777 if let Some(_pat) = e.pat() { 736 // TODO write type for pat
778 // TODO write type for pat 737 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
779 }
780 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
781 // TODO always unit?
782 Ty::unit() 738 Ty::unit()
783 } 739 }
784 ast::Expr::LambdaExpr(e) => { 740 Expr::Lambda { body, .. } => {
785 let _body_ty = self.infer_expr_opt(e.body(), &Expectation::none())?; 741 // TODO write types for args, infer lambda type etc.
742 let _body_ty = self.infer_expr(*body, &Expectation::none())?;
786 Ty::Unknown 743 Ty::Unknown
787 } 744 }
788 ast::Expr::CallExpr(e) => { 745 Expr::Call { callee, args } => {
789 let callee_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 746 let callee_ty = self.infer_expr(*callee, &Expectation::none())?;
790 let (arg_tys, ret_ty) = match &callee_ty { 747 let (arg_tys, ret_ty) = match &callee_ty {
791 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), 748 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()),
792 _ => { 749 _ => {
@@ -795,112 +752,102 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
795 (&[][..], Ty::Unknown) 752 (&[][..], Ty::Unknown)
796 } 753 }
797 }; 754 };
798 if let Some(arg_list) = e.arg_list() { 755 for (i, arg) in args.iter().enumerate() {
799 for (i, arg) in arg_list.args().enumerate() { 756 self.infer_expr(
800 self.infer_expr( 757 *arg,
801 arg, 758 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)),
802 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)), 759 )?;
803 )?;
804 }
805 } 760 }
806 ret_ty 761 ret_ty
807 } 762 }
808 ast::Expr::MethodCallExpr(e) => { 763 Expr::MethodCall { receiver, args, .. } => {
809 let _receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 764 let _receiver_ty = self.infer_expr(*receiver, &Expectation::none())?;
810 if let Some(arg_list) = e.arg_list() { 765 // TODO resolve method...
811 for arg in arg_list.args() { 766 for (_i, arg) in args.iter().enumerate() {
812 // TODO unify / expect argument type 767 // TODO unify / expect argument type
813 self.infer_expr(arg, &Expectation::none())?; 768 self.infer_expr(*arg, &Expectation::none())?;
814 }
815 } 769 }
816 Ty::Unknown 770 Ty::Unknown
817 } 771 }
818 ast::Expr::MatchExpr(e) => { 772 Expr::Match { expr, arms } => {
819 let _ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 773 let _ty = self.infer_expr(*expr, &Expectation::none())?;
820 if let Some(match_arm_list) = e.match_arm_list() { 774 for arm in arms {
821 for arm in match_arm_list.arms() { 775 // TODO type the bindings in pats
822 // TODO type the bindings in pat 776 // TODO type the guard
823 // TODO type the guard 777 let _ty = self.infer_expr(arm.expr, &Expectation::none())?;
824 let _ty = self.infer_expr_opt(arm.expr(), &Expectation::none())?;
825 }
826 // TODO unify all the match arm types
827 Ty::Unknown
828 } else {
829 Ty::Unknown
830 } 778 }
779 // TODO unify all the match arm types
780 Ty::Unknown
831 } 781 }
832 ast::Expr::TupleExpr(_e) => Ty::Unknown, 782 Expr::Path(p) => self.infer_path_expr(expr, p)?.unwrap_or(Ty::Unknown),
833 ast::Expr::ArrayExpr(_e) => Ty::Unknown, 783 Expr::Continue => Ty::Never,
834 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), 784 Expr::Break { expr } => {
835 ast::Expr::ContinueExpr(_e) => Ty::Never, 785 if let Some(expr) = expr {
836 ast::Expr::BreakExpr(_e) => Ty::Never, 786 // TODO handle break with value
837 ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr(), expected)?, 787 self.infer_expr(*expr, &Expectation::none())?;
838 ast::Expr::Label(_e) => Ty::Unknown, 788 }
839 ast::Expr::ReturnExpr(e) => {
840 // TODO expect return type of function
841 self.infer_expr_opt(e.expr(), &Expectation::none())?;
842 Ty::Never 789 Ty::Never
843 } 790 }
844 ast::Expr::StructLit(e) => { 791 Expr::Return { expr } => {
845 let (ty, def_id) = self.resolve_variant(e.path())?; 792 if let Some(expr) = expr {
846 if let Some(nfl) = e.named_field_list() { 793 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()))?;
847 for field in nfl.fields() {
848 let field_ty = if let (Some(def_id), Some(nr)) = (def_id, field.name_ref())
849 {
850 self.db.type_for_field(def_id, nr.as_name())?
851 } else {
852 Ty::Unknown
853 };
854 self.infer_expr_opt(field.expr(), &Expectation::has_type(field_ty))?;
855 }
856 } 794 }
857 ty 795 Ty::Never
858 } 796 }
859 ast::Expr::IndexExpr(_e) => Ty::Unknown, 797 Expr::StructLit {
860 ast::Expr::FieldExpr(e) => { 798 path,
861 let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 799 fields,
862 if let Some(nr) = e.name_ref() { 800 spread,
863 let ty = match receiver_ty { 801 } => {
864 Ty::Tuple(fields) => { 802 let (ty, def_id) = self.resolve_variant(path.as_ref())?;
865 let i = nr.text().parse::<usize>().ok(); 803 for field in fields {
866 i.and_then(|i| fields.get(i).cloned()) 804 let field_ty = if let Some(def_id) = def_id {
867 .unwrap_or(Ty::Unknown) 805 self.db.type_for_field(def_id, field.name.clone())?
868 } 806 } else {
869 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, nr.as_name())?, 807 Ty::Unknown
870 _ => Ty::Unknown,
871 }; 808 };
872 self.insert_type_vars(ty) 809 self.infer_expr(field.expr, &Expectation::has_type(field_ty))?;
873 } else { 810 }
874 Ty::Unknown 811 if let Some(expr) = spread {
812 self.infer_expr(*expr, &Expectation::has_type(ty.clone()))?;
875 } 813 }
814 ty
815 }
816 Expr::Field { expr, name } => {
817 let receiver_ty = self.infer_expr(*expr, &Expectation::none())?;
818 let ty = match receiver_ty {
819 Ty::Tuple(fields) => {
820 let i = name.to_string().parse::<usize>().ok();
821 i.and_then(|i| fields.get(i).cloned())
822 .unwrap_or(Ty::Unknown)
823 }
824 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone())?,
825 _ => Ty::Unknown,
826 };
827 self.insert_type_vars(ty)
876 } 828 }
877 ast::Expr::TryExpr(e) => { 829 Expr::Try { expr } => {
878 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 830 let _inner_ty = self.infer_expr(*expr, &Expectation::none())?;
879 Ty::Unknown 831 Ty::Unknown
880 } 832 }
881 ast::Expr::CastExpr(e) => { 833 Expr::Cast { expr, type_ref } => {
882 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 834 let _inner_ty = self.infer_expr(*expr, &Expectation::none())?;
883 let cast_ty = Ty::from_ast_opt( 835 let cast_ty =
884 self.db, 836 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)?;
885 &self.module,
886 self.impl_block.as_ref(),
887 e.type_ref(),
888 )?;
889 let cast_ty = self.insert_type_vars(cast_ty); 837 let cast_ty = self.insert_type_vars(cast_ty);
890 // TODO do the coercion... 838 // TODO check the cast...
891 cast_ty 839 cast_ty
892 } 840 }
893 ast::Expr::RefExpr(e) => { 841 Expr::Ref { expr, mutability } => {
894 // TODO pass the expectation down 842 // TODO pass the expectation down
895 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 843 let inner_ty = self.infer_expr(*expr, &Expectation::none())?;
896 let m = Mutability::from_mutable(e.is_mut());
897 // TODO reference coercions etc. 844 // TODO reference coercions etc.
898 Ty::Ref(Arc::new(inner_ty), m) 845 Ty::Ref(Arc::new(inner_ty), *mutability)
899 } 846 }
900 ast::Expr::PrefixExpr(e) => { 847 Expr::UnaryOp { expr, op } => {
901 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 848 let inner_ty = self.infer_expr(*expr, &Expectation::none())?;
902 match e.op() { 849 match op {
903 Some(PrefixOp::Deref) => { 850 Some(UnaryOp::Deref) => {
904 match inner_ty { 851 match inner_ty {
905 // builtin deref: 852 // builtin deref:
906 Ty::Ref(ref_inner, _) => (*ref_inner).clone(), 853 Ty::Ref(ref_inner, _) => (*ref_inner).clone(),
@@ -912,18 +859,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
912 _ => Ty::Unknown, 859 _ => Ty::Unknown,
913 } 860 }
914 } 861 }
915 ast::Expr::RangeExpr(_e) => Ty::Unknown, 862 Expr::BinaryOp { lhs, rhs, op } => match op {
916 ast::Expr::BinExpr(e) => match e.op() {
917 Some(op) => { 863 Some(op) => {
918 let subtype_expectation = match op { 864 let subtype_expectation = match op {
919 BinOp::BooleanAnd | BinOp::BooleanOr => Expectation::has_type(Ty::Bool), 865 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => {
866 Expectation::has_type(Ty::Bool)
867 }
920 _ => Expectation::none(), 868 _ => Expectation::none(),
921 }; 869 };
922 let (lhs, rhs) = e.sub_exprs(); 870 let _lhs_ty = self.infer_expr(*lhs, &subtype_expectation)?;
923 let _lhs_ty = self.infer_expr_opt(lhs, &subtype_expectation)?; 871 let _rhs_ty = self.infer_expr(*rhs, &subtype_expectation)?;
924 let _rhs_ty = self.infer_expr_opt(rhs, &subtype_expectation)?;
925 872
926 if is_boolean_operator(op) { 873 if is_boolean_operator(*op) {
927 Ty::Bool 874 Ty::Bool
928 } else { 875 } else {
929 Ty::Unknown 876 Ty::Unknown
@@ -931,128 +878,93 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
931 } 878 }
932 _ => Ty::Unknown, 879 _ => Ty::Unknown,
933 }, 880 },
934 ast::Expr::Literal(_e) => Ty::Unknown,
935 }; 881 };
936 // use a new type variable if we got Ty::Unknown here 882 // use a new type variable if we got Ty::Unknown here
937 let ty = self.insert_type_vars_shallow(ty); 883 let ty = self.insert_type_vars_shallow(ty);
938 self.unify(&ty, &expected.ty); 884 self.unify(&ty, &expected.ty);
939 self.write_ty(expr.syntax(), ty.clone()); 885 let ty = self.resolve_ty_as_possible(ty);
886 self.write_expr_ty(expr, ty.clone());
940 Ok(ty) 887 Ok(ty)
941 } 888 }
942 889
943 fn infer_block_opt( 890 fn infer_block(
944 &mut self, 891 &mut self,
945 node: Option<ast::Block>, 892 statements: &[Statement],
893 tail: Option<ExprId>,
946 expected: &Expectation, 894 expected: &Expectation,
947 ) -> Cancelable<Ty> { 895 ) -> Cancelable<Ty> {
948 if let Some(b) = node { 896 for stmt in statements {
949 self.infer_block(b, expected)
950 } else {
951 Ok(Ty::Unknown)
952 }
953 }
954
955 fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelable<Ty> {
956 for stmt in node.statements() {
957 match stmt { 897 match stmt {
958 ast::Stmt::LetStmt(stmt) => { 898 Statement::Let {
959 let decl_ty = Ty::from_ast_opt( 899 pat,
900 type_ref,
901 initializer,
902 } => {
903 let decl_ty = Ty::from_hir_opt(
960 self.db, 904 self.db,
961 &self.module, 905 &self.module,
962 self.impl_block.as_ref(), 906 self.impl_block.as_ref(),
963 stmt.type_ref(), 907 type_ref.as_ref(),
964 )?; 908 )?;
965 let decl_ty = self.insert_type_vars(decl_ty); 909 let decl_ty = self.insert_type_vars(decl_ty);
966 let ty = if let Some(expr) = stmt.initializer() { 910 let ty = if let Some(expr) = initializer {
967 let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; 911 let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty))?;
968 expr_ty 912 expr_ty
969 } else { 913 } else {
970 decl_ty 914 decl_ty
971 }; 915 };
972 916
973 if let Some(pat) = stmt.pat() { 917 self.write_pat_ty(*pat, ty);
974 self.write_ty(pat.syntax(), ty);
975 };
976 } 918 }
977 ast::Stmt::ExprStmt(expr_stmt) => { 919 Statement::Expr(expr) => {
978 self.infer_expr_opt(expr_stmt.expr(), &Expectation::none())?; 920 self.infer_expr(*expr, &Expectation::none())?;
979 } 921 }
980 } 922 }
981 } 923 }
982 let ty = if let Some(expr) = node.expr() { 924 let ty = if let Some(expr) = tail {
983 self.infer_expr(expr, expected)? 925 self.infer_expr(expr, expected)?
984 } else { 926 } else {
985 Ty::unit() 927 Ty::unit()
986 }; 928 };
987 self.write_ty(node.syntax(), ty.clone());
988 Ok(ty) 929 Ok(ty)
989 } 930 }
990 931
991 fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> { 932 fn collect_fn_signature(&mut self, signature: &FnSignature) -> Cancelable<()> {
992 if let Some(param_list) = node.param_list() { 933 let body = Arc::clone(&self.body); // avoid borrow checker problem
993 if let Some(self_param) = param_list.self_param() { 934 for (type_ref, pat) in signature.args().iter().zip(body.args()) {
994 let self_type = if let Some(type_ref) = self_param.type_ref() { 935 let ty = self.make_ty(type_ref)?;
995 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; 936 let ty = self.insert_type_vars(ty);
996 self.insert_type_vars(ty) 937 self.write_pat_ty(*pat, ty);
997 } else {
998 // TODO this should be handled by desugaring during HIR conversion
999 let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?;
1000 let ty = match self_param.flavor() {
1001 ast::SelfParamFlavor::Owned => ty,
1002 ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
1003 ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
1004 };
1005 self.insert_type_vars(ty)
1006 };
1007 if let Some(self_kw) = self_param.self_kw() {
1008 let self_param = LocalSyntaxPtr::new(self_kw.syntax());
1009 self.self_param = Some(self_param);
1010 self.type_of.insert(self_param, self_type);
1011 }
1012 }
1013 for param in param_list.params() {
1014 let pat = if let Some(pat) = param.pat() {
1015 pat
1016 } else {
1017 continue;
1018 };
1019 let ty = if let Some(type_ref) = param.type_ref() {
1020 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
1021 self.insert_type_vars(ty)
1022 } else {
1023 // missing type annotation
1024 self.new_type_var()
1025 };
1026 self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
1027 }
1028 } 938 }
1029 939 self.return_ty = {
1030 self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { 940 let ty = self.make_ty(signature.ret_type())?;
1031 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; 941 let ty = self.insert_type_vars(ty);
1032 self.insert_type_vars(ty) 942 ty
1033 } else {
1034 Ty::unit()
1035 }; 943 };
944 Ok(())
945 }
1036 946
947 fn infer_body(&mut self) -> Cancelable<()> {
948 self.infer_expr(
949 self.body.body_expr(),
950 &Expectation::has_type(self.return_ty.clone()),
951 )?;
1037 Ok(()) 952 Ok(())
1038 } 953 }
1039} 954}
1040 955
1041pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 956pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
1042 let function = Function::new(def_id); // TODO: consts also need inference 957 let function = Function::new(def_id); // TODO: consts also need inference
1043 let scopes = function.scopes(db)?; 958 let body = function.body(db)?;
959 let scopes = db.fn_scopes(def_id)?;
1044 let module = function.module(db)?; 960 let module = function.module(db)?;
1045 let impl_block = function.impl_block(db)?; 961 let impl_block = function.impl_block(db)?;
1046 let mut ctx = InferenceContext::new(db, scopes, module, impl_block); 962 let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block);
1047
1048 let syntax = function.syntax(db);
1049 let node = syntax.borrowed();
1050 963
1051 ctx.collect_fn_signature(node)?; 964 let signature = function.signature(db);
965 ctx.collect_fn_signature(&signature)?;
1052 966
1053 if let Some(block) = node.body() { 967 ctx.infer_body()?;
1054 ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?;
1055 }
1056 968
1057 Ok(Arc::new(ctx.resolve_all())) 969 Ok(Arc::new(ctx.resolve_all()))
1058} 970}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 25a354947..83aedaa00 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -5,7 +5,7 @@ use std::fs;
5 5
6use salsa::Database; 6use salsa::Database;
7 7
8use ra_db::{SyntaxDatabase}; 8use ra_db::SyntaxDatabase;
9use ra_syntax::ast::{self, AstNode}; 9use ra_syntax::ast::{self, AstNode};
10use test_utils::{project_dir, assert_eq_text, read_text}; 10use test_utils::{project_dir, assert_eq_text, read_text};
11 11
@@ -34,7 +34,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
34 "test"; 34 "test";
35 1.0f32; 35 1.0f32;
36}"#, 36}"#,
37 "0001_basics.txt", 37 "basics.txt",
38 ); 38 );
39} 39}
40 40
@@ -48,7 +48,7 @@ fn test() {
48 let c = b; 48 let c = b;
49} 49}
50}"#, 50}"#,
51 "0002_let.txt", 51 "let.txt",
52 ); 52 );
53} 53}
54 54
@@ -67,7 +67,7 @@ fn test() {
67 b::c(); 67 b::c();
68} 68}
69}"#, 69}"#,
70 "0003_paths.txt", 70 "paths.txt",
71 ); 71 );
72} 72}
73 73
@@ -90,7 +90,7 @@ fn test() {
90 a.c; 90 a.c;
91} 91}
92"#, 92"#,
93 "0004_struct.txt", 93 "struct.txt",
94 ); 94 );
95} 95}
96 96
@@ -112,7 +112,7 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
112 *d; 112 *d;
113} 113}
114"#, 114"#,
115 "0005_refs.txt", 115 "refs_and_ptrs.txt",
116 ); 116 );
117} 117}
118 118
@@ -133,7 +133,7 @@ fn test() -> &mut &f64 {
133 &mut &c 133 &mut &c
134} 134}
135"#, 135"#,
136 "0006_backwards.txt", 136 "backwards.txt",
137 ); 137 );
138} 138}
139 139
@@ -152,7 +152,7 @@ impl S {
152 } 152 }
153} 153}
154"#, 154"#,
155 "0007_self.txt", 155 "self.txt",
156 ); 156 );
157} 157}
158 158
@@ -176,7 +176,7 @@ fn test() {
176 10 < 3 176 10 < 3
177} 177}
178"#, 178"#,
179 "0008_boolean_op.txt", 179 "boolean_op.txt",
180 ); 180 );
181} 181}
182 182
@@ -193,7 +193,25 @@ fn infer(content: &str) -> String {
193 .unwrap() 193 .unwrap()
194 .unwrap(); 194 .unwrap();
195 let inference_result = func.infer(&db).unwrap(); 195 let inference_result = func.infer(&db).unwrap();
196 for (syntax_ptr, ty) in &inference_result.type_of { 196 let body_syntax_mapping = func.body_syntax_mapping(&db).unwrap();
197 let mut types = Vec::new();
198 for (pat, ty) in inference_result.type_of_pat.iter() {
199 let syntax_ptr = match body_syntax_mapping.pat_syntax(pat) {
200 Some(sp) => sp,
201 None => continue,
202 };
203 types.push((syntax_ptr, ty));
204 }
205 for (expr, ty) in inference_result.type_of_expr.iter() {
206 let syntax_ptr = match body_syntax_mapping.expr_syntax(expr) {
207 Some(sp) => sp,
208 None => continue,
209 };
210 types.push((syntax_ptr, ty));
211 }
212 // sort ranges for consistency
213 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
214 for (syntax_ptr, ty) in &types {
197 let node = syntax_ptr.resolve(&source_file); 215 let node = syntax_ptr.resolve(&source_file);
198 write!( 216 write!(
199 acc, 217 acc,
@@ -246,7 +264,6 @@ fn test_data_dir() -> PathBuf {
246} 264}
247 265
248#[test] 266#[test]
249#[should_panic] // TODO this should work once hir::Expr is used
250fn typing_whitespace_inside_a_function_should_not_invalidate_types() { 267fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
251 let (mut db, pos) = MockDatabase::with_position( 268 let (mut db, pos) = MockDatabase::with_position(
252 " 269 "
diff --git a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt b/crates/ra_hir/src/ty/tests/data/backwards.txt
index 120069401..b6807fb2a 100644
--- a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt
+++ b/crates/ra_hir/src/ty/tests/data/backwards.txt
@@ -1,20 +1,20 @@
1[22; 24) '{}': ()
2[14; 15) 'x': u32 1[14; 15) 'x': u32
3[142; 158) 'unknow...nction': [unknown] 2[22; 24) '{}': ()
4[126; 127) 'a': u32
5[198; 216) 'unknow...tion()': f64
6[228; 229) 'c': f64
7[198; 214) 'unknow...nction': [unknown]
8[166; 184) 'S { i3...d: b }': S
9[222; 229) '&mut &c': &mut &f64
10[194; 195) 'c': f64
11[92; 110) 'unknow...tion()': u32
12[142; 160) 'unknow...tion()': i32
13[92; 108) 'unknow...nction': [unknown]
14[116; 128) 'takes_u32(a)': ()
15[78; 231) '{ ...t &c }': &mut &f64 3[78; 231) '{ ...t &c }': &mut &f64
16[227; 229) '&c': &f64
17[88; 89) 'a': u32 4[88; 89) 'a': u32
18[181; 182) 'b': i32 5[92; 108) 'unknow...nction': [unknown]
6[92; 110) 'unknow...tion()': u32
19[116; 125) 'takes_u32': fn(u32,) -> () 7[116; 125) 'takes_u32': fn(u32,) -> ()
8[116; 128) 'takes_u32(a)': ()
9[126; 127) 'a': u32
20[138; 139) 'b': i32 10[138; 139) 'b': i32
11[142; 158) 'unknow...nction': [unknown]
12[142; 160) 'unknow...tion()': i32
13[166; 184) 'S { i3...d: b }': S
14[181; 182) 'b': i32
15[194; 195) 'c': f64
16[198; 214) 'unknow...nction': [unknown]
17[198; 216) 'unknow...tion()': f64
18[222; 229) '&mut &c': &mut &f64
19[227; 229) '&c': &f64
20[228; 229) 'c': f64
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt
index 212e92e00..8ea244ba8 100644
--- a/crates/ra_hir/src/ty/tests/data/0001_basics.txt
+++ b/crates/ra_hir/src/ty/tests/data/basics.txt
@@ -1,13 +1,13 @@
1[9; 10) 'a': u32
2[17; 18) 'b': isize
3[27; 28) 'c': !
1[33; 34) 'd': &[unknown] 4[33; 34) 'd': &[unknown]
2[88; 94) '1isize': [unknown] 5[42; 121) '{ ...f32; }': ()
3[48; 49) 'a': u32 6[48; 49) 'a': u32
4[55; 56) 'b': isize 7[55; 56) 'b': isize
5[112; 118) '1.0f32': [unknown]
6[76; 82) '1usize': [unknown]
7[9; 10) 'a': u32
8[27; 28) 'c': !
9[62; 63) 'c': ! 8[62; 63) 'c': !
10[17; 18) 'b': isize
11[100; 106) '"test"': [unknown]
12[42; 121) '{ ...f32; }': ()
13[69; 70) 'd': &[unknown] 9[69; 70) 'd': &[unknown]
10[76; 82) '1usize': [unknown]
11[88; 94) '1isize': [unknown]
12[100; 106) '"test"': [unknown]
13[112; 118) '1.0f32': [unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt b/crates/ra_hir/src/ty/tests/data/boolean_op.txt
index ca01ad159..cce8d68fb 100644
--- a/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt
+++ b/crates/ra_hir/src/ty/tests/data/boolean_op.txt
@@ -1,31 +1,31 @@
1[28; 32) '0i32': i32
2[22; 34) '{ 0i32 }': i32
3[6; 7) 'x': [unknown] 1[6; 7) 'x': [unknown]
4[127; 134) 'CONST_1': [unknown] 2[22; 34) '{ 0i32 }': i32
5[201; 205) '3i32': bool 3[28; 32) '0i32': i32
6[76; 77) 'y': bool 4[46; 237) '{ ... < 3 }': bool
7[65; 66) 'b': bool 5[56; 57) 'x': bool
6[60; 61) 'a': bool
8[60; 66) 'a && b': bool 7[60; 66) 'a && b': bool
8[65; 66) 'b': bool
9[76; 77) 'y': bool
10[80; 84) 'true': bool
11[80; 93) 'true || false': bool
12[88; 93) 'false': bool
13[103; 104) 'z': bool
14[107; 108) 'x': bool
15[107; 113) 'x == y': bool
16[112; 113) 'y': bool
17[123; 124) 'h': bool
18[127; 134) 'CONST_1': [unknown]
9[127; 145) 'CONST_...ONST_2': bool 19[127; 145) 'CONST_...ONST_2': bool
20[138; 145) 'CONST_2': [unknown]
21[155; 156) 'c': [unknown]
22[159; 172) 'f(z || y) + 5': [unknown]
10[182; 183) 'd': [unknown] 23[182; 183) 'd': [unknown]
11[229; 231) '10': [unknown]
12[209; 222) '"hello world"': bool
13[229; 235) '10 < 3': bool
14[186; 187) 'b': [unknown] 24[186; 187) 'b': [unknown]
15[159; 172) 'f(z || y) + 5': [unknown] 25[197; 198) 'e': bool
16[56; 57) 'x': bool 26[201; 205) '3i32': bool
17[112; 113) 'y': bool
18[201; 222) '3i32 &...world"': bool 27[201; 222) '3i32 &...world"': bool
28[209; 222) '"hello world"': bool
29[229; 231) '10': [unknown]
30[229; 235) '10 < 3': bool
19[234; 235) '3': [unknown] 31[234; 235) '3': [unknown]
20[138; 145) 'CONST_2': [unknown]
21[80; 93) 'true || false': bool
22[46; 237) '{ ... < 3 }': bool
23[197; 198) 'e': bool
24[107; 113) 'x == y': bool
25[88; 93) 'false': bool
26[80; 84) 'true': bool
27[123; 124) 'h': bool
28[155; 156) 'c': [unknown]
29[103; 104) 'z': bool
30[60; 61) 'a': bool
31[107; 108) 'x': bool
diff --git a/crates/ra_hir/src/ty/tests/data/0002_let.txt b/crates/ra_hir/src/ty/tests/data/let.txt
index 916ca25a1..30f4a2cf5 100644
--- a/crates/ra_hir/src/ty/tests/data/0002_let.txt
+++ b/crates/ra_hir/src/ty/tests/data/let.txt
@@ -1,7 +1,7 @@
1[21; 22) 'a': [unknown]
2[52; 53) '1': usize
3[11; 71) '{ ...= b; }': () 1[11; 71) '{ ...= b; }': ()
4[63; 64) 'c': usize 2[21; 22) 'a': [unknown]
5[25; 31) '1isize': [unknown] 3[25; 31) '1isize': [unknown]
6[41; 42) 'b': usize 4[41; 42) 'b': usize
5[52; 53) '1': usize
6[63; 64) 'c': usize
7[67; 68) 'b': usize 7[67; 68) 'b': usize
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/paths.txt
index 2a12d264f..b22f4d4a5 100644
--- a/crates/ra_hir/src/ty/tests/data/0003_paths.txt
+++ b/crates/ra_hir/src/ty/tests/data/paths.txt
@@ -1,9 +1,9 @@
1[15; 20) '{ 1 }': u32 1[15; 20) '{ 1 }': u32
2[17; 18) '1': u32 2[17; 18) '1': u32
3[50; 51) '1': u32
4[48; 53) '{ 1 }': u32 3[48; 53) '{ 1 }': u32
5[82; 88) 'b::c()': u32 4[50; 51) '1': u32
6[67; 91) '{ ...c(); }': () 5[67; 91) '{ ...c(); }': ()
7[73; 74) 'a': fn() -> u32 6[73; 74) 'a': fn() -> u32
8[73; 76) 'a()': u32 7[73; 76) 'a()': u32
9[82; 86) 'b::c': fn() -> u32 8[82; 86) 'b::c': fn() -> u32
9[82; 88) 'b::c()': u32
diff --git a/crates/ra_hir/src/ty/tests/data/0005_refs.txt b/crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt
index 296e955c1..afab343ea 100644
--- a/crates/ra_hir/src/ty/tests/data/0005_refs.txt
+++ b/crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt
@@ -1,23 +1,23 @@
1[115; 117) '&b': &&mut u32 1[9; 10) 'a': &u32
2[88; 94) '&mut a': &mut &u32 2[18; 19) 'b': &mut u32
3[146; 147) 'd': *mut u32 3[31; 32) 'c': *const u32
4[145; 147) '*d': u32
5[65; 66) 'a': &u32
6[46; 47) 'd': *mut u32 4[46; 47) 'd': *mut u32
7[59; 150) '{ ... *d; }': () 5[59; 150) '{ ... *d; }': ()
8[116; 117) 'b': &mut u32 6[65; 66) 'a': &u32
9[131; 132) 'c': *const u32
10[130; 132) '*c': u32
11[72; 74) '*a': u32 7[72; 74) '*a': u32
12[107; 109) '*b': u32 8[73; 74) 'a': &u32
13[108; 109) 'b': &mut u32 9[80; 82) '&a': &&u32
14[9; 10) 'a': &u32 10[81; 82) 'a': &u32
15[18; 19) 'b': &mut u32 11[88; 94) '&mut a': &mut &u32
16[93; 94) 'a': &u32 12[93; 94) 'a': &u32
17[100; 101) 'b': &mut u32 13[100; 101) 'b': &mut u32
18[81; 82) 'a': &u32 14[107; 109) '*b': u32
19[80; 82) '&a': &&u32 15[108; 109) 'b': &mut u32
20[73; 74) 'a': &u32 16[115; 117) '&b': &&mut u32
17[116; 117) 'b': &mut u32
21[123; 124) 'c': *const u32 18[123; 124) 'c': *const u32
22[31; 32) 'c': *const u32 19[130; 132) '*c': u32
20[131; 132) 'c': *const u32
23[138; 139) 'd': *mut u32 21[138; 139) 'd': *mut u32
22[145; 147) '*d': u32
23[146; 147) 'd': *mut u32
diff --git a/crates/ra_hir/src/ty/tests/data/0007_self.txt b/crates/ra_hir/src/ty/tests/data/self.txt
index db4ba17d0..c38029f97 100644
--- a/crates/ra_hir/src/ty/tests/data/0007_self.txt
+++ b/crates/ra_hir/src/ty/tests/data/self.txt
@@ -1,6 +1,6 @@
1[50; 54) 'self': &S
2[34; 38) 'self': &S 1[34; 38) 'self': &S
3[40; 61) '{ ... }': () 2[40; 61) '{ ... }': ()
3[50; 54) 'self': &S
4[75; 79) 'self': &S
4[88; 109) '{ ... }': () 5[88; 109) '{ ... }': ()
5[98; 102) 'self': &S 6[98; 102) 'self': &S
6[75; 79) 'self': &S
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt
index b4af18b87..7b324c82f 100644
--- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/struct.txt
@@ -1,16 +1,16 @@
1[86; 90) 'C(1)': [unknown] 1[72; 154) '{ ...a.c; }': ()
2[121; 122) 'B': B 2[82; 83) 'c': [unknown]
3[86; 87) 'C': [unknown] 3[86; 87) 'C': [unknown]
4[129; 130) '1': [unknown] 4[86; 90) 'C(1)': [unknown]
5[88; 89) '1': [unknown]
6[96; 97) 'B': [unknown]
5[107; 108) 'a': A 7[107; 108) 'a': A
8[114; 133) 'A { b:...C(1) }': A
9[121; 122) 'B': B
6[127; 128) 'C': [unknown] 10[127; 128) 'C': [unknown]
11[127; 131) 'C(1)': C
12[129; 130) '1': [unknown]
13[139; 140) 'a': A
7[139; 142) 'a.b': B 14[139; 142) 'a.b': B
8[114; 133) 'A { b:...C(1) }': A
9[148; 151) 'a.c': C
10[148; 149) 'a': A 15[148; 149) 'a': A
11[139; 140) 'a': A 16[148; 151) 'a.c': C
12[72; 154) '{ ...a.c; }': ()
13[96; 97) 'B': [unknown]
14[88; 89) '1': [unknown]
15[82; 83) 'c': [unknown]
16[127; 131) 'C(1)': C