From 180655077a4d582d49d4aa14bed67b382f336cf0 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 15 Apr 2019 02:26:21 +0800 Subject: Fix 1099 --- crates/ra_hir/src/ty/infer.rs | 51 ++++++++++++++++++++++++++++++++--- crates/ra_hir/src/ty/tests.rs | 63 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 651a78fe5..fe6553f79 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -459,6 +459,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; let remaining_index = remaining_index.unwrap_or(path.segments.len()); + let mut actual_def_ty: Option = None; // resolve intermediate segments for segment in &path.segments[remaining_index..] { @@ -468,9 +469,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let typable: Option = def.into(); let typable = typable?; - let substs = + let mut substs = Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable); - self.db.type_for_def(typable, Namespace::Types).subst(&substs) + + if remaining_index > 0 { + substs = Ty::substs_from_path_segment( + self.db, + &self.resolver, + &path.segments[remaining_index - 1], + typable, + ); + } + + let ty = self.db.type_for_def(typable, Namespace::Types); + ty.subst(&substs) } Resolution::LocalBinding(_) => { // can't have a local binding in an associated item path @@ -489,6 +501,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Attempt to find an impl_item for the type which has a name matching // the current segment log::debug!("looking for path segment: {:?}", segment); + actual_def_ty = Some(ty.clone()); + let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { let matching_def: Option = match item { crate::ImplItem::Method(func) => { @@ -528,9 +542,40 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Resolution::Def(def) => { let typable: Option = def.into(); let typable = typable?; + + let ty = self.db.type_for_def(typable, Namespace::Values); let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); - let ty = self.db.type_for_def(typable, Namespace::Values).subst(&substs); + let ty = ty.subst(&substs); let ty = self.insert_type_vars(ty); + + // plug the old parent_ty in + if let Some(actual_def_ty) = actual_def_ty { + if let crate::ModuleDef::Function(func) = def { + let gen = func.generic_params(self.db); + if let Some(target_ty) = func.impl_block(self.db) { + let target_ty = target_ty.target_ty(self.db); + let old_params = target_ty.substs().unwrap().clone(); + + let target_ty = target_ty.subst(&substs); + let target_ty = self.insert_type_vars(target_ty); + + if gen.count_parent_params() > 0 { + self.unify(&target_ty, &actual_def_ty); + + if let Ty::Apply(ty) = &ty { + for (param, pty) in + old_params.iter().zip(target_ty.substs().unwrap().iter()) + { + if let Ty::Param { idx, .. } = param { + self.unify(pty, &ty.parameters.0[*idx as usize]); + } + } + } + } + } + } + } + Some(ty) } Resolution::LocalBinding(pat) => { diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 82c4aeddb..8d8a0eaaa 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -1426,6 +1426,65 @@ fn test() { ); } +#[test] +fn infer_associated_method_generics_without_args() { + assert_snapshot_matches!( + infer(r#" +struct Gen { + val: T +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::::make(); +} +"#), + @r###" +[76; 100) '{ ... }': ! +[86; 94) 'loop { }': ! +[91; 94) '{ }': () +[114; 149) '{ ...e(); }': () +[124; 125) 'a': Gen +[128; 144) 'Gen::<...::make': fn make() -> Gen +[128; 146) 'Gen::<...make()': Gen"### + ); +} + +#[test] +fn infer_associated_method_generics_2_type_params_without_args() { + assert_snapshot_matches!( + infer(r#" +struct Gen { + val: T, + val2: U, +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::::make(); +} +"#), + @r###" +[102; 126) '{ ... }': ! +[112; 120) 'loop { }': ! +[117; 120) '{ }': () +[140; 180) '{ ...e(); }': () +[150; 151) 'a': Gen +[154; 175) 'Gen::<...::make': fn make() -> Gen +[154; 177) 'Gen::<...make()': Gen"### + ); +} + #[test] fn infer_type_alias() { assert_snapshot_matches!( @@ -1814,8 +1873,8 @@ pub fn main_loop() { @r###" [144; 146) '{}': () [169; 198) '{ ...t(); }': () -[175; 193) 'FxHash...efault': fn default<{unknown}, {unknown}>() -> HashSet -[175; 195) 'FxHash...ault()': HashSet<{unknown}, {unknown}>"### +[175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet +[175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>"### ); } -- cgit v1.2.3 From 0edb5ce97a000c3da1e0eb1792d031d945ce5dba Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 15 Apr 2019 07:43:35 +0800 Subject: Bug fix and add more comments --- crates/ra_hir/src/ty/infer.rs | 82 +++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 22 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index fe6553f79..a3c4f1886 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -469,16 +469,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let typable: Option = def.into(); let typable = typable?; + // For example, this substs will take `Gen::make::**` let mut substs = Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable); if remaining_index > 0 { - substs = Ty::substs_from_path_segment( + // For example, this substs will take `Gen::**::make` + let parent_substs = Ty::substs_from_path_segment( self.db, &self.resolver, &path.segments[remaining_index - 1], typable, ); + + // merge parent and child substs + let max_len = std::cmp::max(substs.len(), parent_substs.len()); + let mut merged = vec![]; + for i in 0..max_len { + let s = match (substs.0.get(i), parent_substs.0.get(i)) { + (Some(s @ Ty::Apply(_)), _) => s, + (_, Some(s @ Ty::Apply(_))) => s, + (Some(s), _) => s, + (_, Some(s)) => s, + _ => unreachable!(), + }; + merged.push(s.clone()); + } + + substs = Substs(merged.into()); } let ty = self.db.type_for_def(typable, Namespace::Types); @@ -549,32 +567,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ty = self.insert_type_vars(ty); // plug the old parent_ty in - if let Some(actual_def_ty) = actual_def_ty { + let plug_self_types = || -> Option<()> { + let actual_def_ty = actual_def_ty?; + if let crate::ModuleDef::Function(func) = def { + // We only do the infer if parent has generic params let gen = func.generic_params(self.db); - if let Some(target_ty) = func.impl_block(self.db) { - let target_ty = target_ty.target_ty(self.db); - let old_params = target_ty.substs().unwrap().clone(); - - let target_ty = target_ty.subst(&substs); - let target_ty = self.insert_type_vars(target_ty); - - if gen.count_parent_params() > 0 { - self.unify(&target_ty, &actual_def_ty); - - if let Ty::Apply(ty) = &ty { - for (param, pty) in - old_params.iter().zip(target_ty.substs().unwrap().iter()) - { - if let Ty::Param { idx, .. } = param { - self.unify(pty, &ty.parameters.0[*idx as usize]); - } + if gen.count_parent_params() == 0 { + return None; + } + + let impl_block = func.impl_block(self.db)?; + let impl_block = impl_block.target_ty(self.db); + + // We save the impl block type params for later use + let old_params = impl_block.substs().unwrap().clone(); + + // Turn the impl block generic params to unknown + let mut subst = vec![]; + for _ in 0..impl_block.substs().map(|x| x.len()).unwrap_or(0) { + subst.push(Ty::Unknown); + } + let impl_block = impl_block.subst(&Substs(subst.into())); + let impl_block = self.insert_type_vars(impl_block); + + // Unify *self type* and impl_block + // e.g. Gen:: <=> Gen:: + self.unify(&impl_block, &actual_def_ty); + + // The following code *link up* the function parent generic param + // and the impl_block generic param by unify them one by one + if let Ty::Apply(ty) = &ty { + old_params.iter().zip(impl_block.substs()?.iter()).for_each( + |(param, pty)| { + if let Ty::Param { idx, .. } = param { + self.unify(pty, &ty.parameters.0[*idx as usize]); } - } - } + }, + ); } + + return Some(()); } - } + None + }; + + plug_self_types(); Some(ty) } -- cgit v1.2.3 From 039ab2e820defdee3b547c765739614ccbfd3c44 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 17 Apr 2019 01:47:59 +0800 Subject: Simpliy code --- crates/ra_hir/src/ty/infer.rs | 92 +++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 60 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index a3c4f1886..d426d275e 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -469,38 +469,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let typable: Option = def.into(); let typable = typable?; - // For example, this substs will take `Gen::make::**` - let mut substs = - Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable); + let mut ty = self.db.type_for_def(typable, Namespace::Types); if remaining_index > 0 { // For example, this substs will take `Gen::**::make` - let parent_substs = Ty::substs_from_path_segment( + let substs = Ty::substs_from_path_segment( self.db, &self.resolver, &path.segments[remaining_index - 1], typable, ); - // merge parent and child substs - let max_len = std::cmp::max(substs.len(), parent_substs.len()); - let mut merged = vec![]; - for i in 0..max_len { - let s = match (substs.0.get(i), parent_substs.0.get(i)) { - (Some(s @ Ty::Apply(_)), _) => s, - (_, Some(s @ Ty::Apply(_))) => s, - (Some(s), _) => s, - (_, Some(s)) => s, - _ => unreachable!(), - }; - merged.push(s.clone()); - } - - substs = Substs(merged.into()); + ty = ty.subst(&substs); } - let ty = self.db.type_for_def(typable, Namespace::Types); - ty.subst(&substs) + ty } Resolution::LocalBinding(_) => { // can't have a local binding in an associated item path @@ -558,16 +541,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match resolved { Resolution::Def(def) => { - let typable: Option = def.into(); - let typable = typable?; - - let ty = self.db.type_for_def(typable, Namespace::Values); - let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); - let ty = ty.subst(&substs); - let ty = self.insert_type_vars(ty); - - // plug the old parent_ty in - let plug_self_types = || -> Option<()> { + // Helpper function for finding self types + let find_self_types = || -> Option { let actual_def_ty = actual_def_ty?; if let crate::ModuleDef::Function(func) = def { @@ -577,43 +552,40 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { return None; } - let impl_block = func.impl_block(self.db)?; - let impl_block = impl_block.target_ty(self.db); + let impl_block = func.impl_block(self.db)?.target_ty(self.db); + let impl_block_substs = impl_block.substs()?; + let actual_substs = actual_def_ty.substs()?; - // We save the impl block type params for later use - let old_params = impl_block.substs().unwrap().clone(); + let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; - // Turn the impl block generic params to unknown - let mut subst = vec![]; - for _ in 0..impl_block.substs().map(|x| x.len()).unwrap_or(0) { - subst.push(Ty::Unknown); - } - let impl_block = impl_block.subst(&Substs(subst.into())); - let impl_block = self.insert_type_vars(impl_block); - - // Unify *self type* and impl_block - // e.g. Gen:: <=> Gen:: - self.unify(&impl_block, &actual_def_ty); - - // The following code *link up* the function parent generic param - // and the impl_block generic param by unify them one by one - if let Ty::Apply(ty) = &ty { - old_params.iter().zip(impl_block.substs()?.iter()).for_each( - |(param, pty)| { - if let Ty::Param { idx, .. } = param { - self.unify(pty, &ty.parameters.0[*idx as usize]); + // The following code *link up* the function actual parma type + // and impl_block type param index + impl_block_substs.iter().zip(actual_substs.iter()).for_each( + |(param, pty)| { + if let Ty::Param { idx, .. } = param { + if let Some(s) = new_substs.get_mut(*idx as usize) { + *s = pty.clone(); } - }, - ); - } + } + }, + ); - return Some(()); + Some(Substs(new_substs.into())) + } else { + None } - None }; - plug_self_types(); + let typable: Option = def.into(); + let typable = typable?; + let mut ty = self.db.type_for_def(typable, Namespace::Values); + if let Some(sts) = find_self_types() { + ty = ty.subst(&sts); + } + let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); + let ty = ty.subst(&substs); + let ty = self.insert_type_vars(ty); Some(ty) } Resolution::LocalBinding(pat) => { -- cgit v1.2.3 From 8747c903a2fd9b09e07b9d9a1310c7c3acc36e2f Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 17 Apr 2019 09:26:01 +0800 Subject: Refactoring --- crates/ra_hir/src/ty/infer.rs | 97 ++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 51 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index d426d275e..7ca1ff595 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -35,16 +35,17 @@ use crate::{ expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self}, generics::{GenericParams, HasGenericParams}, path::{GenericArgs, GenericArg}, + ModuleDef, adt::VariantDef, resolve::{Resolver, Resolution}, nameres::Namespace, + ty::infer::diagnostics::InferenceDiagnostic, diagnostics::DiagnosticSink, }; use super::{ Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, traits::{ Solution, Obligation, Guidance}, }; -use self::diagnostics::InferenceDiagnostic; /// The entry point of type inference. pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc { @@ -462,28 +463,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let mut actual_def_ty: Option = None; // resolve intermediate segments - for segment in &path.segments[remaining_index..] { + for (i, segment) in path.segments[remaining_index..].iter().enumerate() { let ty = match resolved { Resolution::Def(def) => { // FIXME resolve associated items from traits as well let typable: Option = def.into(); let typable = typable?; - let mut ty = self.db.type_for_def(typable, Namespace::Types); + let ty = self.db.type_for_def(typable, Namespace::Types); - if remaining_index > 0 { - // For example, this substs will take `Gen::**::make` - let substs = Ty::substs_from_path_segment( - self.db, - &self.resolver, - &path.segments[remaining_index - 1], - typable, - ); - - ty = ty.subst(&substs); - } + // For example, this substs will take `Gen::**::make` + assert!(remaining_index > 0); + let substs = Ty::substs_from_path_segment( + self.db, + &self.resolver, + &path.segments[remaining_index + i - 1], + typable, + ); - ty + ty.subst(&substs) } Resolution::LocalBinding(_) => { // can't have a local binding in an associated item path @@ -541,45 +539,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match resolved { Resolution::Def(def) => { - // Helpper function for finding self types - let find_self_types = || -> Option { - let actual_def_ty = actual_def_ty?; - - if let crate::ModuleDef::Function(func) = def { - // We only do the infer if parent has generic params - let gen = func.generic_params(self.db); - if gen.count_parent_params() == 0 { - return None; - } - - let impl_block = func.impl_block(self.db)?.target_ty(self.db); - let impl_block_substs = impl_block.substs()?; - let actual_substs = actual_def_ty.substs()?; - - let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; - - // The following code *link up* the function actual parma type - // and impl_block type param index - impl_block_substs.iter().zip(actual_substs.iter()).for_each( - |(param, pty)| { - if let Ty::Param { idx, .. } = param { - if let Some(s) = new_substs.get_mut(*idx as usize) { - *s = pty.clone(); - } - } - }, - ); - - Some(Substs(new_substs.into())) - } else { - None - } - }; - let typable: Option = def.into(); let typable = typable?; let mut ty = self.db.type_for_def(typable, Namespace::Values); - if let Some(sts) = find_self_types() { + if let Some(sts) = self.find_self_types(&def, actual_def_ty) { ty = ty.subst(&sts); } @@ -604,6 +567,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } + fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option) -> Option { + let actual_def_ty = actual_def_ty?; + + if let crate::ModuleDef::Function(func) = def { + // We only do the infer if parent has generic params + let gen = func.generic_params(self.db); + if gen.count_parent_params() == 0 { + return None; + } + + let impl_block = func.impl_block(self.db)?.target_ty(self.db); + let impl_block_substs = impl_block.substs()?; + let actual_substs = actual_def_ty.substs()?; + + let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; + + // The following code *link up* the function actual parma type + // and impl_block type param index + impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { + if let Ty::Param { idx, .. } = param { + if let Some(s) = new_substs.get_mut(*idx as usize) { + *s = pty.clone(); + } + } + }); + + Some(Substs(new_substs.into())) + } else { + None + } + } + fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option) { let path = match path { Some(path) => path, -- cgit v1.2.3