mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
Extract coercion logic to InferenceTable
To make it accessible without an InferenceContext.
This commit is contained in:
parent
6a0b199c82
commit
6133e6a002
2 changed files with 34 additions and 18 deletions
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue