From 72712b8a428e17d63c413522c770e8f1f0587455 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 20 Feb 2019 22:36:54 +0100 Subject: Fix handling of generics in tuple variants and refactor a bit Also make them display a tiny bit nicer. Fixes #860. --- crates/ra_hir/src/ty.rs | 83 +++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 38 deletions(-) (limited to 'crates/ra_hir/src/ty.rs') diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d4d896673..7f28a6edd 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) -> 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). @@ -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::>(); - 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::>() .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,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } + fn substs_for_method_call( + &mut self, + def_generics: Option>, + generic_args: &Option, + ) -> 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); + } + 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 +1467,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) => { -- cgit v1.2.3 From db9a5a9ac047ed13aebd136edaabd4309f442e99 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 21 Feb 2019 21:25:27 +0100 Subject: Add an assert (and fix the other) --- crates/ra_hir/src/ty.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir/src/ty.rs') diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 7f28a6edd..1a3e1994f 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -443,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()) } @@ -1374,6 +1374,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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()) } -- cgit v1.2.3