1145: Fix #1099, plug self type type parameters in infer_path_expr r=flodiebold a=edwin0cheng

As discussed in #1099, this PR try to "plug" a `self type` type parameters in `infer_path_expr`.
All the cases in 1099 was fixed and tested.
And luckily, this PR fixed bug #1030 again and make the test output correct.





Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2019-04-17 11:03:34 +00:00
commit 4c8e6e89aa
2 changed files with 117 additions and 8 deletions

View File

@ -35,16 +35,17 @@
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<InferenceResult> {
@ -459,18 +460,28 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
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<Ty> = 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<TypableDef> = def.into();
let typable = typable?;
let substs =
Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable);
self.db.type_for_def(typable, Namespace::Types).subst(&substs)
let ty = self.db.type_for_def(typable, Namespace::Types);
// For example, this substs will take `Gen::*<u32>*::make`
assert!(remaining_index > 0);
let substs = Ty::substs_from_path_segment(
self.db,
&self.resolver,
&path.segments[remaining_index + i - 1],
typable,
);
ty.subst(&substs)
}
Resolution::LocalBinding(_) => {
// can't have a local binding in an associated item path
@ -489,6 +500,8 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
// 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<crate::ModuleDef> = match item {
crate::ImplItem::Method(func) => {
@ -528,8 +541,13 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
Resolution::Def(def) => {
let typable: Option<TypableDef> = def.into();
let typable = typable?;
let mut ty = self.db.type_for_def(typable, Namespace::Values);
if let Some(sts) = self.find_self_types(&def, actual_def_ty) {
ty = ty.subst(&sts);
}
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);
Some(ty)
}
@ -549,6 +567,38 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
}
}
fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option<Ty>) -> Option<Substs> {
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<VariantDef>) {
let path = match path {
Some(path) => path,

View File

@ -1426,6 +1426,65 @@ fn test() {
);
}
#[test]
fn infer_associated_method_generics_without_args() {
assert_snapshot_matches!(
infer(r#"
struct Gen<T> {
val: T
}
impl<T> Gen<T> {
pub fn make() -> Gen<T> {
loop { }
}
}
fn test() {
let a = Gen::<u32>::make();
}
"#),
@r###"
[76; 100) '{ ... }': !
[86; 94) 'loop { }': !
[91; 94) '{ }': ()
[114; 149) '{ ...e(); }': ()
[124; 125) 'a': Gen<u32>
[128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T>
[128; 146) 'Gen::<...make()': Gen<u32>"###
);
}
#[test]
fn infer_associated_method_generics_2_type_params_without_args() {
assert_snapshot_matches!(
infer(r#"
struct Gen<T, U> {
val: T,
val2: U,
}
impl<T> Gen<u32, T> {
pub fn make() -> Gen<u32,T> {
loop { }
}
}
fn test() {
let a = Gen::<u32, u64>::make();
}
"#),
@r###"
[102; 126) '{ ... }': !
[112; 120) 'loop { }': !
[117; 120) '{ }': ()
[140; 180) '{ ...e(); }': ()
[150; 151) 'a': Gen<u32, u64>
[154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T>
[154; 177) 'Gen::<...make()': Gen<u32, u64>"###
);
}
#[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<T, H>
[175; 195) 'FxHash...ault()': HashSet<{unknown}, {unknown}>"###
[175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
[175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>"###
);
}