aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-21 20:47:50 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-21 20:47:50 +0000
commitbb665a70627cbc2f4fb930fefb04899941b6afa6 (patch)
treee63b8aa30ec149dbff97d5dbf45fed998fdaf744
parent5100aeac429919d1758908efb2f9cbe0d02c7510 (diff)
parentdb9a5a9ac047ed13aebd136edaabd4309f442e99 (diff)
Merge #864
864: Fix handling of generics in tuple variants and refactor a bit r=matklad a=flodiebold (The problem was that we created separate substitutions for the return value, so we lost the connection between the type arguments in the constructor call and the type arguments of the result.) Also make them display a tiny bit nicer. Fixes #860. Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_hir/src/generics.rs13
-rw-r--r--crates/ra_hir/src/ty.rs86
-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
-rw-r--r--crates/ra_ide_api/src/hover.rs17
6 files changed, 124 insertions, 42 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..1a3e1994f 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).
@@ -454,7 +443,7 @@ impl Ty {
454 for _ in supplied_params..def_generics.count_params_including_parent() { 443 for _ in supplied_params..def_generics.count_params_including_parent() {
455 substs.push(Ty::Unknown); 444 substs.push(Ty::Unknown);
456 } 445 }
457 assert_eq!(substs.len(), def_generics.params.len()); 446 assert_eq!(substs.len(), def_generics.count_params_including_parent());
458 Substs(substs.into()) 447 Substs(substs.into())
459 } 448 }
460 449
@@ -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,37 @@ 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 assert_eq!(substs.len(), parent_param_count + param_count);
1378 Substs(substs.into())
1379 }
1380
1356 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 1381 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
1357 let body = Arc::clone(&self.body); // avoid borrow checker problem 1382 let body = Arc::clone(&self.body); // avoid borrow checker problem
1358 let ty = match &body[tgt_expr] { 1383 let ty = match &body[tgt_expr] {
@@ -1443,25 +1468,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1443 } 1468 }
1444 None => (Ty::Unknown, receiver_ty, None), 1469 None => (Ty::Unknown, receiver_ty, None),
1445 }; 1470 };
1446 // handle provided type arguments 1471 let substs = self.substs_for_method_call(def_generics, generic_args);
1447 let method_ty = if let Some(generic_args) = generic_args { 1472 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); 1473 let method_ty = self.insert_type_vars(method_ty);
1466 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 1474 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
1467 Ty::FnPtr(sig) => { 1475 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",
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 0888ab6de..a41c4e546 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -164,6 +164,23 @@ mod tests {
164 } 164 }
165 165
166 #[test] 166 #[test]
167 fn hover_some() {
168 let (analysis, position) = single_file_with_position(
169 "
170 enum Option<T> { Some(T) }
171 use Option::Some;
172
173 fn main() {
174 So<|>me(12);
175 }
176 ",
177 );
178 let hover = analysis.hover(position).unwrap().unwrap();
179 // not the nicest way to show it currently
180 assert_eq!(hover.info, "Some<i32>(T) -> Option<T>");
181 }
182
183 #[test]
167 fn hover_for_local_variable() { 184 fn hover_for_local_variable() {
168 let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }"); 185 let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }");
169 let hover = analysis.hover(position).unwrap().unwrap(); 186 let hover = analysis.hover(position).unwrap().unwrap();