aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-02-20 21:36:54 +0000
committerFlorian Diebold <[email protected]>2019-02-20 21:48:55 +0000
commit72712b8a428e17d63c413522c770e8f1f0587455 (patch)
tree74455d20e5c1be76b1ecf43e9db448a0cae4bf95 /crates/ra_hir/src
parentc84561bb624280b84eb2fe6c6b2a6b9fe3f1dbf7 (diff)
Fix handling of generics in tuple variants and refactor a bit
Also make them display a tiny bit nicer. Fixes #860.
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/generics.rs13
-rw-r--r--crates/ra_hir/src/ty.rs83
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap6
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap23
-rw-r--r--crates/ra_hir/src/ty/tests.rs21
5 files changed, 105 insertions, 41 deletions
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index fcc513353..c494beeb0 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -87,4 +87,17 @@ impl GenericParams {
87 let parent_count = self.count_parent_params(); 87 let parent_count = self.count_parent_params();
88 parent_count + self.params.len() 88 parent_count + self.params.len()
89 } 89 }
90
91 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
92 if let Some(parent) = &self.parent_params {
93 parent.for_each_param(f);
94 }
95 self.params.iter().for_each(f);
96 }
97
98 pub fn params_including_parent(&self) -> Vec<&GenericParam> {
99 let mut vec = Vec::with_capacity(self.count_params_including_parent());
100 self.for_each_param(&mut |p| vec.push(p));
101 vec
102 }
90} 103}
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d4d896673..7f28a6edd 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -40,7 +40,7 @@ use crate::{
40 name::KnownName, 40 name::KnownName,
41 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, 41 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
42 generics::GenericParams, 42 generics::GenericParams,
43 path::GenericArg, 43 path::{ GenericArgs, GenericArg},
44 adt::VariantDef, 44 adt::VariantDef,
45 resolve::{Resolver, Resolution}, nameres::Namespace 45 resolve::{Resolver, Resolution}, nameres::Namespace
46}; 46};
@@ -165,17 +165,6 @@ impl Substs {
165 pub fn empty() -> Substs { 165 pub fn empty() -> Substs {
166 Substs(Arc::new([])) 166 Substs(Arc::new([]))
167 } 167 }
168
169 /// Replaces the end of the substitutions by other ones.
170 pub(crate) fn replace_tail(self, replace_by: Vec<Ty>) -> Substs {
171 // again missing Arc::make_mut_slice...
172 let len = replace_by.len().min(self.0.len());
173 let parent_len = self.0.len() - len;
174 let mut result = Vec::with_capacity(parent_len + len);
175 result.extend(self.0.iter().take(parent_len).cloned());
176 result.extend(replace_by);
177 Substs(result.into())
178 }
179} 168}
180 169
181/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). 170/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
@@ -639,8 +628,11 @@ impl fmt::Display for Ty {
639 join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?; 628 join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?;
640 write!(f, " -> {}", sig.output) 629 write!(f, " -> {}", sig.output)
641 } 630 }
642 Ty::FnDef { name, substs, sig, .. } => { 631 Ty::FnDef { def, name, substs, sig, .. } => {
643 write!(f, "fn {}", name)?; 632 match def {
633 CallableDef::Function(_) => write!(f, "fn {}", name)?,
634 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
635 }
644 if substs.0.len() > 0 { 636 if substs.0.len() > 0 {
645 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; 637 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?;
646 } 638 }
@@ -712,16 +704,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
712 .iter() 704 .iter()
713 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 705 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
714 .collect::<Vec<_>>(); 706 .collect::<Vec<_>>();
715 let output = type_for_enum(db, def.parent_enum(db));
716 let sig = Arc::new(FnSig { input, output });
717 let substs = make_substs(&generics); 707 let substs = make_substs(&generics);
708 let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone());
709 let sig = Arc::new(FnSig { input, output });
718 Ty::FnDef { def: def.into(), sig, name, substs } 710 Ty::FnDef { def: def.into(), sig, name, substs }
719} 711}
720 712
721fn make_substs(generics: &GenericParams) -> Substs { 713fn make_substs(generics: &GenericParams) -> Substs {
722 Substs( 714 Substs(
723 (0..generics.count_params_including_parent()) 715 generics
724 .map(|_p| Ty::Unknown) 716 .params_including_parent()
717 .into_iter()
718 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
725 .collect::<Vec<_>>() 719 .collect::<Vec<_>>()
726 .into(), 720 .into(),
727 ) 721 )
@@ -736,7 +730,7 @@ fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
736 } 730 }
737} 731}
738 732
739pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { 733fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
740 let generics = s.generic_params(db); 734 let generics = s.generic_params(db);
741 Ty::Adt { 735 Ty::Adt {
742 def_id: s.into(), 736 def_id: s.into(),
@@ -1353,6 +1347,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1353 ty 1347 ty
1354 } 1348 }
1355 1349
1350 fn substs_for_method_call(
1351 &mut self,
1352 def_generics: Option<Arc<GenericParams>>,
1353 generic_args: &Option<GenericArgs>,
1354 ) -> Substs {
1355 let (parent_param_count, param_count) =
1356 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
1357 let mut substs = Vec::with_capacity(parent_param_count + param_count);
1358 for _ in 0..parent_param_count {
1359 substs.push(Ty::Unknown);
1360 }
1361 // handle provided type arguments
1362 if let Some(generic_args) = generic_args {
1363 // if args are provided, it should be all of them, but we can't rely on that
1364 for arg in generic_args.args.iter().take(param_count) {
1365 match arg {
1366 GenericArg::Type(type_ref) => {
1367 let ty = self.make_ty(type_ref);
1368 substs.push(ty);
1369 }
1370 }
1371 }
1372 };
1373 let supplied_params = substs.len();
1374 for _ in supplied_params..parent_param_count + param_count {
1375 substs.push(Ty::Unknown);
1376 }
1377 Substs(substs.into())
1378 }
1379
1356 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 1380 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
1357 let body = Arc::clone(&self.body); // avoid borrow checker problem 1381 let body = Arc::clone(&self.body); // avoid borrow checker problem
1358 let ty = match &body[tgt_expr] { 1382 let ty = match &body[tgt_expr] {
@@ -1443,25 +1467,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1443 } 1467 }
1444 None => (Ty::Unknown, receiver_ty, None), 1468 None => (Ty::Unknown, receiver_ty, None),
1445 }; 1469 };
1446 // handle provided type arguments 1470 let substs = self.substs_for_method_call(def_generics, generic_args);
1447 let method_ty = if let Some(generic_args) = generic_args { 1471 let method_ty = method_ty.apply_substs(substs);
1448 // if args are provided, it should be all of them, but we can't rely on that
1449 let param_count = def_generics.map(|g| g.params.len()).unwrap_or(0);
1450 let mut new_substs = Vec::with_capacity(generic_args.args.len());
1451 for arg in generic_args.args.iter().take(param_count) {
1452 match arg {
1453 GenericArg::Type(type_ref) => {
1454 let ty = self.make_ty(type_ref);
1455 new_substs.push(ty);
1456 }
1457 }
1458 }
1459 let substs = method_ty.substs().unwrap_or_else(Substs::empty);
1460 let substs = substs.replace_tail(new_substs);
1461 method_ty.apply_substs(substs)
1462 } else {
1463 method_ty
1464 };
1465 let method_ty = self.insert_type_vars(method_ty); 1472 let method_ty = self.insert_type_vars(method_ty);
1466 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 1473 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
1467 Ty::FnPtr(sig) => { 1474 Ty::FnPtr(sig) => {
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap
index 294186b06..32f1fa108 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap
@@ -1,19 +1,19 @@
1--- 1---
2created: "2019-02-17T16:16:58.863630956Z" 2created: "2019-02-20T21:31:12.910924715Z"
3creator: [email protected] 3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs 4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result" 5expression: "&result"
6--- 6---
7[72; 154) '{ ...a.c; }': () 7[72; 154) '{ ...a.c; }': ()
8[82; 83) 'c': C 8[82; 83) 'c': C
9[86; 87) 'C': fn C(usize) -> C 9[86; 87) 'C': C(usize) -> C
10[86; 90) 'C(1)': C 10[86; 90) 'C(1)': C
11[88; 89) '1': usize 11[88; 89) '1': usize
12[96; 97) 'B': B 12[96; 97) 'B': B
13[107; 108) 'a': A 13[107; 108) 'a': A
14[114; 133) 'A { b:...C(1) }': A 14[114; 133) 'A { b:...C(1) }': A
15[121; 122) 'B': B 15[121; 122) 'B': B
16[127; 128) 'C': fn C(usize) -> C 16[127; 128) 'C': C(usize) -> C
17[127; 131) 'C(1)': C 17[127; 131) 'C(1)': C
18[129; 130) '1': usize 18[129; 130) '1': usize
19[139; 140) 'a': A 19[139; 140) 'a': A
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap
new file mode 100644
index 000000000..783795cfd
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap
@@ -0,0 +1,23 @@
1---
2created: "2019-02-20T21:31:12.911275141Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[77; 185) '{ ...one; }': ()
8[83; 84) 'A': A<i32>(T) -> A<T>
9[83; 88) 'A(42)': A<i32>
10[85; 87) '42': i32
11[94; 95) 'A': A<u128>(T) -> A<T>
12[94; 103) 'A(42u128)': A<u128>
13[96; 102) '42u128': u128
14[109; 113) 'Some': Some<&str>(T) -> Option<T>
15[109; 118) 'Some("x")': Option<&str>
16[114; 117) '"x"': &str
17[124; 136) 'Option::Some': Some<&str>(T) -> Option<T>
18[124; 141) 'Option...e("x")': Option<&str>
19[137; 140) '"x"': &str
20[147; 151) 'None': Option<[unknown]>
21[161; 162) 'x': Option<i64>
22[178; 182) 'None': Option<i64>
23
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 4ab442b8a..3affcb4fe 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -466,6 +466,27 @@ fn test(a1: A<u32>, i: i32) {
466} 466}
467 467
468#[test] 468#[test]
469fn infer_tuple_struct_generics() {
470 check_inference(
471 "infer_tuple_struct_generics",
472 r#"
473struct A<T>(T);
474enum Option<T> { Some(T), None };
475use Option::*;
476
477fn test() {
478 A(42);
479 A(42u128);
480 Some("x");
481 Option::Some("x");
482 None;
483 let x: Option<i64> = None;
484}
485"#,
486 );
487}
488
489#[test]
469fn infer_generics_in_patterns() { 490fn infer_generics_in_patterns() {
470 check_inference( 491 check_inference(
471 "infer_generics_in_patterns", 492 "infer_generics_in_patterns",