Unnamed repository; edit this file 'description' to name the repository.
Extract coercion logic to InferenceTable
To make it accessible without an InferenceContext.
Florian Diebold 2022-03-21
parent 6a0b199 · commit 6133e6a
-rw-r--r--crates/hir_ty/src/infer/coerce.rs50
-rw-r--r--crates/hir_ty/src/infer/expr.rs2
2 files changed, 34 insertions, 18 deletions
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 528e3ba882..1275d59673 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -22,6 +22,8 @@ use crate::{
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
};
+use super::unify::InferenceTable;
+
pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
/// Do not require any adjustments, i.e. coerce `x -> x`.
@@ -84,8 +86,8 @@ impl CoerceMany {
};
if let Some(sig) = sig {
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
- let result1 = ctx.coerce_inner(self.expected_ty.clone(), &target_ty);
- let result2 = ctx.coerce_inner(expr_ty.clone(), &target_ty);
+ let result1 = ctx.table.coerce_inner(self.expected_ty.clone(), &target_ty);
+ let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty);
if let (Ok(result1), Ok(result2)) = (result1, result2) {
ctx.table.register_infer_ok(result1);
ctx.table.register_infer_ok(result2);
@@ -126,16 +128,31 @@ impl<'a> InferenceContext<'a> {
expr: Option<ExprId>,
from_ty: &Ty,
to_ty: &Ty,
- ) -> InferResult<Ty> {
+ ) -> Result<Ty, TypeError> {
+ let from_ty = self.resolve_ty_shallow(from_ty);
+ let to_ty = self.resolve_ty_shallow(to_ty);
+ let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty)?;
+ if let Some(expr) = expr {
+ self.write_expr_adj(expr, adjustments);
+ }
+ Ok(ty)
+ }
+}
+
+impl<'a> InferenceTable<'a> {
+ /// Unify two types, but may coerce the first one to the second one
+ /// using "implicit coercion rules" if needed.
+ pub(crate) fn coerce(
+ &mut self,
+ from_ty: &Ty,
+ to_ty: &Ty,
+ ) -> Result<(Vec<Adjustment>, Ty), TypeError> {
let from_ty = self.resolve_ty_shallow(from_ty);
let to_ty = self.resolve_ty_shallow(to_ty);
match self.coerce_inner(from_ty, &to_ty) {
Ok(InferOk { value: (adjustments, ty), goals }) => {
- if let Some(expr) = expr {
- self.write_expr_adj(expr, adjustments);
- }
- self.table.register_infer_ok(InferOk { value: (), goals });
- Ok(InferOk { value: ty, goals: Vec::new() })
+ self.register_infer_ok(InferOk { value: (), goals });
+ Ok((adjustments, ty))
}
Err(e) => {
// FIXME deal with error
@@ -154,7 +171,7 @@ impl<'a> InferenceContext<'a> {
//
// here, we would coerce from `!` to `?T`.
if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) {
- self.table.set_diverging(*tv, true);
+ self.set_diverging(*tv, true);
}
return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
}
@@ -203,8 +220,7 @@ impl<'a> InferenceContext<'a> {
where
F: FnOnce(Ty) -> Vec<Adjustment>,
{
- self.table
- .try_unify(t1, t2)
+ self.try_unify(t1, t2)
.and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals))
}
@@ -259,9 +275,9 @@ impl<'a> InferenceContext<'a> {
// details of coercion errors though, so I think it's useful to leave
// the structure like it is.
- let snapshot = self.table.snapshot();
+ let snapshot = self.snapshot();
- let mut autoderef = Autoderef::new(&mut self.table, from_ty.clone());
+ let mut autoderef = Autoderef::new(self, from_ty.clone());
let mut first_error = None;
let mut found = None;
@@ -317,7 +333,7 @@ impl<'a> InferenceContext<'a> {
let InferOk { value: ty, goals } = match found {
Some(d) => d,
None => {
- self.table.rollback_to(snapshot);
+ self.rollback_to(snapshot);
let err = first_error.expect("coerce_borrowed_pointer had no error");
return Err(err);
}
@@ -513,7 +529,7 @@ impl<'a> InferenceContext<'a> {
let coerce_from =
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
- let krate = self.resolver.krate().unwrap();
+ let krate = self.trait_env.krate;
let coerce_unsized_trait =
match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
Some(LangItemTarget::TraitId(trait_)) => trait_,
@@ -546,7 +562,7 @@ impl<'a> InferenceContext<'a> {
match solution {
Solution::Unique(v) => {
canonicalized.apply_solution(
- &mut self.table,
+ self,
Canonical {
binders: v.binders,
// FIXME handle constraints
@@ -556,7 +572,7 @@ impl<'a> InferenceContext<'a> {
}
Solution::Ambig(Guidance::Definite(subst)) => {
// FIXME need to record an obligation here
- canonicalized.apply_solution(&mut self.table, subst)
+ canonicalized.apply_solution(self, subst)
}
// FIXME actually we maybe should also accept unknown guidance here
_ => return Err(TypeError),
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index ebbce33e01..be00d8ab37 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -67,7 +67,7 @@ impl<'a> InferenceContext<'a> {
let ty = self.infer_expr_inner(expr, expected);
if let Some(target) = expected.only_has_type(&mut self.table) {
match self.coerce(Some(expr), &ty, &target) {
- Ok(res) => res.value,
+ Ok(res) => res,
Err(_) => {
self.result
.type_mismatches