diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-21 20:47:50 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-21 20:47:50 +0000 |
commit | bb665a70627cbc2f4fb930fefb04899941b6afa6 (patch) | |
tree | e63b8aa30ec149dbff97d5dbf45fed998fdaf744 | |
parent | 5100aeac429919d1758908efb2f9cbe0d02c7510 (diff) | |
parent | db9a5a9ac047ed13aebd136edaabd4309f442e99 (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.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 21 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 17 |
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 | ||
721 | fn make_substs(generics: &GenericParams) -> Substs { | 713 | fn 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 | ||
739 | pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | 733 | fn 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 | --- |
2 | created: "2019-02-17T16:16:58.863630956Z" | 2 | created: "2019-02-20T21:31:12.910924715Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_hir/src/ty/tests.rs | 4 | source: crates/ra_hir/src/ty/tests.rs |
5 | expression: "&result" | 5 | expression: "&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 | --- | ||
2 | created: "2019-02-20T21:31:12.911275141Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&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] |
469 | fn infer_tuple_struct_generics() { | ||
470 | check_inference( | ||
471 | "infer_tuple_struct_generics", | ||
472 | r#" | ||
473 | struct A<T>(T); | ||
474 | enum Option<T> { Some(T), None }; | ||
475 | use Option::*; | ||
476 | |||
477 | fn 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] | ||
469 | fn infer_generics_in_patterns() { | 490 | fn 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(); |