Extract coercion logic to InferenceTable

To make it accessible without an InferenceContext.
This commit is contained in:
Florian Diebold 2022-03-20 13:42:47 +01:00
parent 6a0b199c82
commit 6133e6a002
2 changed files with 34 additions and 18 deletions

View file

@ -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),

View file

@ -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