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) | |
| download | rust-bb665a70627cbc2f4fb930fefb04899941b6afa6.tar.gz rust-bb665a70627cbc2f4fb930fefb04899941b6afa6.zip | |
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 <flodiebold@gmail.com> Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
| -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 fcc5133535d..c494beeb012 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -87,4 +87,17 @@ impl GenericParams { let parent_count = self.count_parent_params(); parent_count + self.params.len() } + + fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) { + if let Some(parent) = &self.parent_params { + parent.for_each_param(f); + } + self.params.iter().for_each(f); + } + + pub fn params_including_parent(&self) -> Vec<&GenericParam> { + let mut vec = Vec::with_capacity(self.count_params_including_parent()); + self.for_each_param(&mut |p| vec.push(p)); + vec + } } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d4d8966732a..1a3e1994fe4 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -40,7 +40,7 @@ use crate::{ name::KnownName, expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, generics::GenericParams, - path::GenericArg, + path::{ GenericArgs, GenericArg}, adt::VariantDef, resolve::{Resolver, Resolution}, nameres::Namespace }; @@ -165,17 +165,6 @@ impl Substs { pub fn empty() -> Substs { Substs(Arc::new([])) } - - /// Replaces the end of the substitutions by other ones. - pub(crate) fn replace_tail(self, replace_by: Vec<Ty>) -> Substs { - // again missing Arc::make_mut_slice... - let len = replace_by.len().min(self.0.len()); - let parent_len = self.0.len() - len; - let mut result = Vec::with_capacity(parent_len + len); - result.extend(self.0.iter().take(parent_len).cloned()); - result.extend(replace_by); - Substs(result.into()) - } } /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). @@ -454,7 +443,7 @@ impl Ty { for _ in supplied_params..def_generics.count_params_including_parent() { substs.push(Ty::Unknown); } - assert_eq!(substs.len(), def_generics.params.len()); + assert_eq!(substs.len(), def_generics.count_params_including_parent()); Substs(substs.into()) } @@ -639,8 +628,11 @@ impl fmt::Display for Ty { join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?; write!(f, " -> {}", sig.output) } - Ty::FnDef { name, substs, sig, .. } => { - write!(f, "fn {}", name)?; + Ty::FnDef { def, name, substs, sig, .. } => { + match def { + CallableDef::Function(_) => write!(f, "fn {}", name)?, + CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, + } if substs.0.len() > 0 { join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; } @@ -712,16 +704,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> .iter() .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) .collect::<Vec<_>>(); - let output = type_for_enum(db, def.parent_enum(db)); - let sig = Arc::new(FnSig { input, output }); let substs = make_substs(&generics); + let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone()); + let sig = Arc::new(FnSig { input, output }); Ty::FnDef { def: def.into(), sig, name, substs } } fn make_substs(generics: &GenericParams) -> Substs { Substs( - (0..generics.count_params_including_parent()) - .map(|_p| Ty::Unknown) + generics + .params_including_parent() + .into_iter() + .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) .collect::<Vec<_>>() .into(), ) @@ -736,7 +730,7 @@ fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { } } -pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { +fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { let generics = s.generic_params(db); Ty::Adt { def_id: s.into(), @@ -1353,6 +1347,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } + fn substs_for_method_call( + &mut self, + def_generics: Option<Arc<GenericParams>>, + generic_args: &Option<GenericArgs>, + ) -> Substs { + let (parent_param_count, param_count) = + def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); + let mut substs = Vec::with_capacity(parent_param_count + param_count); + for _ in 0..parent_param_count { + substs.push(Ty::Unknown); + } + // handle provided type arguments + if let Some(generic_args) = generic_args { + // if args are provided, it should be all of them, but we can't rely on that + for arg in generic_args.args.iter().take(param_count) { + match arg { + GenericArg::Type(type_ref) => { + let ty = self.make_ty(type_ref); + substs.push(ty); + } + } + } + }; + let supplied_params = substs.len(); + for _ in supplied_params..parent_param_count + param_count { + substs.push(Ty::Unknown); + } + assert_eq!(substs.len(), parent_param_count + param_count); + Substs(substs.into()) + } + fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem let ty = match &body[tgt_expr] { @@ -1443,25 +1468,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } None => (Ty::Unknown, receiver_ty, None), }; - // handle provided type arguments - let method_ty = if let Some(generic_args) = generic_args { - // if args are provided, it should be all of them, but we can't rely on that - let param_count = def_generics.map(|g| g.params.len()).unwrap_or(0); - let mut new_substs = Vec::with_capacity(generic_args.args.len()); - for arg in generic_args.args.iter().take(param_count) { - match arg { - GenericArg::Type(type_ref) => { - let ty = self.make_ty(type_ref); - new_substs.push(ty); - } - } - } - let substs = method_ty.substs().unwrap_or_else(Substs::empty); - let substs = substs.replace_tail(new_substs); - method_ty.apply_substs(substs) - } else { - method_ty - }; + let substs = self.substs_for_method_call(def_generics, generic_args); + let method_ty = method_ty.apply_substs(substs); let method_ty = self.insert_type_vars(method_ty); let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 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 294186b0657..32f1fa10806 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 @@ --- -created: "2019-02-17T16:16:58.863630956Z" +created: "2019-02-20T21:31:12.910924715Z" creator: insta@0.6.2 source: crates/ra_hir/src/ty/tests.rs expression: "&result" --- [72; 154) '{ ...a.c; }': () [82; 83) 'c': C -[86; 87) 'C': fn C(usize) -> C +[86; 87) 'C': C(usize) -> C [86; 90) 'C(1)': C [88; 89) '1': usize [96; 97) 'B': B [107; 108) 'a': A [114; 133) 'A { b:...C(1) }': A [121; 122) 'B': B -[127; 128) 'C': fn C(usize) -> C +[127; 128) 'C': C(usize) -> C [127; 131) 'C(1)': C [129; 130) '1': usize [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 00000000000..783795cfdd7 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_tuple_struct_generics.snap @@ -0,0 +1,23 @@ +--- +created: "2019-02-20T21:31:12.911275141Z" +creator: insta@0.6.2 +source: crates/ra_hir/src/ty/tests.rs +expression: "&result" +--- +[77; 185) '{ ...one; }': () +[83; 84) 'A': A<i32>(T) -> A<T> +[83; 88) 'A(42)': A<i32> +[85; 87) '42': i32 +[94; 95) 'A': A<u128>(T) -> A<T> +[94; 103) 'A(42u128)': A<u128> +[96; 102) '42u128': u128 +[109; 113) 'Some': Some<&str>(T) -> Option<T> +[109; 118) 'Some("x")': Option<&str> +[114; 117) '"x"': &str +[124; 136) 'Option::Some': Some<&str>(T) -> Option<T> +[124; 141) 'Option...e("x")': Option<&str> +[137; 140) '"x"': &str +[147; 151) 'None': Option<[unknown]> +[161; 162) 'x': Option<i64> +[178; 182) 'None': Option<i64> + diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 4ab442b8a4d..3affcb4fe32 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) { } #[test] +fn infer_tuple_struct_generics() { + check_inference( + "infer_tuple_struct_generics", + r#" +struct A<T>(T); +enum Option<T> { Some(T), None }; +use Option::*; + +fn test() { + A(42); + A(42u128); + Some("x"); + Option::Some("x"); + None; + let x: Option<i64> = None; +} +"#, + ); +} + +#[test] fn infer_generics_in_patterns() { check_inference( "infer_generics_in_patterns", diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 0888ab6de6a..a41c4e546d8 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -164,6 +164,23 @@ mod tests { } #[test] + fn hover_some() { + let (analysis, position) = single_file_with_position( + " + enum Option<T> { Some(T) } + use Option::Some; + + fn main() { + So<|>me(12); + } + ", + ); + let hover = analysis.hover(position).unwrap().unwrap(); + // not the nicest way to show it currently + assert_eq!(hover.info, "Some<i32>(T) -> Option<T>"); + } + + #[test] fn hover_for_local_variable() { let (analysis, position) = single_file_with_position("fn func(foo: i32) { fo<|>o; }"); let hover = analysis.hover(position).unwrap().unwrap(); |
