From 9339241b78ef7474e88de37738bdbece7767d333 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 9 Apr 2019 22:04:59 +0200 Subject: Some cleanup --- crates/ra_hir/src/ty/infer.rs | 189 ++++++++++++++++-------------- crates/ra_hir/src/ty/lower.rs | 7 +- crates/ra_hir/src/ty/method_resolution.rs | 13 +- 3 files changed, 111 insertions(+), 98 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 3dec5936a..b28bb47c6 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -461,6 +461,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for segment in &path.segments[remaining_index..] { let ty = match resolved { Resolution::Def(def) => { + // FIXME resolve associated items from traits as well let typable: Option = def.into(); let typable = typable?; @@ -750,12 +751,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn substs_for_method_call( &mut self, def_generics: Option>, - generic_args: &Option, + generic_args: Option<&GenericArgs>, receiver_ty: &Ty, ) -> Substs { let (parent_param_count, param_count) = def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); let mut substs = Vec::with_capacity(parent_param_count + param_count); + // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { for param in &parent_generics.params { if param.name.as_known_name() == Some(crate::KnownName::SelfType) { @@ -785,6 +787,100 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Substs(substs.into()) } + fn register_obligations_for_call(&mut self, callable_ty: &Ty) { + match callable_ty { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::FnDef(def) => { + // add obligation for trait implementation, if this is a trait method + // FIXME also register obligations from where clauses from the trait or impl and method + match def { + CallableDef::Function(f) => { + if let Some(trait_) = f.parent_trait(self.db) { + // construct a TraitDef + let substs = a_ty.parameters.prefix( + trait_.generic_params(self.db).count_params_including_parent(), + ); + self.obligations + .push(Obligation::Trait(TraitRef { trait_, substs })); + } + } + CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {} + } + } + _ => {} + }, + _ => {} + } + } + + fn infer_method_call( + &mut self, + tgt_expr: ExprId, + receiver: ExprId, + args: &[ExprId], + method_name: &Name, + generic_args: Option<&GenericArgs>, + ) -> Ty { + let receiver_ty = self.infer_expr(receiver, &Expectation::none()); + let resolved = receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); + let (derefed_receiver_ty, method_ty, def_generics) = match resolved { + Some((ty, func)) => { + self.write_method_resolution(tgt_expr, func); + ( + ty, + self.db.type_for_def(func.into(), Namespace::Values), + Some(func.generic_params(self.db)), + ) + } + None => (receiver_ty, Ty::Unknown, None), + }; + let substs = + self.substs_for_method_call(def_generics.clone(), generic_args, &derefed_receiver_ty); + let method_ty = method_ty.apply_substs(substs); + let method_ty = self.insert_type_vars(method_ty); + self.register_obligations_for_call(&method_ty); + let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::FnPtr => { + let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); + if !sig.params().is_empty() { + (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) + } else { + (Ty::Unknown, Vec::new(), sig.ret().clone()) + } + } + TypeCtor::FnDef(def) => { + let sig = self.db.callable_item_signature(def); + let ret_ty = sig.ret().clone().subst(&a_ty.parameters); + + if !sig.params().is_empty() { + let mut params_iter = + sig.params().iter().map(|ty| ty.clone().subst(&a_ty.parameters)); + let receiver_ty = params_iter.next().unwrap(); + (receiver_ty, params_iter.collect(), ret_ty) + } else { + (Ty::Unknown, Vec::new(), ret_ty) + } + } + _ => (Ty::Unknown, Vec::new(), Ty::Unknown), + }, + _ => (Ty::Unknown, Vec::new(), Ty::Unknown), + }; + // Apply autoref so the below unification works correctly + // FIXME: return correct autorefs from lookup_method + let actual_receiver_ty = match expected_receiver_ty.as_reference() { + Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty), + _ => derefed_receiver_ty, + }; + self.unify(&expected_receiver_ty, &actual_receiver_ty); + + let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); + for (arg, param) in args.iter().zip(param_iter) { + self.infer_expr(*arg, &Expectation::has_type(param)); + } + ret_ty + } + 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] { @@ -872,95 +968,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } ret_ty } - Expr::MethodCall { receiver, args, method_name, generic_args } => { - let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); - let resolved = - receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); - let (derefed_receiver_ty, method_ty, def_generics) = match resolved { - Some((ty, func)) => { - self.write_method_resolution(tgt_expr, func); - ( - ty, - self.db.type_for_def(func.into(), Namespace::Values), - Some(func.generic_params(self.db)), - ) - } - None => (receiver_ty, Ty::Unknown, None), - }; - let substs = self.substs_for_method_call( - def_generics.clone(), - generic_args, - &derefed_receiver_ty, - ); - 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::Apply(a_ty) => match a_ty.ctor { - TypeCtor::FnPtr => { - let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); - if !sig.params().is_empty() { - ( - sig.params()[0].clone(), - sig.params()[1..].to_vec(), - sig.ret().clone(), - ) - } else { - (Ty::Unknown, Vec::new(), sig.ret().clone()) - } - } - TypeCtor::FnDef(def) => { - let sig = self.db.callable_item_signature(def); - let ret_ty = sig.ret().clone().subst(&a_ty.parameters); - - // add obligation for trait implementation, if this is a trait method - // FIXME also register obligations from where clauses from the trait or impl and method - match def { - CallableDef::Function(f) => { - if let Some(trait_) = f.parent_trait(self.db) { - // construct a TraitDef - let substs = a_ty.parameters.prefix( - def_generics - .expect("trait parent should always have generics") - .count_parent_params(), - ); - self.obligations - .push(Obligation::Trait(TraitRef { trait_, substs })); - } - } - CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {} - } - - if !sig.params().is_empty() { - let mut params_iter = sig - .params() - .iter() - .map(|ty| ty.clone().subst(&a_ty.parameters)); - let receiver_ty = params_iter.next().unwrap(); - (receiver_ty, params_iter.collect(), ret_ty) - } else { - (Ty::Unknown, Vec::new(), ret_ty) - } - } - _ => (Ty::Unknown, Vec::new(), Ty::Unknown), - }, - _ => (Ty::Unknown, Vec::new(), Ty::Unknown), - }; - // Apply autoref so the below unification works correctly - // FIXME: return correct autorefs/derefs from lookup_method - let actual_receiver_ty = match expected_receiver_ty.as_reference() { - Some((_, mutability)) => { - Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty) - } - _ => derefed_receiver_ty, - }; - self.unify(&expected_receiver_ty, &actual_receiver_ty); - - let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); - for (arg, param) in args.iter().zip(param_iter) { - self.infer_expr(*arg, &Expectation::has_type(param)); - } - ret_ty - } + Expr::MethodCall { receiver, args, method_name, generic_args } => self + .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), Expr::Match { expr, arms } => { let expected = if expected.ty == Ty::Unknown { Expectation::has_type(self.new_type_var()) diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index ccacb5e73..bb8fdd8c7 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -5,6 +5,7 @@ //! - Building the type for an item: This happens through the `type_for_def` query. //! //! This usually involves resolving names, collecting generic arguments etc. +use std::iter; use crate::{ Function, Struct, StructField, Enum, EnumVariant, Path, @@ -172,16 +173,18 @@ pub(super) fn substs_from_path_segment( ) -> Substs { let mut substs = Vec::new(); let parent_param_count = def_generics.count_parent_params(); - substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); + substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); if add_self_param { // FIXME this add_self_param argument is kind of a hack: Traits have the // Self type as an implicit first type parameter, but it can't be // actually provided in the type arguments + // (well, actually sometimes it can, in the form of type-relative paths: `::default()`) substs.push(Ty::Unknown); } if let Some(generic_args) = &segment.args_and_bindings { // if args are provided, it should be all of them, but we can't rely on that - let param_count = def_generics.params.len(); + let self_param_correction = if add_self_param { 1 } else { 0 }; + let param_count = def_generics.params.len() - self_param_correction; for arg in generic_args.args.iter().take(param_count) { match arg { GenericArg::Type(type_ref) => { diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index f69b8304b..126edeaff 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -233,15 +233,16 @@ impl Ty { } } +/// This creates Substs for a trait with the given Self type and type variables +/// for all other parameters. This is kind of a hack since these aren't 'real' +/// type variables; the resulting trait reference is just used for the +/// preliminary method candidate check. fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { let mut substs = Vec::new(); - let mut counter = 0; let generics = tr.generic_params(db); substs.push(self_ty); - substs.extend(generics.params_including_parent().into_iter().skip(1).map(|_p| { - let fresh_var = Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(counter))); - counter += 1; - fresh_var - })); + substs.extend(generics.params_including_parent().into_iter().skip(1).enumerate().map( + |(i, _p)| Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(i as u32))), + )); substs.into() } -- cgit v1.2.3