@@ -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,37 +113,35 @@ 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, 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 ) ;
121137 }
138+
139+ Ok ( check)
122140 }
123141
124142 fn report_cast_error < ' a > ( & self ,
125143 fcx : & FnCtxt < ' a , ' tcx > ,
126144 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-
145145 match e {
146146 CastError :: NeedViaPtr |
147147 CastError :: NeedViaThinPtr |
@@ -205,6 +205,61 @@ impl<'tcx> CastCheck<'tcx> {
205205 }
206206 }
207207
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+
208263 fn trivial_cast_lint < ' a > ( & self , fcx : & FnCtxt < ' a , ' tcx > ) {
209264 let t_cast = self . cast_ty ;
210265 let t_expr = self . expr_ty ;
@@ -237,7 +292,9 @@ impl<'tcx> CastCheck<'tcx> {
237292 debug ! ( "check_cast({}, {:?} as {:?})" , self . expr. id, self . expr_ty,
238293 self . cast_ty) ;
239294
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 ( ) {
241298 // No sense in giving duplicate error messages
242299 } else if self . try_coercion_cast ( fcx) {
243300 self . trivial_cast_lint ( fcx) ;
@@ -422,3 +479,17 @@ impl<'tcx> CastCheck<'tcx> {
422479 }
423480
424481}
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