mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Extract coercion logic to InferenceTable
To make it accessible without an InferenceContext.
This commit is contained in:
parent
6a0b199c82
commit
6133e6a002
@ -22,6 +22,8 @@ use crate::{
|
|||||||
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
|
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::unify::InferenceTable;
|
||||||
|
|
||||||
pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
|
pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
|
||||||
|
|
||||||
/// Do not require any adjustments, i.e. coerce `x -> x`.
|
/// Do not require any adjustments, i.e. coerce `x -> x`.
|
||||||
@ -84,8 +86,8 @@ impl CoerceMany {
|
|||||||
};
|
};
|
||||||
if let Some(sig) = sig {
|
if let Some(sig) = sig {
|
||||||
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
|
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
|
||||||
let result1 = ctx.coerce_inner(self.expected_ty.clone(), &target_ty);
|
let result1 = ctx.table.coerce_inner(self.expected_ty.clone(), &target_ty);
|
||||||
let result2 = ctx.coerce_inner(expr_ty.clone(), &target_ty);
|
let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty);
|
||||||
if let (Ok(result1), Ok(result2)) = (result1, result2) {
|
if let (Ok(result1), Ok(result2)) = (result1, result2) {
|
||||||
ctx.table.register_infer_ok(result1);
|
ctx.table.register_infer_ok(result1);
|
||||||
ctx.table.register_infer_ok(result2);
|
ctx.table.register_infer_ok(result2);
|
||||||
@ -126,16 +128,31 @@ impl<'a> InferenceContext<'a> {
|
|||||||
expr: Option<ExprId>,
|
expr: Option<ExprId>,
|
||||||
from_ty: &Ty,
|
from_ty: &Ty,
|
||||||
to_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 from_ty = self.resolve_ty_shallow(from_ty);
|
||||||
let to_ty = self.resolve_ty_shallow(to_ty);
|
let to_ty = self.resolve_ty_shallow(to_ty);
|
||||||
match self.coerce_inner(from_ty, &to_ty) {
|
match self.coerce_inner(from_ty, &to_ty) {
|
||||||
Ok(InferOk { value: (adjustments, ty), goals }) => {
|
Ok(InferOk { value: (adjustments, ty), goals }) => {
|
||||||
if let Some(expr) = expr {
|
self.register_infer_ok(InferOk { value: (), goals });
|
||||||
self.write_expr_adj(expr, adjustments);
|
Ok((adjustments, ty))
|
||||||
}
|
|
||||||
self.table.register_infer_ok(InferOk { value: (), goals });
|
|
||||||
Ok(InferOk { value: ty, goals: Vec::new() })
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// FIXME deal with error
|
// FIXME deal with error
|
||||||
@ -154,7 +171,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
//
|
//
|
||||||
// here, we would coerce from `!` to `?T`.
|
// here, we would coerce from `!` to `?T`.
|
||||||
if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) {
|
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![]);
|
return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
|
||||||
}
|
}
|
||||||
@ -203,8 +220,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(Ty) -> Vec<Adjustment>,
|
F: FnOnce(Ty) -> Vec<Adjustment>,
|
||||||
{
|
{
|
||||||
self.table
|
self.try_unify(t1, t2)
|
||||||
.try_unify(t1, t2)
|
|
||||||
.and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals))
|
.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
|
// details of coercion errors though, so I think it's useful to leave
|
||||||
// the structure like it is.
|
// 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 first_error = None;
|
||||||
let mut found = None;
|
let mut found = None;
|
||||||
|
|
||||||
@ -317,7 +333,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let InferOk { value: ty, goals } = match found {
|
let InferOk { value: ty, goals } = match found {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
None => {
|
None => {
|
||||||
self.table.rollback_to(snapshot);
|
self.rollback_to(snapshot);
|
||||||
let err = first_error.expect("coerce_borrowed_pointer had no error");
|
let err = first_error.expect("coerce_borrowed_pointer had no error");
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
@ -513,7 +529,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let coerce_from =
|
let coerce_from =
|
||||||
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
|
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 =
|
let coerce_unsized_trait =
|
||||||
match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
|
match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
|
||||||
Some(LangItemTarget::TraitId(trait_)) => trait_,
|
Some(LangItemTarget::TraitId(trait_)) => trait_,
|
||||||
@ -546,7 +562,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
match solution {
|
match solution {
|
||||||
Solution::Unique(v) => {
|
Solution::Unique(v) => {
|
||||||
canonicalized.apply_solution(
|
canonicalized.apply_solution(
|
||||||
&mut self.table,
|
self,
|
||||||
Canonical {
|
Canonical {
|
||||||
binders: v.binders,
|
binders: v.binders,
|
||||||
// FIXME handle constraints
|
// FIXME handle constraints
|
||||||
@ -556,7 +572,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
}
|
}
|
||||||
Solution::Ambig(Guidance::Definite(subst)) => {
|
Solution::Ambig(Guidance::Definite(subst)) => {
|
||||||
// FIXME need to record an obligation here
|
// 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
|
// FIXME actually we maybe should also accept unknown guidance here
|
||||||
_ => return Err(TypeError),
|
_ => return Err(TypeError),
|
||||||
|
@ -67,7 +67,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let ty = self.infer_expr_inner(expr, expected);
|
let ty = self.infer_expr_inner(expr, expected);
|
||||||
if let Some(target) = expected.only_has_type(&mut self.table) {
|
if let Some(target) = expected.only_has_type(&mut self.table) {
|
||||||
match self.coerce(Some(expr), &ty, &target) {
|
match self.coerce(Some(expr), &ty, &target) {
|
||||||
Ok(res) => res.value,
|
Ok(res) => res,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.result
|
self.result
|
||||||
.type_mismatches
|
.type_mismatches
|
||||||
|
Loading…
Reference in New Issue
Block a user