From e480d81988fc0c0e4f80f1c54058b95b9aaf1ebf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 1 Apr 2021 21:04:02 +0200 Subject: Introduce `GenericArg` like in Chalk Plus some more adaptations to Substitution. Lots of `assert_ty_ref` that we should revisit when introducing lifetime/const parameters. --- crates/hir_ty/src/infer/coerce.rs | 2 +- crates/hir_ty/src/infer/expr.rs | 24 ++++++++++------- crates/hir_ty/src/infer/pat.rs | 17 +++++++----- crates/hir_ty/src/infer/path.rs | 6 ++--- crates/hir_ty/src/infer/unify.rs | 55 +++++++++++++++++++++------------------ 5 files changed, 58 insertions(+), 46 deletions(-) (limited to 'crates/hir_ty/src/infer') diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 9c62932b1..8f7322b36 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs @@ -100,7 +100,7 @@ impl<'a> InferenceContext<'a> { }, (TyKind::Closure(.., substs), TyKind::Function { .. }) => { - from_ty = substs[0].clone(); + from_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone(); } _ => {} diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 25ab3ea4c..b99b6cd21 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -266,7 +266,7 @@ impl<'a> InferenceContext<'a> { let sig_ty = TyKind::Function(FnPointer { num_args: sig_tys.len() - 1, sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, - substs: Substitution(sig_tys.clone().into()), + substs: Substitution::from_iter(&Interner, sig_tys.clone()), }) .intern(&Interner); let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); @@ -406,7 +406,7 @@ impl<'a> InferenceContext<'a> { self.unify(&ty, &expected.ty); - let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); + let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); for field in fields.iter() { @@ -456,9 +456,13 @@ impl<'a> InferenceContext<'a> { .unwrap_or(true) }; match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) { - TyKind::Tuple(_, substs) => { - name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned()) - } + TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| { + substs + .interned(&Interner) + .get(idx) + .map(|a| a.assert_ty_ref(&Interner)) + .cloned() + }), TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { let local_id = self.db.struct_data(*s).variant_data.field(name)?; let field = FieldId { parent: (*s).into(), local_id }; @@ -635,7 +639,7 @@ impl<'a> InferenceContext<'a> { let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); match (range_type, lhs_ty, rhs_ty) { (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { - Some(adt) => Ty::adt_ty(adt, Substitution::empty()), + Some(adt) => Ty::adt_ty(adt, Substitution::empty(&Interner)), None => self.err_ty(), }, (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { @@ -694,8 +698,8 @@ impl<'a> InferenceContext<'a> { Expr::Tuple { exprs } => { let mut tys = match expected.ty.interned(&Interner) { TyKind::Tuple(_, substs) => substs - .iter() - .cloned() + .iter(&Interner) + .map(|a| a.assert_ty_ref(&Interner).clone()) .chain(repeat_with(|| self.table.new_type_var())) .take(exprs.len()) .collect::>(), @@ -706,7 +710,7 @@ impl<'a> InferenceContext<'a> { self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); } - TyKind::Tuple(tys.len(), Substitution(tys.into())).intern(&Interner) + TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner) } Expr::Array(array) => { let elem_ty = match expected.ty.interned(&Interner) { @@ -953,7 +957,7 @@ impl<'a> InferenceContext<'a> { substs.push(self.err_ty()); } assert_eq!(substs.len(), total_len); - Substitution(substs.into()) + Substitution::from_iter(&Interner, substs) } fn register_obligations_for_call(&mut self, callable_ty: &Ty) { diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 474363709..f1316415f 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -35,7 +35,7 @@ impl<'a> InferenceContext<'a> { } self.unify(&ty, expected); - let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); + let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); let (pre, post) = match ellipsis { @@ -74,7 +74,7 @@ impl<'a> InferenceContext<'a> { self.unify(&ty, expected); - let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); + let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); for subpat in subpats { @@ -134,7 +134,8 @@ impl<'a> InferenceContext<'a> { }; let n_uncovered_patterns = expectations.len().saturating_sub(args.len()); let err_ty = self.err_ty(); - let mut expectations_iter = expectations.iter().chain(repeat(&err_ty)); + let mut expectations_iter = + expectations.iter().map(|a| a.assert_ty_ref(&Interner)).chain(repeat(&err_ty)); let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm); let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len()); @@ -142,7 +143,8 @@ impl<'a> InferenceContext<'a> { inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned()); inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat)); - TyKind::Tuple(inner_tys.len(), Substitution(inner_tys.into())).intern(&Interner) + TyKind::Tuple(inner_tys.len(), Substitution::from_iter(&Interner, inner_tys)) + .intern(&Interner) } Pat::Or(ref pats) => { if let Some((first_pat, rest)) = pats.split_first() { @@ -236,9 +238,10 @@ impl<'a> InferenceContext<'a> { Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { let (inner_ty, alloc_ty) = match expected.as_adt() { - Some((adt, subst)) if adt == box_adt => { - (subst[0].clone(), subst.get(1).cloned()) - } + Some((adt, subst)) if adt == box_adt => ( + subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(), + subst.interned(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()), + ), _ => (self.result.standard_types.unknown.clone(), None), }; diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 717738789..b96391776 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs @@ -97,12 +97,12 @@ impl<'a> InferenceContext<'a> { let ty = self.db.value_ty(typable); // self_subst is just for the parent - let parent_substs = self_subst.unwrap_or_else(Substitution::empty); + let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(&Interner)); let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); let substs = ctx.substs_from_path(path, typable, true); - let full_substs = Substitution::builder(substs.len()) + let full_substs = Substitution::builder(substs.len(&Interner)) .use_parent_substs(&parent_substs) - .fill(substs.0[parent_substs.len()..].iter().cloned()) + .fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned()) .build(); let ty = ty.subst(&full_substs); Some(ty) diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 5ea4b7481..0efc62e53 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs @@ -129,29 +129,28 @@ impl Canonicalized { solution: Canonical, ) { // the solution may contain new variables, which we need to convert to new inference vars - let new_vars = Substitution( - solution - .binders - .iter(&Interner) - .map(|k| match k.kind { - VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), - VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), - VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), - // HACK: Chalk can sometimes return new lifetime variables. We - // want to just skip them, but to not mess up the indices of - // other variables, we'll just create a new type variable in - // their place instead. This should not matter (we never see the - // actual *uses* of the lifetime variable). - VariableKind::Lifetime => ctx.table.new_type_var(), - _ => panic!("const variable in solution"), - }) - .collect(), + let new_vars = Substitution::from_iter( + &Interner, + solution.binders.iter(&Interner).map(|k| match k.kind { + VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), + VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), + VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), + // HACK: Chalk can sometimes return new lifetime variables. We + // want to just skip them, but to not mess up the indices of + // other variables, we'll just create a new type variable in + // their place instead. This should not matter (we never see the + // actual *uses* of the lifetime variable). + VariableKind::Lifetime => ctx.table.new_type_var(), + _ => panic!("const variable in solution"), + }), ); - for (i, ty) in solution.value.into_iter().enumerate() { + for (i, ty) in solution.value.iter(&Interner).enumerate() { let (v, k) = self.free_vars[i]; // eagerly replace projections in the type; we may be getting types // e.g. from where clauses where this hasn't happened yet - let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); + let ty = ctx.normalize_associated_types_in( + ty.assert_ty_ref(&Interner).clone().subst_bound_vars(&new_vars), + ); ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty); } } @@ -163,13 +162,13 @@ pub fn could_unify(t1: &Ty, t2: &Ty) -> bool { pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option { let mut table = InferenceTable::new(); - let vars = Substitution( + let vars = Substitution::from_iter( + &Interner, tys.binders .iter(&Interner) // we always use type vars here because we want everything to // fallback to Unknown in the end (kind of hacky, as below) - .map(|_| table.new_type_var()) - .collect(), + .map(|_| table.new_type_var()), ); let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); @@ -178,7 +177,8 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option { } // default any type vars that weren't unified back to their original bound vars // (kind of hacky) - for (i, var) in vars.iter().enumerate() { + for (i, var) in vars.iter(&Interner).enumerate() { + let var = var.assert_ty_ref(&Interner); if &*table.resolve_ty_shallow(var) == var { table.unify( var, @@ -188,7 +188,10 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option { } Some( Substitution::builder(tys.binders.len(&Interner)) - .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) + .fill( + vars.iter(&Interner) + .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())), + ) .build(), ) } @@ -284,7 +287,9 @@ impl InferenceTable { substs2: &Substitution, depth: usize, ) -> bool { - substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) + substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| { + self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth) + }) } fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { -- cgit v1.2.3