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.rs46
1 files changed, 46 insertions, 0 deletions
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
new file mode 100644
index 0000000000..9e1c74b16f
--- /dev/null
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -0,0 +1,46 @@
+//! Type cast logic. Basically coercion + additional casts.
+
+use crate::{infer::unify::InferenceTable, Interner, Ty, TyExt, TyKind};
+
+#[derive(Clone, Debug)]
+pub(super) struct CastCheck {
+ expr_ty: Ty,
+ cast_ty: Ty,
+}
+
+impl CastCheck {
+ pub(super) fn new(expr_ty: Ty, cast_ty: Ty) -> Self {
+ Self { expr_ty, cast_ty }
+ }
+
+ pub(super) fn check(self, table: &mut InferenceTable<'_>) {
+ // FIXME: This function currently only implements the bits that influence the type
+ // inference. We should return the adjustments on success and report diagnostics on error.
+ let expr_ty = table.resolve_ty_shallow(&self.expr_ty);
+ let cast_ty = table.resolve_ty_shallow(&self.cast_ty);
+
+ if expr_ty.contains_unknown() || cast_ty.contains_unknown() {
+ return;
+ }
+
+ if table.coerce(&expr_ty, &cast_ty).is_ok() {
+ return;
+ }
+
+ if check_ref_to_ptr_cast(expr_ty, cast_ty, table) {
+ // Note that this type of cast is actually split into a coercion to a
+ // pointer type and a cast:
+ // &[T; N] -> *[T; N] -> *T
+ return;
+ }
+
+ // FIXME: Check other kinds of non-coercion casts and report error if any?
+ }
+}
+
+fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool {
+ let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; };
+ let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; };
+ let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; };
+ table.coerce(expr_elt_ty, cast_inner_ty).is_ok()
+}