@@ -45,19 +45,21 @@ use super::structurally_resolved_type;
45
45
46
46
use lint;
47
47
use hir:: def_id:: DefId ;
48
+ use rustc:: hir;
49
+ use rustc:: traits;
48
50
use rustc:: ty:: { self , Ty , TypeFoldable } ;
49
51
use rustc:: ty:: cast:: { CastKind , CastTy } ;
50
- use syntax:: codemap:: Span ;
51
- use rustc:: hir;
52
52
use syntax:: ast;
53
-
53
+ use syntax:: codemap:: Span ;
54
+ use util:: common:: ErrorReported ;
54
55
55
56
/// Reifies a cast check to be checked once we have full type information for
56
57
/// a function context.
57
58
pub struct CastCheck < ' tcx > {
58
59
expr : & ' tcx hir:: Expr ,
59
60
expr_ty : Ty < ' tcx > ,
60
61
cast_ty : Ty < ' tcx > ,
62
+ cast_span : Span ,
61
63
span : Span ,
62
64
}
63
65
@@ -111,17 +113,37 @@ enum CastError {
111
113
}
112
114
113
115
impl < ' 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 {
117
124
expr : expr,
118
125
expr_ty : expr_ty,
119
126
cast_ty : cast_ty,
127
+ cast_span : cast_span,
120
128
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
+ }
121
142
}
122
143
}
123
144
124
- fn report_cast_error < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ,
145
+ fn report_cast_error < ' a > ( & self ,
146
+ fcx : & FnCtxt < ' a , ' tcx > ,
125
147
e : CastError ) {
126
148
match e {
127
149
CastError :: NeedViaPtr |
@@ -186,6 +208,61 @@ impl<'tcx> CastCheck<'tcx> {
186
208
}
187
209
}
188
210
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
+
189
266
fn trivial_cast_lint < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ) {
190
267
let t_cast = self . cast_ty ;
191
268
let t_expr = self . expr_ty ;
@@ -218,7 +295,9 @@ impl<'tcx> CastCheck<'tcx> {
218
295
debug ! ( "check_cast({}, {:?} as {:?})" , self . expr. id, self . expr_ty,
219
296
self . cast_ty) ;
220
297
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 ( ) {
222
301
// No sense in giving duplicate error messages
223
302
} else if self . try_coercion_cast ( fcx) {
224
303
self . trivial_cast_lint ( fcx) ;
@@ -403,3 +482,17 @@ impl<'tcx> CastCheck<'tcx> {
403
482
}
404
483
405
484
}
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