Skip to content

Commit

Permalink
Rollup merge of rust-lang#37442 - estebank:cast-deref-hint, r=jonatha…
Browse files Browse the repository at this point in the history
…ndturner

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
 --> file3.rs:2:35
  |
2 |     vec![0.0].iter().map(|s| s as i16).collect::<Vec<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
```

Fixes rust-lang#37338.
  • Loading branch information
GuillaumeGomez authored Nov 23, 2016
2 parents ccdc26f + ec24442 commit 464cce9
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
44 changes: 42 additions & 2 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ enum CastError {
/// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
SizedUnsizedCast,
IllegalCast,
NeedDeref,
NeedViaPtr,
NeedViaThinPtr,
NeedViaInt,
Expand Down Expand Up @@ -138,6 +139,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {

fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
match e {
CastError::NeedDeref => {
let cast_ty = fcx.ty_to_string(self.cast_ty);
let mut err = fcx.type_error_struct(self.cast_span,
|actual| {
format!("casting `{}` as `{}` is invalid",
actual,
cast_ty)
},
self.expr_ty);
err.span_label(self.expr.span,
&format!("cannot cast `{}` as `{}`",
fcx.ty_to_string(self.expr_ty),
cast_ty));
if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
err.span_label(self.expr.span,
&format!("did you mean `*{}`?", snippet));
}
err.emit();
}
CastError::NeedViaThinPtr |
CastError::NeedViaPtr => {
let mut err = fcx.type_error_struct(self.span,
Expand Down Expand Up @@ -390,8 +410,28 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
(RPtr(_), Int(_)) |
(RPtr(_), Float) => Err(CastError::NeedViaPtr),
(RPtr(p), Int(_)) |
(RPtr(p), Float) => {
match p.ty.sty {
ty::TypeVariants::TyInt(_) |
ty::TypeVariants::TyUint(_) |
ty::TypeVariants::TyFloat(_) => {
Err(CastError::NeedDeref)
}
ty::TypeVariants::TyInfer(t) => {
match t {
ty::InferTy::IntVar(_) |
ty::InferTy::FloatVar(_) |
ty::InferTy::FreshIntTy(_) |
ty::InferTy::FreshFloatTy(_) => {
Err(CastError::NeedDeref)
}
_ => Err(CastError::NeedViaPtr),
}
}
_ => Err(CastError::NeedViaPtr),
}
}
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
Expand Down
5 changes: 5 additions & 0 deletions src/test/compile-fail/cast-rfc0401.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,9 @@ fn main()
let _ = cf as *const Bar;
//~^ ERROR casting
//~^^ NOTE vtable kinds

vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
//~^ ERROR casting `&{float}` as `f32` is invalid
//~| NOTE cannot cast `&{float}` as `f32`
//~| NOTE did you mean `*s`?
}

0 comments on commit 464cce9

Please sign in to comment.