@@ -45,19 +45,21 @@ use super::structurally_resolved_type;
4545
4646use lint;
4747use hir:: def_id:: DefId ;
48+ use rustc:: hir;
49+ use rustc:: traits;
4850use rustc:: ty:: { self , Ty , TypeFoldable } ;
4951use rustc:: ty:: cast:: { CastKind , CastTy } ;
50- use syntax:: codemap:: Span ;
51- use rustc:: hir;
5252use syntax:: ast;
53-
53+ use syntax:: codemap:: Span ;
54+ use util:: common:: ErrorReported ;
5455
5556/// Reifies a cast check to be checked once we have full type information for
5657/// a function context.
5758pub struct CastCheck < ' tcx > {
5859 expr : & ' tcx hir:: Expr ,
5960 expr_ty : Ty < ' tcx > ,
6061 cast_ty : Ty < ' tcx > ,
62+ cast_span : Span ,
6163 span : Span ,
6264}
6365
@@ -111,17 +113,37 @@ enum CastError {
111113}
112114
113115impl < ' tcx > CastCheck < ' tcx > {
114- pub fn new ( expr : & ' tcx hir:: Expr , expr_ty : Ty < ' tcx > , cast_ty : Ty < ' tcx > , span : Span )
115- -> CastCheck < ' tcx > {
116- CastCheck {
116+ pub fn new < ' a > ( fcx : & FnCtxt < ' a , ' tcx > ,
117+ expr : & ' tcx hir:: Expr ,
118+ expr_ty : Ty < ' tcx > ,
119+ cast_ty : Ty < ' tcx > ,
120+ cast_span : Span ,
121+ span : Span )
122+ -> Result < CastCheck < ' tcx > , ErrorReported > {
123+ let check = CastCheck {
117124 expr : expr,
118125 expr_ty : expr_ty,
119126 cast_ty : cast_ty,
127+ cast_span : cast_span,
120128 span : span,
129+ } ;
130+
131+ // For better error messages, check for some obviously unsized
132+ // cases now. We do a more thorough check at the end, once
133+ // inference is more completely known.
134+ match cast_ty. sty {
135+ ty:: TyTrait ( ..) | ty:: TySlice ( ..) => {
136+ check. report_cast_to_unsized_type ( fcx) ;
137+ Err ( ErrorReported )
138+ }
139+ _ => {
140+ Ok ( check)
141+ }
121142 }
122143 }
123144
124- fn report_cast_error < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ,
145+ fn report_cast_error < ' a > ( & self ,
146+ fcx : & FnCtxt < ' a , ' tcx > ,
125147 e : CastError ) {
126148 match e {
127149 CastError :: NeedViaPtr |
@@ -186,6 +208,61 @@ impl<'tcx> CastCheck<'tcx> {
186208 }
187209 }
188210
211+ fn report_cast_to_unsized_type < ' a > ( & self ,
212+ fcx : & FnCtxt < ' a , ' tcx > ) {
213+ if
214+ self . cast_ty . references_error ( ) ||
215+ self . expr_ty . references_error ( )
216+ {
217+ return ;
218+ }
219+
220+ let tstr = fcx. infcx ( ) . ty_to_string ( self . cast_ty ) ;
221+ let mut err = fcx. type_error_struct ( self . span , |actual| {
222+ format ! ( "cast to unsized type: `{}` as `{}`" , actual, tstr)
223+ } , self . expr_ty , None ) ;
224+ match self . expr_ty . sty {
225+ ty:: TyRef ( _, ty:: TypeAndMut { mutbl : mt, .. } ) => {
226+ let mtstr = match mt {
227+ hir:: MutMutable => "mut " ,
228+ hir:: MutImmutable => ""
229+ } ;
230+ if self . cast_ty . is_trait ( ) {
231+ match fcx. tcx ( ) . sess . codemap ( ) . span_to_snippet ( self . cast_span ) {
232+ Ok ( s) => {
233+ err. span_suggestion ( self . cast_span ,
234+ "try casting to a reference instead:" ,
235+ format ! ( "&{}{}" , mtstr, s) ) ;
236+ } ,
237+ Err ( _) =>
238+ span_help ! ( err, self . cast_span,
239+ "did you mean `&{}{}`?" , mtstr, tstr) ,
240+ }
241+ } else {
242+ span_help ! ( err, self . span,
243+ "consider using an implicit coercion to `&{}{}` instead" ,
244+ mtstr, tstr) ;
245+ }
246+ }
247+ ty:: TyBox ( ..) => {
248+ match fcx. tcx ( ) . sess . codemap ( ) . span_to_snippet ( self . cast_span ) {
249+ Ok ( s) => {
250+ err. span_suggestion ( self . cast_span ,
251+ "try casting to a `Box` instead:" ,
252+ format ! ( "Box<{}>" , s) ) ;
253+ } ,
254+ Err ( _) =>
255+ span_help ! ( err, self . cast_span, "did you mean `Box<{}>`?" , tstr) ,
256+ }
257+ }
258+ _ => {
259+ span_help ! ( err, self . expr. span,
260+ "consider using a box or reference as appropriate" ) ;
261+ }
262+ }
263+ err. emit ( ) ;
264+ }
265+
189266 fn trivial_cast_lint < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ) {
190267 let t_cast = self . cast_ty ;
191268 let t_expr = self . expr_ty ;
@@ -218,7 +295,9 @@ impl<'tcx> CastCheck<'tcx> {
218295 debug ! ( "check_cast({}, {:?} as {:?})" , self . expr. id, self . expr_ty,
219296 self . cast_ty) ;
220297
221- if self . expr_ty . references_error ( ) || self . cast_ty . references_error ( ) {
298+ if !fcx. type_is_known_to_be_sized ( self . cast_ty , self . span ) {
299+ self . report_cast_to_unsized_type ( fcx) ;
300+ } else if self . expr_ty . references_error ( ) || self . cast_ty . references_error ( ) {
222301 // No sense in giving duplicate error messages
223302 } else if self . try_coercion_cast ( fcx) {
224303 self . trivial_cast_lint ( fcx) ;
@@ -403,3 +482,17 @@ impl<'tcx> CastCheck<'tcx> {
403482 }
404483
405484}
485+
486+ impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
487+ fn type_is_known_to_be_sized ( & self ,
488+ ty : Ty < ' tcx > ,
489+ span : Span )
490+ -> bool
491+ {
492+ traits:: type_known_to_meet_builtin_bound ( self . infcx ( ) ,
493+ ty,
494+ ty:: BoundSized ,
495+ span)
496+ }
497+ }
498+
0 commit comments