@@ -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,37 +113,35 @@ 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, we try to check whether the
132
+ // target type is known to be sized now (we will also check
133
+ // later, once inference is more complete done).
134
+ if !fcx. type_is_known_to_be_sized ( cast_ty, span) {
135
+ check. report_cast_to_unsized_type ( fcx) ;
136
+ return Err ( ErrorReported ) ;
121
137
}
138
+
139
+ Ok ( check)
122
140
}
123
141
124
142
fn report_cast_error < ' a > ( & self ,
125
143
fcx : & FnCtxt < ' a , ' tcx > ,
126
144
e : CastError ) {
127
- // As a heuristic, don't report errors if there are unresolved
128
- // inference variables floating around AND we've already
129
- // reported some errors in this fn. It happens often that those
130
- // inference variables are unresolved precisely *because* of
131
- // the errors we've already reported. See #31997.
132
- //
133
- // Note: it's kind of annoying that we need this. Fallback is
134
- // modified to push all unresolved inference variables to
135
- // ty-err, but it's STILL possible to see fallback for
136
- // integral/float variables, because those cannot be unified
137
- // with ty-error.
138
- if
139
- fcx. infcx ( ) . is_tainted_by_errors ( ) &&
140
- ( self . cast_ty . has_infer_types ( ) || self . expr_ty . has_infer_types ( ) )
141
- {
142
- return ;
143
- }
144
-
145
145
match e {
146
146
CastError :: NeedViaPtr |
147
147
CastError :: NeedViaThinPtr |
@@ -205,6 +205,61 @@ impl<'tcx> CastCheck<'tcx> {
205
205
}
206
206
}
207
207
208
+ fn report_cast_to_unsized_type < ' a > ( & self ,
209
+ fcx : & FnCtxt < ' a , ' tcx > ) {
210
+ if
211
+ self . cast_ty . references_error ( ) ||
212
+ self . expr_ty . references_error ( )
213
+ {
214
+ return ;
215
+ }
216
+
217
+ let tstr = fcx. infcx ( ) . ty_to_string ( self . cast_ty ) ;
218
+ let mut err = fcx. type_error_struct ( self . span , |actual| {
219
+ format ! ( "cast to unsized type: `{}` as `{}`" , actual, tstr)
220
+ } , self . expr_ty , None ) ;
221
+ match self . expr_ty . sty {
222
+ ty:: TyRef ( _, ty:: TypeAndMut { mutbl : mt, .. } ) => {
223
+ let mtstr = match mt {
224
+ hir:: MutMutable => "mut " ,
225
+ hir:: MutImmutable => ""
226
+ } ;
227
+ if self . cast_ty . is_trait ( ) {
228
+ match fcx. tcx ( ) . sess . codemap ( ) . span_to_snippet ( self . cast_span ) {
229
+ Ok ( s) => {
230
+ err. span_suggestion ( self . cast_span ,
231
+ "try casting to a reference instead:" ,
232
+ format ! ( "&{}{}" , mtstr, s) ) ;
233
+ } ,
234
+ Err ( _) =>
235
+ span_help ! ( err, self . cast_span,
236
+ "did you mean `&{}{}`?" , mtstr, tstr) ,
237
+ }
238
+ } else {
239
+ span_help ! ( err, self . span,
240
+ "consider using an implicit coercion to `&{}{}` instead" ,
241
+ mtstr, tstr) ;
242
+ }
243
+ }
244
+ ty:: TyBox ( ..) => {
245
+ match fcx. tcx ( ) . sess . codemap ( ) . span_to_snippet ( self . cast_span ) {
246
+ Ok ( s) => {
247
+ err. span_suggestion ( self . cast_span ,
248
+ "try casting to a `Box` instead:" ,
249
+ format ! ( "Box<{}>" , s) ) ;
250
+ } ,
251
+ Err ( _) =>
252
+ span_help ! ( err, self . cast_span, "did you mean `Box<{}>`?" , tstr) ,
253
+ }
254
+ }
255
+ _ => {
256
+ span_help ! ( err, self . expr. span,
257
+ "consider using a box or reference as appropriate" ) ;
258
+ }
259
+ }
260
+ err. emit ( ) ;
261
+ }
262
+
208
263
fn trivial_cast_lint < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ) {
209
264
let t_cast = self . cast_ty ;
210
265
let t_expr = self . expr_ty ;
@@ -237,7 +292,9 @@ impl<'tcx> CastCheck<'tcx> {
237
292
debug ! ( "check_cast({}, {:?} as {:?})" , self . expr. id, self . expr_ty,
238
293
self . cast_ty) ;
239
294
240
- if self . expr_ty . references_error ( ) || self . cast_ty . references_error ( ) {
295
+ if !fcx. type_is_known_to_be_sized ( self . cast_ty , self . span ) {
296
+ self . report_cast_to_unsized_type ( fcx) ;
297
+ } else if self . expr_ty . references_error ( ) || self . cast_ty . references_error ( ) {
241
298
// No sense in giving duplicate error messages
242
299
} else if self . try_coercion_cast ( fcx) {
243
300
self . trivial_cast_lint ( fcx) ;
@@ -422,3 +479,17 @@ impl<'tcx> CastCheck<'tcx> {
422
479
}
423
480
424
481
}
482
+
483
+ impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
484
+ fn type_is_known_to_be_sized ( & self ,
485
+ ty : Ty < ' tcx > ,
486
+ span : Span )
487
+ -> bool
488
+ {
489
+ traits:: type_known_to_meet_builtin_bound ( self . infcx ( ) ,
490
+ ty,
491
+ ty:: BoundSized ,
492
+ span)
493
+ }
494
+ }
495
+
0 commit comments