Skip to content

Commit a278370

Browse files
authored
Merge pull request #19432 from ShoyuVanilla/issue-19431
fix: Yet another false positive invalid cast diagnostic
2 parents 6832c5a + 9cfea3e commit a278370

File tree

3 files changed

+134
-26
lines changed

3 files changed

+134
-26
lines changed

crates/hir-ty/src/infer/cast.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl CastTy {
5050
None
5151
}
5252
}
53-
TyKind::Raw(m, ty) => Some(Self::Ptr(table.resolve_ty_shallow(ty), *m)),
53+
TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)),
5454
TyKind::Function(_) => Some(Self::FnPtr),
5555
_ => None,
5656
}
@@ -105,9 +105,8 @@ impl CastCheck {
105105
F: FnMut(ExprId, Vec<Adjustment>),
106106
G: FnMut(ExprId),
107107
{
108-
table.resolve_obligations_as_possible();
109-
self.expr_ty = table.resolve_ty_shallow(&self.expr_ty);
110-
self.cast_ty = table.resolve_ty_shallow(&self.cast_ty);
108+
self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone());
109+
self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone());
111110

112111
if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() {
113112
return Ok(());
@@ -153,7 +152,7 @@ impl CastCheck {
153152
(None, Some(t_cast)) => match self.expr_ty.kind(Interner) {
154153
TyKind::FnDef(..) => {
155154
let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig");
156-
let sig = table.normalize_associated_types_in(sig);
155+
let sig = table.eagerly_normalize_and_resolve_shallow_in(sig);
157156
let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
158157
if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes)
159158
{
@@ -165,7 +164,6 @@ impl CastCheck {
165164
(CastTy::FnPtr, t_cast)
166165
}
167166
TyKind::Ref(mutbl, _, inner_ty) => {
168-
let inner_ty = table.resolve_ty_shallow(inner_ty);
169167
return match t_cast {
170168
CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) {
171169
TyKind::Scalar(
@@ -180,13 +178,13 @@ impl CastCheck {
180178
},
181179
// array-ptr-cast
182180
CastTy::Ptr(t, m) => {
183-
let t = table.resolve_ty_shallow(&t);
181+
let t = table.eagerly_normalize_and_resolve_shallow_in(t);
184182
if !table.is_sized(&t) {
185183
return Err(CastError::IllegalCast);
186184
}
187185
self.check_ref_cast(
188186
table,
189-
&inner_ty,
187+
inner_ty,
190188
*mutbl,
191189
&t,
192190
m,
@@ -359,7 +357,7 @@ impl CastCheck {
359357
}
360358
}
361359

362-
#[derive(PartialEq, Eq)]
360+
#[derive(Debug, PartialEq, Eq)]
363361
enum PointerKind {
364362
// thin pointer
365363
Thin,
@@ -373,8 +371,7 @@ enum PointerKind {
373371
}
374372

375373
fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<PointerKind>, ()> {
376-
let ty = table.resolve_ty_shallow(ty);
377-
let ty = table.normalize_associated_types_in(ty);
374+
let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone());
378375

379376
if table.is_sized(&ty) {
380377
return Ok(Some(PointerKind::Thin));

crates/hir-ty/src/infer/unify.rs

+81-14
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,64 @@ impl<'a> InferenceTable<'a> {
364364
)
365365
}
366366

367+
/// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
368+
/// the inference variables
369+
pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T
370+
where
371+
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
372+
{
373+
fn eagerly_resolve_ty<const N: usize>(
374+
table: &mut InferenceTable<'_>,
375+
ty: Ty,
376+
mut tys: SmallVec<[Ty; N]>,
377+
) -> Ty {
378+
if tys.contains(&ty) {
379+
return ty;
380+
}
381+
tys.push(ty.clone());
382+
383+
match ty.kind(Interner) {
384+
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
385+
let ty = table.normalize_projection_ty(proj_ty.clone());
386+
eagerly_resolve_ty(table, ty, tys)
387+
}
388+
TyKind::InferenceVar(..) => {
389+
let ty = table.resolve_ty_shallow(&ty);
390+
eagerly_resolve_ty(table, ty, tys)
391+
}
392+
_ => ty,
393+
}
394+
}
395+
396+
fold_tys_and_consts(
397+
ty,
398+
|e, _| match e {
399+
Either::Left(ty) => {
400+
Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new()))
401+
}
402+
Either::Right(c) => Either::Right(match &c.data(Interner).value {
403+
chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
404+
crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
405+
// FIXME: same as `normalize_associated_types_in`
406+
if subst.len(Interner) == 0 {
407+
if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
408+
eval
409+
} else {
410+
unknown_const(c.data(Interner).ty.clone())
411+
}
412+
} else {
413+
unknown_const(c.data(Interner).ty.clone())
414+
}
415+
}
416+
_ => c,
417+
},
418+
_ => c,
419+
}),
420+
},
421+
DebruijnIndex::INNERMOST,
422+
)
423+
}
424+
367425
pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
368426
let var = self.new_type_var();
369427
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
@@ -918,7 +976,26 @@ impl<'a> InferenceTable<'a> {
918976

919977
/// Check if given type is `Sized` or not
920978
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
979+
fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> {
980+
match ty.kind(Interner) {
981+
TyKind::Scalar(..)
982+
| TyKind::Ref(..)
983+
| TyKind::Raw(..)
984+
| TyKind::Never
985+
| TyKind::FnDef(..)
986+
| TyKind::Array(..)
987+
| TyKind::Function(..) => Some(true),
988+
TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false),
989+
_ => None,
990+
}
991+
}
992+
921993
let mut ty = ty.clone();
994+
ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
995+
if let Some(sized) = short_circuit_trivial_tys(&ty) {
996+
return sized;
997+
}
998+
922999
{
9231000
let mut structs = SmallVec::<[_; 8]>::new();
9241001
// Must use a loop here and not recursion because otherwise users will conduct completely
@@ -937,26 +1014,16 @@ impl<'a> InferenceTable<'a> {
9371014
// Structs can have DST as its last field and such cases are not handled
9381015
// as unsized by the chalk, so we do this manually.
9391016
ty = last_field_ty;
1017+
ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
1018+
if let Some(sized) = short_circuit_trivial_tys(&ty) {
1019+
return sized;
1020+
}
9401021
} else {
9411022
break;
9421023
};
9431024
}
9441025
}
9451026

946-
// Early return for some obvious types
947-
if matches!(
948-
ty.kind(Interner),
949-
TyKind::Scalar(..)
950-
| TyKind::Ref(..)
951-
| TyKind::Raw(..)
952-
| TyKind::Never
953-
| TyKind::FnDef(..)
954-
| TyKind::Array(..)
955-
| TyKind::Function(_)
956-
) {
957-
return true;
958-
}
959-
9601027
let Some(sized) = self
9611028
.db
9621029
.lang_item(self.trait_env.krate, LangItem::Sized)

crates/ide-diagnostics/src/handlers/invalid_cast.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,9 @@ fn main() {
440440
q as *const [i32];
441441
//^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]`
442442
443+
// FIXME: This should emit diagnostics but disabled to prevent many false positives
443444
let t: *mut (dyn Trait + 'static) = 0 as *mut _;
444-
//^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _`
445+
445446
let mut fail: *const str = 0 as *const str;
446447
//^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str`
447448
let mut fail2: *const str = 0isize as *const str;
@@ -1161,6 +1162,49 @@ struct ZerocopyKnownLayoutMaybeUninit(<<Flexible as Field>::Type as KnownLayout>
11611162
fn test(ptr: *mut [u8]) -> *mut ZerocopyKnownLayoutMaybeUninit {
11621163
ptr as *mut _
11631164
}
1165+
"#,
1166+
);
1167+
}
1168+
1169+
#[test]
1170+
fn regression_19431() {
1171+
check_diagnostics(
1172+
r#"
1173+
//- minicore: coerce_unsized
1174+
struct Dst([u8]);
1175+
1176+
struct Struct {
1177+
body: Dst,
1178+
}
1179+
1180+
trait Field {
1181+
type Type: ?Sized;
1182+
}
1183+
1184+
impl Field for Struct {
1185+
type Type = Dst;
1186+
}
1187+
1188+
trait KnownLayout {
1189+
type MaybeUninit: ?Sized;
1190+
type PointerMetadata;
1191+
}
1192+
1193+
impl<T> KnownLayout for [T] {
1194+
type MaybeUninit = [T];
1195+
type PointerMetadata = usize;
1196+
}
1197+
1198+
impl KnownLayout for Dst {
1199+
type MaybeUninit = Dst;
1200+
type PointerMetadata = <[u8] as KnownLayout>::PointerMetadata;
1201+
}
1202+
1203+
struct ZerocopyKnownLayoutMaybeUninit(<<Struct as Field>::Type as KnownLayout>::MaybeUninit);
1204+
1205+
fn test(ptr: *mut ZerocopyKnownLayoutMaybeUninit) -> *mut <<Struct as Field>::Type as KnownLayout>::MaybeUninit {
1206+
ptr as *mut _
1207+
}
11641208
"#,
11651209
);
11661210
}

0 commit comments

Comments
 (0)