diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/generics.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 83 | ||||
-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, 122 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 | ||
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,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 | --- |
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(); |