mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Merge pull request #19432 from ShoyuVanilla/issue-19431
fix: Yet another false positive invalid cast diagnostic
This commit is contained in:
		
						commit
						a2783704bf
					
				
					 3 changed files with 134 additions and 26 deletions
				
			
		|  | @ -50,7 +50,7 @@ impl CastTy { | |||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             TyKind::Raw(m, ty) => Some(Self::Ptr(table.resolve_ty_shallow(ty), *m)), | ||||
|             TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)), | ||||
|             TyKind::Function(_) => Some(Self::FnPtr), | ||||
|             _ => None, | ||||
|         } | ||||
|  | @ -105,9 +105,8 @@ impl CastCheck { | |||
|         F: FnMut(ExprId, Vec<Adjustment>), | ||||
|         G: FnMut(ExprId), | ||||
|     { | ||||
|         table.resolve_obligations_as_possible(); | ||||
|         self.expr_ty = table.resolve_ty_shallow(&self.expr_ty); | ||||
|         self.cast_ty = table.resolve_ty_shallow(&self.cast_ty); | ||||
|         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()); | ||||
| 
 | ||||
|         if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() { | ||||
|             return Ok(()); | ||||
|  | @ -153,7 +152,7 @@ impl CastCheck { | |||
|                 (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.normalize_associated_types_in(sig); | ||||
|                         let sig = 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) | ||||
|                         { | ||||
|  | @ -165,7 +164,6 @@ impl CastCheck { | |||
|                         (CastTy::FnPtr, t_cast) | ||||
|                     } | ||||
|                     TyKind::Ref(mutbl, _, inner_ty) => { | ||||
|                         let inner_ty = table.resolve_ty_shallow(inner_ty); | ||||
|                         return match t_cast { | ||||
|                             CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) { | ||||
|                                 TyKind::Scalar( | ||||
|  | @ -180,13 +178,13 @@ impl CastCheck { | |||
|                             }, | ||||
|                             // array-ptr-cast
 | ||||
|                             CastTy::Ptr(t, m) => { | ||||
|                                 let t = table.resolve_ty_shallow(&t); | ||||
|                                 let t = table.eagerly_normalize_and_resolve_shallow_in(t); | ||||
|                                 if !table.is_sized(&t) { | ||||
|                                     return Err(CastError::IllegalCast); | ||||
|                                 } | ||||
|                                 self.check_ref_cast( | ||||
|                                     table, | ||||
|                                     &inner_ty, | ||||
|                                     inner_ty, | ||||
|                                     *mutbl, | ||||
|                                     &t, | ||||
|                                     m, | ||||
|  | @ -359,7 +357,7 @@ impl CastCheck { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(PartialEq, Eq)] | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| enum PointerKind { | ||||
|     // thin pointer
 | ||||
|     Thin, | ||||
|  | @ -373,8 +371,7 @@ enum PointerKind { | |||
| } | ||||
| 
 | ||||
| fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<PointerKind>, ()> { | ||||
|     let ty = table.resolve_ty_shallow(ty); | ||||
|     let ty = table.normalize_associated_types_in(ty); | ||||
|     let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone()); | ||||
| 
 | ||||
|     if table.is_sized(&ty) { | ||||
|         return Ok(Some(PointerKind::Thin)); | ||||
|  |  | |||
|  | @ -364,6 +364,64 @@ impl<'a> InferenceTable<'a> { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
 | ||||
|     /// the inference variables
 | ||||
|     pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T | ||||
|     where | ||||
|         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>, | ||||
|     { | ||||
|         fn eagerly_resolve_ty<const N: usize>( | ||||
|             table: &mut InferenceTable<'_>, | ||||
|             ty: Ty, | ||||
|             mut tys: SmallVec<[Ty; N]>, | ||||
|         ) -> Ty { | ||||
|             if tys.contains(&ty) { | ||||
|                 return ty; | ||||
|             } | ||||
|             tys.push(ty.clone()); | ||||
| 
 | ||||
|             match ty.kind(Interner) { | ||||
|                 TyKind::Alias(AliasTy::Projection(proj_ty)) => { | ||||
|                     let ty = table.normalize_projection_ty(proj_ty.clone()); | ||||
|                     eagerly_resolve_ty(table, ty, tys) | ||||
|                 } | ||||
|                 TyKind::InferenceVar(..) => { | ||||
|                     let ty = table.resolve_ty_shallow(&ty); | ||||
|                     eagerly_resolve_ty(table, ty, tys) | ||||
|                 } | ||||
|                 _ => ty, | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         fold_tys_and_consts( | ||||
|             ty, | ||||
|             |e, _| match e { | ||||
|                 Either::Left(ty) => { | ||||
|                     Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new())) | ||||
|                 } | ||||
|                 Either::Right(c) => Either::Right(match &c.data(Interner).value { | ||||
|                     chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { | ||||
|                         crate::ConstScalar::UnevaluatedConst(c_id, subst) => { | ||||
|                             // FIXME: same as `normalize_associated_types_in`
 | ||||
|                             if subst.len(Interner) == 0 { | ||||
|                                 if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) { | ||||
|                                     eval | ||||
|                                 } else { | ||||
|                                     unknown_const(c.data(Interner).ty.clone()) | ||||
|                                 } | ||||
|                             } else { | ||||
|                                 unknown_const(c.data(Interner).ty.clone()) | ||||
|                             } | ||||
|                         } | ||||
|                         _ => c, | ||||
|                     }, | ||||
|                     _ => c, | ||||
|                 }), | ||||
|             }, | ||||
|             DebruijnIndex::INNERMOST, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { | ||||
|         let var = self.new_type_var(); | ||||
|         let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; | ||||
|  | @ -918,7 +976,26 @@ impl<'a> InferenceTable<'a> { | |||
| 
 | ||||
|     /// Check if given type is `Sized` or not
 | ||||
|     pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { | ||||
|         fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> { | ||||
|             match ty.kind(Interner) { | ||||
|                 TyKind::Scalar(..) | ||||
|                 | TyKind::Ref(..) | ||||
|                 | TyKind::Raw(..) | ||||
|                 | TyKind::Never | ||||
|                 | TyKind::FnDef(..) | ||||
|                 | TyKind::Array(..) | ||||
|                 | TyKind::Function(..) => Some(true), | ||||
|                 TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false), | ||||
|                 _ => None, | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut ty = ty.clone(); | ||||
|         ty = self.eagerly_normalize_and_resolve_shallow_in(ty); | ||||
|         if let Some(sized) = short_circuit_trivial_tys(&ty) { | ||||
|             return sized; | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let mut structs = SmallVec::<[_; 8]>::new(); | ||||
|             // Must use a loop here and not recursion because otherwise users will conduct completely
 | ||||
|  | @ -937,26 +1014,16 @@ impl<'a> InferenceTable<'a> { | |||
|                     // Structs can have DST as its last field and such cases are not handled
 | ||||
|                     // as unsized by the chalk, so we do this manually.
 | ||||
|                     ty = last_field_ty; | ||||
|                     ty = self.eagerly_normalize_and_resolve_shallow_in(ty); | ||||
|                     if let Some(sized) = short_circuit_trivial_tys(&ty) { | ||||
|                         return sized; | ||||
|                     } | ||||
|                 } else { | ||||
|                     break; | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Early return for some obvious types
 | ||||
|         if matches!( | ||||
|             ty.kind(Interner), | ||||
|             TyKind::Scalar(..) | ||||
|                 | TyKind::Ref(..) | ||||
|                 | TyKind::Raw(..) | ||||
|                 | TyKind::Never | ||||
|                 | TyKind::FnDef(..) | ||||
|                 | TyKind::Array(..) | ||||
|                 | TyKind::Function(_) | ||||
|         ) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         let Some(sized) = self | ||||
|             .db | ||||
|             .lang_item(self.trait_env.krate, LangItem::Sized) | ||||
|  |  | |||
|  | @ -440,8 +440,9 @@ fn main() { | |||
|     q as *const [i32]; | ||||
|   //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]`
 | ||||
| 
 | ||||
|     // FIXME: This should emit diagnostics but disabled to prevent many false positives
 | ||||
|     let t: *mut (dyn Trait + 'static) = 0 as *mut _; | ||||
|                                       //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _`
 | ||||
| 
 | ||||
|     let mut fail: *const str = 0 as *const str; | ||||
|                              //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str`
 | ||||
|     let mut fail2: *const str = 0isize as *const str; | ||||
|  | @ -1161,6 +1162,49 @@ struct ZerocopyKnownLayoutMaybeUninit(<<Flexible as Field>::Type as KnownLayout> | |||
| fn test(ptr: *mut [u8]) -> *mut ZerocopyKnownLayoutMaybeUninit { | ||||
|     ptr as *mut _ | ||||
| } | ||||
| "#,
 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn regression_19431() { | ||||
|         check_diagnostics( | ||||
|             r#" | ||||
| //- minicore: coerce_unsized
 | ||||
| struct Dst([u8]); | ||||
| 
 | ||||
| struct Struct { | ||||
|     body: Dst, | ||||
| } | ||||
| 
 | ||||
| trait Field { | ||||
|     type Type: ?Sized; | ||||
| } | ||||
| 
 | ||||
| impl Field for Struct { | ||||
|     type Type = Dst; | ||||
| } | ||||
| 
 | ||||
| trait KnownLayout { | ||||
|     type MaybeUninit: ?Sized; | ||||
|     type PointerMetadata; | ||||
| } | ||||
| 
 | ||||
| impl<T> KnownLayout for [T] { | ||||
|     type MaybeUninit = [T]; | ||||
|     type PointerMetadata = usize; | ||||
| } | ||||
| 
 | ||||
| impl KnownLayout for Dst { | ||||
|     type MaybeUninit = Dst; | ||||
|     type PointerMetadata = <[u8] as KnownLayout>::PointerMetadata; | ||||
| } | ||||
| 
 | ||||
| struct ZerocopyKnownLayoutMaybeUninit(<<Struct as Field>::Type as KnownLayout>::MaybeUninit); | ||||
| 
 | ||||
| fn test(ptr: *mut ZerocopyKnownLayoutMaybeUninit) -> *mut <<Struct as Field>::Type as KnownLayout>::MaybeUninit { | ||||
|     ptr as *mut _ | ||||
| } | ||||
| "#,
 | ||||
|         ); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth