From 5c42c0851815fb33c723b5462e1e77010e517d6f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 12 Sep 2024 00:57:34 +0300 Subject: [PATCH] Fix inference of literals when the expectation is Castable I followed the compiler: https://github.com/rust-lang/rust/blob/5bce6d48ff09dcb2613278ec93013795718478ef/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs#L1560-L1579. --- crates/hir-ty/src/infer/expr.rs | 37 +++++++++++++++++-- crates/hir-ty/src/tests/coercion.rs | 4 +- crates/hir-ty/src/tests/simple.rs | 2 +- .../src/handlers/invalid_cast.rs | 17 +++++++-- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index b79aa89db4..a04e7b17ae 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -895,21 +895,52 @@ impl InferenceContext<'_> { TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty))) .intern(Interner) } - None => self.table.new_integer_var(), + None => { + let expected_ty = expected.to_option(&mut self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) { + Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty, + Some(TyKind::Scalar(Scalar::Char)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) + } + Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + } }, Literal::Uint(_v, ty) => match ty { Some(int_ty) => { TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty))) .intern(Interner) } - None => self.table.new_integer_var(), + None => { + let expected_ty = expected.to_option(&mut self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) { + Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty, + Some(TyKind::Scalar(Scalar::Char)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner)) + } + Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => { + Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner)) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.new_integer_var()) + } }, Literal::Float(_v, ty) => match ty { Some(float_ty) => { TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty))) .intern(Interner) } - None => self.table.new_float_var(), + None => { + let opt_ty = expected.to_option(&mut self.table).filter(|ty| { + matches!(ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + }); + opt_ty.unwrap_or_else(|| self.table.new_float_var()) + } }, }, Expr::Underscore => { diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index 908bbc248c..273571901a 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -49,7 +49,7 @@ fn let_stmt_coerce() { //- minicore: coerce_unsized fn test() { let x: &[isize] = &[1]; - // ^^^^ adjustments: Deref(None), Borrow(Ref('?3, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?2, Not)), Pointer(Unsize) let x: *const [isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) } @@ -148,7 +148,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref('?10, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 37280f81b8..0473ee02fa 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -917,7 +917,7 @@ fn test(a: A) { 278..279 'A': extern "rust-call" A(*mut i32) -> A 278..292 'A(0 as *mut _)': A 278..307 'A(0 as...B(a)))': &'? i32 - 280..281 '0': i32 + 280..281 '0': usize 280..291 '0 as *mut _': *mut i32 297..306 '&&B(B(a))': &'? &'? B>> 298..306 '&B(B(a))': &'? B>> diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs index 90527c578e..ad4baf5e3a 100644 --- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -441,16 +441,16 @@ fn main() { //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` let t: *mut (dyn Trait + 'static) = 0 as *mut _; - //^^^^^^^^^^^ error: cannot cast `i32` to a fat pointer `*mut _` + //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _` let mut fail: *const str = 0 as *const str; - //^^^^^^^^^^^^^^^ error: cannot cast `i32` to a fat pointer `*const str` + //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str` let mut fail2: *const str = 0isize as *const str; //^^^^^^^^^^^^^^^^^^^^ error: cannot cast `isize` to a fat pointer `*const str` } fn foo() { let s = 0 as *const T; - //^^^^^^^^^^^^^ error: cannot cast `i32` to a fat pointer `*const T` + //^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const T` } "#, &["E0308", "unused_variables"], @@ -1100,4 +1100,15 @@ where "#, ); } + + #[test] + fn cast_literal_to_char() { + check_diagnostics( + r#" +fn foo() { + 0 as char; +} + "#, + ); + } }