Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/cast.rs')
-rw-r--r--crates/hir-ty/src/infer/cast.rs156
1 files changed, 86 insertions, 70 deletions
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index bc3ee3c4c5..4cd6144a14 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -4,12 +4,14 @@ use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy};
use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags};
use stdx::never;
+use crate::infer::coerce::CoerceNever;
use crate::{
- Adjustment, Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex,
- QuantifiedWhereClauses, Ty, TyExt, TyKind, TypeFlags, WhereClause,
+ Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, QuantifiedWhereClauses, Ty,
+ TyExt, TyKind, TypeFlags, WhereClause,
db::HirDatabase,
from_chalk_trait_id,
- infer::{coerce::CoerceNever, unify::InferenceTable},
+ infer::{AllowTwoPhase, InferenceContext},
+ next_solver::mapping::ChalkToNextSolver,
};
#[derive(Debug)]
@@ -93,23 +95,25 @@ impl CastCheck {
Self { expr, source_expr, expr_ty, cast_ty }
}
- pub(super) fn check<F, G>(
+ pub(super) fn check(
&mut self,
- table: &mut InferenceTable<'_>,
- apply_adjustments: &mut F,
- set_coercion_cast: &mut G,
- ) -> Result<(), InferenceDiagnostic>
- where
- F: FnMut(ExprId, Vec<Adjustment>),
- G: FnMut(ExprId),
- {
- self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone());
- self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone());
+ ctx: &mut InferenceContext<'_>,
+ ) -> Result<(), InferenceDiagnostic> {
+ self.expr_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone());
+ self.cast_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone());
// This should always come first so that we apply the coercion, which impacts infer vars.
- if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty, CoerceNever::Yes) {
- apply_adjustments(self.source_expr, adj);
- set_coercion_cast(self.source_expr);
+ if ctx
+ .coerce(
+ self.source_expr.into(),
+ self.expr_ty.to_nextsolver(ctx.table.interner),
+ self.cast_ty.to_nextsolver(ctx.table.interner),
+ AllowTwoPhase::No,
+ CoerceNever::Yes,
+ )
+ .is_ok()
+ {
+ ctx.result.coercion_casts.insert(self.source_expr);
return Ok(());
}
@@ -118,7 +122,7 @@ impl CastCheck {
}
if !self.cast_ty.data(Interner).flags.contains(TypeFlags::HAS_TY_INFER)
- && !table.is_sized(&self.cast_ty)
+ && !ctx.table.is_sized(&self.cast_ty)
{
return Err(InferenceDiagnostic::CastToUnsized {
expr: self.expr,
@@ -133,30 +137,31 @@ impl CastCheck {
return Ok(());
}
- self.do_check(table, apply_adjustments)
+ self.do_check(ctx)
.map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone()))
}
- fn do_check<F>(
- &self,
- table: &mut InferenceTable<'_>,
- apply_adjustments: &mut F,
- ) -> Result<(), CastError>
- where
- F: FnMut(ExprId, Vec<Adjustment>),
- {
+ fn do_check(&self, ctx: &mut InferenceContext<'_>) -> Result<(), CastError> {
let (t_from, t_cast) = match (
- CastTy::from_ty(table.db, &self.expr_ty),
- CastTy::from_ty(table.db, &self.cast_ty),
+ CastTy::from_ty(ctx.db, &self.expr_ty),
+ CastTy::from_ty(ctx.db, &self.cast_ty),
) {
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
(None, Some(t_cast)) => match self.expr_ty.kind(Interner) {
TyKind::FnDef(..) => {
- let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig");
- let sig = table.eagerly_normalize_and_resolve_shallow_in(sig);
+ let sig = self.expr_ty.callable_sig(ctx.db).expect("FnDef had no sig");
+ let sig = ctx.table.eagerly_normalize_and_resolve_shallow_in(sig);
let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
- if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes) {
- apply_adjustments(self.source_expr, adj);
+ if ctx
+ .coerce(
+ self.source_expr.into(),
+ self.expr_ty.to_nextsolver(ctx.table.interner),
+ fn_ptr.to_nextsolver(ctx.table.interner),
+ AllowTwoPhase::No,
+ CoerceNever::Yes,
+ )
+ .is_ok()
+ {
} else {
return Err(CastError::IllegalCast);
}
@@ -176,11 +181,11 @@ impl CastCheck {
},
// array-ptr-cast
CastTy::Ptr(t, m) => {
- let t = table.eagerly_normalize_and_resolve_shallow_in(t);
- if !table.is_sized(&t) {
+ let t = ctx.table.eagerly_normalize_and_resolve_shallow_in(t);
+ if !ctx.table.is_sized(&t) {
return Err(CastError::IllegalCast);
}
- self.check_ref_cast(table, inner_ty, *mutbl, &t, m, apply_adjustments)
+ self.check_ref_cast(ctx, inner_ty, *mutbl, &t, m)
}
_ => Err(CastError::NonScalar),
};
@@ -202,12 +207,10 @@ impl CastCheck {
}
(CastTy::Int(Int::Bool | Int::CEnum | Int::Char) | CastTy::Float, CastTy::Ptr(..))
| (CastTy::Ptr(..) | CastTy::FnPtr, CastTy::Float) => Err(CastError::IllegalCast),
- (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => {
- self.check_ptr_ptr_cast(table, &src, &dst)
- }
- (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(table, &src),
- (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(table, &dst),
- (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(table, &dst),
+ (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => self.check_ptr_ptr_cast(ctx, &src, &dst),
+ (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(ctx, &src),
+ (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(ctx, &dst),
+ (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(ctx, &dst),
(CastTy::Int(Int::CEnum), CastTy::Int(_)) => Ok(()),
(CastTy::Int(Int::Char | Int::Bool), CastTy::Int(_)) => Ok(()),
(CastTy::Int(_) | CastTy::Float, CastTy::Int(_) | CastTy::Float) => Ok(()),
@@ -215,26 +218,30 @@ impl CastCheck {
}
}
- fn check_ref_cast<F>(
+ fn check_ref_cast(
&self,
- table: &mut InferenceTable<'_>,
+ ctx: &mut InferenceContext<'_>,
t_expr: &Ty,
m_expr: Mutability,
t_cast: &Ty,
m_cast: Mutability,
- apply_adjustments: &mut F,
- ) -> Result<(), CastError>
- where
- F: FnMut(ExprId, Vec<Adjustment>),
- {
+ ) -> Result<(), CastError> {
// Mutability order is opposite to rustc. `Mut < Not`
if m_expr <= m_cast
&& let TyKind::Array(ety, _) = t_expr.kind(Interner)
{
// Coerce to a raw pointer so that we generate RawPtr in MIR.
let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner);
- if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes) {
- apply_adjustments(self.source_expr, adj);
+ if ctx
+ .coerce(
+ self.source_expr.into(),
+ self.expr_ty.to_nextsolver(ctx.table.interner),
+ array_ptr_type.to_nextsolver(ctx.table.interner),
+ AllowTwoPhase::No,
+ CoerceNever::Yes,
+ )
+ .is_ok()
+ {
} else {
never!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
@@ -245,7 +252,16 @@ impl CastCheck {
// This is a less strict condition than rustc's `demand_eqtype`,
// but false negative is better than false positive
- if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() {
+ if ctx
+ .coerce(
+ self.source_expr.into(),
+ ety.to_nextsolver(ctx.table.interner),
+ t_cast.to_nextsolver(ctx.table.interner),
+ AllowTwoPhase::No,
+ CoerceNever::Yes,
+ )
+ .is_ok()
+ {
return Ok(());
}
}
@@ -255,12 +271,12 @@ impl CastCheck {
fn check_ptr_ptr_cast(
&self,
- table: &mut InferenceTable<'_>,
+ ctx: &mut InferenceContext<'_>,
src: &Ty,
dst: &Ty,
) -> Result<(), CastError> {
- let src_kind = pointer_kind(src, table).map_err(|_| CastError::Unknown)?;
- let dst_kind = pointer_kind(dst, table).map_err(|_| CastError::Unknown)?;
+ let src_kind = pointer_kind(src, ctx).map_err(|_| CastError::Unknown)?;
+ let dst_kind = pointer_kind(dst, ctx).map_err(|_| CastError::Unknown)?;
match (src_kind, dst_kind) {
(Some(PointerKind::Error), _) | (_, Some(PointerKind::Error)) => Ok(()),
@@ -285,9 +301,9 @@ impl CastCheck {
return Ok(());
}
let src_principal =
- table.db.trait_signature(from_chalk_trait_id(src_principal));
+ ctx.db.trait_signature(from_chalk_trait_id(src_principal));
let dst_principal =
- table.db.trait_signature(from_chalk_trait_id(dst_principal));
+ ctx.db.trait_signature(from_chalk_trait_id(dst_principal));
if src_principal.flags.contains(TraitFlags::AUTO)
&& dst_principal.flags.contains(TraitFlags::AUTO)
{
@@ -306,10 +322,10 @@ impl CastCheck {
fn check_ptr_addr_cast(
&self,
- table: &mut InferenceTable<'_>,
+ ctx: &mut InferenceContext<'_>,
expr_ty: &Ty,
) -> Result<(), CastError> {
- match pointer_kind(expr_ty, table).map_err(|_| CastError::Unknown)? {
+ match pointer_kind(expr_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownExprPtrKind),
None => Ok(()),
Some(PointerKind::Error) => Ok(()),
@@ -320,10 +336,10 @@ impl CastCheck {
fn check_addr_ptr_cast(
&self,
- table: &mut InferenceTable<'_>,
+ ctx: &mut InferenceContext<'_>,
cast_ty: &Ty,
) -> Result<(), CastError> {
- match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? {
+ match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownCastPtrKind),
None => Ok(()),
Some(PointerKind::Error) => Ok(()),
@@ -336,10 +352,10 @@ impl CastCheck {
fn check_fptr_ptr_cast(
&self,
- table: &mut InferenceTable<'_>,
+ ctx: &mut InferenceContext<'_>,
cast_ty: &Ty,
) -> Result<(), CastError> {
- match pointer_kind(cast_ty, table).map_err(|_| CastError::Unknown)? {
+ match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownCastPtrKind),
None => Ok(()),
Some(PointerKind::Error) => Ok(()),
@@ -362,10 +378,10 @@ enum PointerKind {
Error,
}
-fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<PointerKind>, ()> {
- let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone());
+fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result<Option<PointerKind>, ()> {
+ let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty.clone());
- if table.is_sized(&ty) {
+ if ctx.table.is_sized(&ty) {
return Ok(Some(PointerKind::Thin));
}
@@ -378,11 +394,11 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
return Err(());
};
- let struct_data = id.fields(table.db);
+ let struct_data = id.fields(ctx.db);
if let Some((last_field, _)) = struct_data.fields().iter().last() {
let last_field_ty =
- table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
- pointer_kind(&last_field_ty, table)
+ ctx.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
+ pointer_kind(&last_field_ty, ctx)
} else {
Ok(Some(PointerKind::Thin))
}
@@ -390,7 +406,7 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
TyKind::Tuple(_, subst) => {
match subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) {
None => Ok(Some(PointerKind::Thin)),
- Some(ty) => pointer_kind(ty, table),
+ Some(ty) => pointer_kind(ty, ctx),
}
}
TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)),