Skip to content

Commit ec24442

Browse files
committed
Provide hint when cast needs a dereference
For a given code: ```rust vec![0.0].iter().map(|s| s as i16).collect::<Vec<i16>>(); ``` display: ```nocode error: casting `&f64` as `i16` is invalid --> foo.rs:2:35 | 2 | vec![0.0].iter().map(|s| s as i16).collect::<Vec<i16>>(); | - ^^^ cannot cast `&f64` as `i16` | | | did you mean `*s`? ``` instead of: ```nocode error: casting `&f64` as `i16` is invalid --> <anon>:2:30 | 2 | vec![0.0].iter().map(|s| s as i16).collect(); | ^^^^^^^^ | = help: cast through a raw pointer first ```
1 parent fb025b4 commit ec24442

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

src/librustc_typeck/check/cast.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ enum CastError {
102102
/// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
103103
SizedUnsizedCast,
104104
IllegalCast,
105+
NeedDeref,
105106
NeedViaPtr,
106107
NeedViaThinPtr,
107108
NeedViaInt,
@@ -138,6 +139,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
138139

139140
fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
140141
match e {
142+
CastError::NeedDeref => {
143+
let cast_ty = fcx.ty_to_string(self.cast_ty);
144+
let mut err = fcx.type_error_struct(self.cast_span,
145+
|actual| {
146+
format!("casting `{}` as `{}` is invalid",
147+
actual,
148+
cast_ty)
149+
},
150+
self.expr_ty);
151+
err.span_label(self.expr.span,
152+
&format!("cannot cast `{}` as `{}`",
153+
fcx.ty_to_string(self.expr_ty),
154+
cast_ty));
155+
if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
156+
err.span_label(self.expr.span,
157+
&format!("did you mean `*{}`?", snippet));
158+
}
159+
err.emit();
160+
}
141161
CastError::NeedViaThinPtr |
142162
CastError::NeedViaPtr => {
143163
let mut err = fcx.type_error_struct(self.span,
@@ -390,8 +410,28 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
390410
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
391411
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
392412
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
393-
(RPtr(_), Int(_)) |
394-
(RPtr(_), Float) => Err(CastError::NeedViaPtr),
413+
(RPtr(p), Int(_)) |
414+
(RPtr(p), Float) => {
415+
match p.ty.sty {
416+
ty::TypeVariants::TyInt(_) |
417+
ty::TypeVariants::TyUint(_) |
418+
ty::TypeVariants::TyFloat(_) => {
419+
Err(CastError::NeedDeref)
420+
}
421+
ty::TypeVariants::TyInfer(t) => {
422+
match t {
423+
ty::InferTy::IntVar(_) |
424+
ty::InferTy::FloatVar(_) |
425+
ty::InferTy::FreshIntTy(_) |
426+
ty::InferTy::FreshFloatTy(_) => {
427+
Err(CastError::NeedDeref)
428+
}
429+
_ => Err(CastError::NeedViaPtr),
430+
}
431+
}
432+
_ => Err(CastError::NeedViaPtr),
433+
}
434+
}
395435
// * -> ptr
396436
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
397437
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),

src/test/compile-fail/cast-rfc0401.rs

+5
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,9 @@ fn main()
115115
let _ = cf as *const Bar;
116116
//~^ ERROR casting
117117
//~^^ NOTE vtable kinds
118+
119+
vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
120+
//~^ ERROR casting `&{float}` as `f32` is invalid
121+
//~| NOTE cannot cast `&{float}` as `f32`
122+
//~| NOTE did you mean `*s`?
118123
}

0 commit comments

Comments
 (0)