From 3a2ed8b640fb01f68ebcc1da648f76ace91fb790 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 6 Sep 2024 01:33:03 +0900 Subject: [PATCH 1/2] fix: Disable invalid cast diagnostics for casts like `&T as &dyn Trait` --- crates/hir-ty/src/infer/cast.rs | 23 +++++++++++++- .../src/handlers/invalid_cast.rs | 30 +++++++++++++------ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index ae914044368c..413112e34131 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs @@ -188,7 +188,28 @@ impl CastCheck { } _ => return Err(CastError::NonScalar), }, - _ => return Err(CastError::NonScalar), + _ => { + // We fail to coerce to dyn Trait sometimes due to lack of some functionalities + // under current chalk trait solver. (See #11847 and #18047) + // So, emit no diagnostic for casts like `&T as &dyn Trait` for now, + // to prevent false positive diagnositcs. + // Direct cast without ref like `T as dyn Trait` is prohibitied by + // `InferenceDiagnostic::CastToUnsized`, so allowing this diagnostics bypass + // only to `&T as &dyn Trait` is sufficient + if let (TyKind::Ref(m_expr, _, _), TyKind::Ref(m_cast, _, t_cast)) = + (self.expr_ty.kind(Interner), self.cast_ty.kind(Interner)) + { + // Refuse casting `&T` into `&mut U` + if m_expr > m_cast { + return Err(CastError::IllegalCast); + } + if matches!(table.resolve_ty_shallow(t_cast).kind(Interner), TyKind::Dyn(_)) + { + return Ok(()); + } + } + return Err(CastError::NonScalar); + } }; // rustc checks whether the `expr_ty` is foreign adt with `non_exhaustive` sym diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs index 2f6f033f25c7..94bc62779874 100644 --- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -289,7 +289,7 @@ pub fn main() { fn dyn_tail_need_normalization() { check_diagnostics( r#" -//- minicore: dispatch_from_dyn +//- minicore: coerce_unsized, dispatch_from_dyn trait Trait { type Associated; } @@ -370,7 +370,7 @@ fn main() { fn fat_ptr_cast() { check_diagnostics_with_disabled( r#" -//- minicore: sized +//- minicore: coerce_unsized, dispatch_from_dyn trait Foo { fn foo(&self) {} //~ WARN method `foo` is never used } @@ -399,12 +399,12 @@ fn main() { let d = to_raw(a) as usize; } "#, - &["E0308"], + &["E0308", "unused_variables"], ); check_diagnostics_with_disabled( r#" -//- minicore: sized +//- minicore: coerce_unsized, dispatch_from_dyn trait Trait {} struct Box; @@ -476,7 +476,7 @@ fn main() { fn ptr_to_ptr_different_regions() { check_diagnostics( r#" -//- minicore: sized +//- minicore: coerce_unsized, dispatch_from_dyn struct Foo<'a> { a: &'a () } fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> { @@ -503,7 +503,7 @@ fn main() { fn ptr_to_trait_obj_add_auto() { check_diagnostics( r#" -//- minicore: pointee +//- minicore: pointee, coerce_unsized, dispatch_from_dyn trait Trait<'a> {} fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) { @@ -522,7 +522,7 @@ fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + fn ptr_to_trait_obj_add_super_auto() { check_diagnostics( r#" -//- minicore: pointee +//- minicore: pointee, coerce_unsized, dispatch_from_dyn trait Trait: Send {} impl Trait for () {} @@ -538,7 +538,7 @@ fn main() { fn ptr_to_trait_obj_ok() { check_diagnostics( r#" -//- minicore: pointee +//- minicore: pointee, coerce_unsized, dispatch_from_dyn trait Trait<'a> {} fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> { @@ -560,7 +560,7 @@ fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) { fn ptr_to_trait_obj_wrap_upcast() { check_diagnostics( r#" -//- minicore: sized +//- minicore: pointee, coerce_unsized, dispatch_from_dyn trait Super {} trait Sub: Super {} @@ -1004,4 +1004,16 @@ fn _slice(bar: &[i32]) -> bool { &["E0308"], ); } + + #[test] + fn cast_into_dst_with_integer_fallback() { + check_diagnostics( + r#" +//- minicore: fmt, coerce_unsized, dispatch_from_dyn +fn test() { + let _ = &42 as &dyn core::fmt::Debug; +} +"#, + ) + } } From e15c26a62b3de0e1fe4262c060f2242df01e9712 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 6 Sep 2024 01:49:42 +0900 Subject: [PATCH 2/2] Typo --- crates/hir-ty/src/infer/cast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index 413112e34131..22072a992130 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs @@ -193,7 +193,7 @@ impl CastCheck { // under current chalk trait solver. (See #11847 and #18047) // So, emit no diagnostic for casts like `&T as &dyn Trait` for now, // to prevent false positive diagnositcs. - // Direct cast without ref like `T as dyn Trait` is prohibitied by + // Direct cast without ref like `T as dyn Trait` is prohibited by // `InferenceDiagnostic::CastToUnsized`, so allowing this diagnostics bypass // only to `&T as &dyn Trait` is sufficient if let (TyKind::Ref(m_expr, _, _), TyKind::Ref(m_cast, _, t_cast)) =