mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +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))
|
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
|
// There should be no inference vars in types passed here
|
||||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||||
let environment = self.env.clone();
|
let environment = self.env.clone();
|
||||||
|
@ -3238,7 +3238,12 @@ impl Type {
|
||||||
|
|
||||||
pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
|
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()));
|
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
|
// https://github.com/rust-lang/rust/issues/57411
|
||||||
#[allow(unreachable_pub)]
|
#[allow(unreachable_pub)]
|
||||||
pub use unify::could_unify;
|
pub use unify::could_unify;
|
||||||
|
pub use coerce::could_coerce;
|
||||||
|
|
||||||
pub(crate) mod unify;
|
pub(crate) mod unify;
|
||||||
mod path;
|
mod path;
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
|
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
|
||||||
//! `librustc_typeck/check/coercion.rs`.
|
//! `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 hir_def::{expr::ExprId, lang_item::LangItemTarget};
|
||||||
use stdx::always;
|
use stdx::always;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||||
PointerCast, TypeError, TypeMismatch,
|
PointerCast, TypeError, TypeMismatch,
|
||||||
},
|
},
|
||||||
static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner,
|
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;
|
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> {
|
impl<'a> InferenceContext<'a> {
|
||||||
/// Unify two types, but may coerce the first one to the second one
|
/// Unify two types, but may coerce the first one to the second one
|
||||||
/// using "implicit coercion rules" if needed.
|
/// using "implicit coercion rules" if needed.
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
|
||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
|
cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
|
||||||
TyVariableKind, UniverseIndex,
|
TyVariableKind, UniverseIndex, CanonicalVarKind,
|
||||||
};
|
};
|
||||||
use chalk_solve::infer::ParameterEnaVariableExt;
|
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||||
use ena::unify::UnifyKey;
|
use ena::unify::UnifyKey;
|
||||||
|
@ -299,11 +299,25 @@ impl<'a> InferenceTable<'a> {
|
||||||
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
|
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
|
pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T::Result
|
||||||
where
|
where
|
||||||
T: HasInterner<Interner = Interner> + Fold<Interner> + std::fmt::Debug,
|
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>(
|
fn resolve_with_fallback_inner<T>(
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub use autoderef::autoderef;
|
||||||
pub use builder::{ParamKind, TyBuilder};
|
pub use builder::{ParamKind, TyBuilder};
|
||||||
pub use chalk_ext::*;
|
pub use chalk_ext::*;
|
||||||
pub use infer::{
|
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 interner::Interner;
|
||||||
pub use lower::{
|
pub use lower::{
|
||||||
|
|
Loading…
Reference in a new issue