From e74d8f148b805f9f6cb1331d1a96f680948da399 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 19 May 2019 17:44:29 +0800 Subject: Add default type to GenericParam --- crates/ra_hir/src/generics.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index c29b96f50..a635c7184 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -5,7 +5,7 @@ use std::sync::Arc; -use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner}; +use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner, DefaultTypeParamOwner}; use crate::{ db::{ HirDatabase, DefDatabase}, @@ -18,6 +18,7 @@ pub struct GenericParam { // FIXME: give generic params proper IDs pub(crate) idx: u32, pub(crate) name: Name, + pub(crate) default: Option, } /// Data about the generic parameters of a function, struct, impl, etc. @@ -68,7 +69,11 @@ impl GenericParams { GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), GenericDef::Trait(it) => { // traits get the Self type as an implicit first type parameter - generics.params.push(GenericParam { idx: start, name: Name::self_type() }); + generics.params.push(GenericParam { + idx: start, + name: Name::self_type(), + default: None, + }); generics.fill(&*it.source(db).1, start + 1); } GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), @@ -90,7 +95,9 @@ impl GenericParams { fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { for (idx, type_param) in params.type_params().enumerate() { let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); - let param = GenericParam { idx: idx as u32 + start, name: name.clone() }; + let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); + + let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; self.params.push(param); let type_ref = TypeRef::Path(name.into()); -- cgit v1.2.3 From d4dc8794159fbee10fcfe78d5da3a7bf41d7f4f6 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 19 May 2019 21:08:16 +0800 Subject: Add infer for generic default type --- crates/ra_hir/src/db.rs | 5 +++- crates/ra_hir/src/ty.rs | 2 +- crates/ra_hir/src/ty/lower.rs | 59 +++++++++++++++++++++++++++++++++---------- crates/ra_hir/src/ty/tests.rs | 29 +++++++++++++++++++++ 4 files changed, 80 insertions(+), 15 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 8e827d4f5..bda02d3cc 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -11,7 +11,7 @@ use crate::{ DefWithBody, Trait, ids, nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, - ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor, GenericPredicate}, + ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor, GenericPredicate, Substs}, adt::{StructData, EnumData}, impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, generics::{GenericParams, GenericDef}, @@ -141,6 +141,9 @@ pub trait HirDatabase: DefDatabase { #[salsa::invoke(crate::ty::generic_predicates)] fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; + #[salsa::invoke(crate::ty::generic_defaults)] + fn generic_defaults(&self, def: GenericDef) -> Substs; + #[salsa::invoke(crate::expr::body_with_source_map_query)] fn body_with_source_map( &self, diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index cfe07156b..9a65bf567 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -19,7 +19,7 @@ use std::{fmt, mem}; use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; use display::{HirDisplay, HirFormatter}; -pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates}; +pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults}; pub(crate) use infer::{infer, InferenceResult, InferTy}; pub use lower::CallableDef; diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 09d26ce5a..b4496789b 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -18,7 +18,7 @@ use crate::{ nameres::Namespace, resolve::{Resolver, Resolution}, path::{PathSegment, GenericArg}, - generics::{GenericParams, HasGenericParams}, + generics::{HasGenericParams}, adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef} }; use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate}; @@ -120,15 +120,15 @@ impl Ty { segment: &PathSegment, resolved: TypableDef, ) -> Substs { - let def_generics = match resolved { - TypableDef::Function(func) => func.generic_params(db), - TypableDef::Struct(s) => s.generic_params(db), - TypableDef::Enum(e) => e.generic_params(db), - TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), - TypableDef::TypeAlias(t) => t.generic_params(db), - TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), + let def_generic: Option = match resolved { + TypableDef::Function(func) => Some(func.into()), + TypableDef::Struct(s) => Some(s.into()), + TypableDef::Enum(e) => Some(e.into()), + TypableDef::EnumVariant(var) => Some(var.parent_enum(db).into()), + TypableDef::TypeAlias(t) => Some(t.into()), + TypableDef::Const(_) | TypableDef::Static(_) => None, }; - substs_from_path_segment(db, resolver, segment, &def_generics, false) + substs_from_path_segment(db, resolver, segment, def_generic, false) } /// Collect generic arguments from a path into a `Substs`. See also @@ -172,10 +172,12 @@ pub(super) fn substs_from_path_segment( db: &impl HirDatabase, resolver: &Resolver, segment: &PathSegment, - def_generics: &GenericParams, + def_generic: Option, add_self_param: bool, ) -> Substs { let mut substs = Vec::new(); + let def_generics = def_generic.map(|def| def.generic_params(db)).unwrap_or_default(); + let parent_param_count = def_generics.count_parent_params(); substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); if add_self_param { @@ -199,13 +201,28 @@ pub(super) fn substs_from_path_segment( } } // add placeholders for args that were not provided - // FIXME: handle defaults let supplied_params = substs.len(); for _ in supplied_params..def_generics.count_params_including_parent() { substs.push(Ty::Unknown); } assert_eq!(substs.len(), def_generics.count_params_including_parent()); - Substs(substs.into()) + let mut substs = Substs(substs.into()); + + // handle defaults + if let Some(def_generic) = def_generic { + let default_substs = db.generic_defaults(def_generic); + assert_eq!(substs.len(), default_substs.len()); + + let mut i = 0; + substs.walk_mut(&mut |ty| { + if *ty == Ty::Unknown { + *ty = default_substs[i].clone(); + } + i += 1; + }); + } + + substs } impl TraitRef { @@ -249,7 +266,7 @@ impl TraitRef { resolved: Trait, ) -> Substs { let segment = path.segments.last().expect("path should have at least one segment"); - substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) + substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) } pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { @@ -331,6 +348,22 @@ pub(crate) fn generic_predicates( predicates.into() } +/// Resolve the default type params from generics +pub(crate) fn generic_defaults(db: &impl HirDatabase, def: GenericDef) -> Substs { + let resolver = def.resolver(db); + let generic_params = def.generic_params(db); + + let defaults = generic_params + .params_including_parent() + .into_iter() + .map(|p| { + p.default.as_ref().map_or(Ty::Unknown, |path| Ty::from_hir_path(db, &resolver, path)) + }) + .collect::>(); + + Substs(defaults.into()) +} + fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { let signature = def.signature(db); let resolver = def.resolver(db); diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f8364203d..cd24faba5 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -1448,6 +1448,35 @@ fn test() { ); } +#[test] +fn infer_associated_method_generics_with_default_param() { + assert_snapshot_matches!( + infer(r#" +struct Gen { + val: T +} + +impl Gen { + pub fn make() -> Gen { + loop { } + } +} + +fn test() { + let a = Gen::make(); +} +"#), + @r###" +[80; 104) '{ ... }': ! +[90; 98) 'loop { }': ! +[95; 98) '{ }': () +[118; 146) '{ ...e(); }': () +[128; 129) 'a': Gen +[132; 141) 'Gen::make': fn make() -> Gen +[132; 143) 'Gen::make()': Gen"### + ); +} + #[test] fn infer_associated_method_generics_without_args() { assert_snapshot_matches!( -- cgit v1.2.3 From 3fc344b9f16ad481e87198da72052dd7ddfc88be Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 20 May 2019 17:48:58 +0800 Subject: Use normal iteration instead of walk_mut --- crates/ra_hir/src/ty/lower.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index b4496789b..8a8cc2a24 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -206,23 +206,20 @@ pub(super) fn substs_from_path_segment( substs.push(Ty::Unknown); } assert_eq!(substs.len(), def_generics.count_params_including_parent()); - let mut substs = Substs(substs.into()); // handle defaults if let Some(def_generic) = def_generic { let default_substs = db.generic_defaults(def_generic); assert_eq!(substs.len(), default_substs.len()); - let mut i = 0; - substs.walk_mut(&mut |ty| { - if *ty == Ty::Unknown { - *ty = default_substs[i].clone(); + for (i, default_ty) in default_substs.iter().enumerate() { + if substs[i] == Ty::Unknown { + substs[i] = default_ty.clone(); } - i += 1; - }); + } } - substs + Substs(substs.into()) } impl TraitRef { -- cgit v1.2.3