diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2016-11-23 12:18:09 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-11-23 12:18:09 +0100 |
| commit | 464cce99f1fe09db35d56ca07ae4c05f591eb651 (patch) | |
| tree | f4e030f5660d678509d4ba5c44d8824c8e1ca259 /src | |
| parent | ccdc26fd42dfccc5832114baa275f0936738095a (diff) | |
| parent | ec24442e60bce2605a64ac3aef5784510e4a5fd5 (diff) | |
| download | rust-464cce99f1fe09db35d56ca07ae4c05f591eb651.tar.gz rust-464cce99f1fe09db35d56ca07ae4c05f591eb651.zip | |
Rollup merge of #37442 - estebank:cast-deref-hint, r=jonathandturner
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 #37338.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_typeck/check/cast.rs | 44 | ||||
| -rw-r--r-- | src/test/compile-fail/cast-rfc0401.rs | 5 |
2 files changed, 47 insertions, 2 deletions
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 4edf0011cb3..5839c606566 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -102,6 +102,7 @@ enum CastError { /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`) SizedUnsizedCast, IllegalCast, + NeedDeref, NeedViaPtr, NeedViaThinPtr, NeedViaInt, @@ -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, @@ -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), diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 1dbad9e30e3..b98f464c902 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -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`? } |
