mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Expose coercion logic in hir API
This commit is contained in:
parent
6133e6a002
commit
2d30dd67d3
5 changed files with 67 additions and 8 deletions
|
@ -2900,7 +2900,7 @@ impl Type {
|
|||
self.autoderef_(db).map(move |ty| self.derived(ty))
|
||||
}
|
||||
|
||||
pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
|
||||
fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
|
||||
// There should be no inference vars in types passed here
|
||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||
let environment = self.env.clone();
|
||||
|
@ -3238,7 +3238,12 @@ impl Type {
|
|||
|
||||
pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
|
||||
let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
|
||||
could_unify(db, self.env.clone(), &tys)
|
||||
hir_ty::could_unify(db, self.env.clone(), &tys)
|
||||
}
|
||||
|
||||
pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
|
||||
let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
|
||||
hir_ty::could_coerce(db, self.env.clone(), &tys)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ use crate::{
|
|||
// https://github.com/rust-lang/rust/issues/57411
|
||||
#[allow(unreachable_pub)]
|
||||
pub use unify::could_unify;
|
||||
pub use coerce::could_coerce;
|
||||
|
||||
pub(crate) mod unify;
|
||||
mod path;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
|
||||
//! `librustc_typeck/check/coercion.rs`.
|
||||
|
||||
use std::iter;
|
||||
use std::{iter, sync::Arc};
|
||||
|
||||
use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind};
|
||||
use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind, BoundVar};
|
||||
use hir_def::{expr::ExprId, lang_item::LangItemTarget};
|
||||
use stdx::always;
|
||||
use syntax::SmolStr;
|
||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||
PointerCast, TypeError, TypeMismatch,
|
||||
},
|
||||
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner,
|
||||
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
|
||||
Solution, Substitution, Ty, TyBuilder, TyExt, TyKind, db::HirDatabase, TraitEnvironment, GenericArgData,
|
||||
};
|
||||
|
||||
use super::unify::InferenceTable;
|
||||
|
@ -120,6 +120,45 @@ impl CoerceMany {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn could_coerce(
|
||||
db: &dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
tys: &Canonical<(Ty, Ty)>,
|
||||
) -> bool {
|
||||
coerce(db, env, tys).is_ok()
|
||||
}
|
||||
|
||||
pub(crate) fn coerce(
|
||||
db: &dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
tys: &Canonical<(Ty, Ty)>,
|
||||
) -> Result<(Vec<Adjustment>, Ty), TypeError> {
|
||||
let mut table = InferenceTable::new(db, env);
|
||||
let vars = table.fresh_subst(tys.binders.as_slice(Interner));
|
||||
let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
|
||||
let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
|
||||
let (adjustments, ty) = table.coerce(&ty1_with_vars, &ty2_with_vars)?;
|
||||
// default any type vars that weren't unified back to their original bound vars
|
||||
// (kind of hacky)
|
||||
let find_var = |iv| {
|
||||
vars.iter(Interner).position(|v| match v.interned() {
|
||||
chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
|
||||
chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
|
||||
chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
|
||||
} == Some(iv))
|
||||
};
|
||||
let fallback = |iv, kind, default, binder| match kind {
|
||||
chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
|
||||
.map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
|
||||
chalk_ir::VariableKind::Lifetime => find_var(iv)
|
||||
.map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
|
||||
chalk_ir::VariableKind::Const(ty) => find_var(iv)
|
||||
.map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
|
||||
};
|
||||
// FIXME also map the types in the adjustments
|
||||
Ok((adjustments, table.resolve_with_fallback(ty, &fallback)))
|
||||
}
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
/// Unify two types, but may coerce the first one to the second one
|
||||
/// using "implicit coercion rules" if needed.
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
|
|||
|
||||
use chalk_ir::{
|
||||
cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
|
||||
TyVariableKind, UniverseIndex,
|
||||
TyVariableKind, UniverseIndex, CanonicalVarKind,
|
||||
};
|
||||
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||
use ena::unify::UnifyKey;
|
||||
|
@ -299,11 +299,25 @@ impl<'a> InferenceTable<'a> {
|
|||
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
|
||||
}
|
||||
|
||||
pub(crate) fn fresh_subst(
|
||||
&mut self,
|
||||
binders: &[CanonicalVarKind<Interner>],
|
||||
) -> Substitution {
|
||||
Substitution::from_iter(
|
||||
Interner,
|
||||
binders.iter().map(|kind| {
|
||||
let param_infer_var = kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
|
||||
param_infer_var.to_generic_arg(Interner)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T::Result
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + Fold<Interner> + std::fmt::Debug,
|
||||
{
|
||||
self.var_unification_table.instantiate_canonical(Interner, canonical)
|
||||
let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
|
||||
subst.apply(canonical.value, Interner)
|
||||
}
|
||||
|
||||
fn resolve_with_fallback_inner<T>(
|
||||
|
|
|
@ -51,7 +51,7 @@ pub use autoderef::autoderef;
|
|||
pub use builder::{ParamKind, TyBuilder};
|
||||
pub use chalk_ext::*;
|
||||
pub use infer::{
|
||||
could_unify, Adjust, Adjustment, AutoBorrow, InferenceDiagnostic, InferenceResult,
|
||||
could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, InferenceDiagnostic, InferenceResult,
|
||||
};
|
||||
pub use interner::Interner;
|
||||
pub use lower::{
|
||||
|
|
Loading…
Reference in a new issue