@@ -182,7 +182,8 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
182
182
/// if the program type checks or not -- and they are unusual
183
183
/// occurrences in any case.
184
184
pub fn report_overflow_error < ' a , ' tcx , T > ( infcx : & InferCtxt < ' a , ' tcx > ,
185
- obligation : & Obligation < ' tcx , T > )
185
+ obligation : & Obligation < ' tcx , T > ,
186
+ suggest_increasing_limit : bool )
186
187
-> !
187
188
where T : fmt:: Display + TypeFoldable < ' tcx >
188
189
{
@@ -192,7 +193,9 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
192
193
"overflow evaluating the requirement `{}`" ,
193
194
predicate) ;
194
195
195
- suggest_new_overflow_limit ( infcx. tcx , & mut err, obligation. cause . span ) ;
196
+ if suggest_increasing_limit {
197
+ suggest_new_overflow_limit ( infcx. tcx , & mut err, obligation. cause . span ) ;
198
+ }
196
199
197
200
note_obligation_cause ( infcx, & mut err, obligation) ;
198
201
@@ -201,6 +204,141 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
201
204
unreachable ! ( ) ;
202
205
}
203
206
207
+ /// Reports that a cycle was detected which led to overflow and halts
208
+ /// compilation. This is equivalent to `report_overflow_error` except
209
+ /// that we can give a more helpful error message (and, in particular,
210
+ /// we do not suggest increasing the overflow limit, which is not
211
+ /// going to help).
212
+ pub fn report_overflow_error_cycle < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
213
+ cycle : & Vec < PredicateObligation < ' tcx > > )
214
+ -> !
215
+ {
216
+ assert ! ( cycle. len( ) > 1 ) ;
217
+
218
+ debug ! ( "report_overflow_error_cycle(cycle length = {})" , cycle. len( ) ) ;
219
+
220
+ let cycle = infcx. resolve_type_vars_if_possible ( cycle) ;
221
+
222
+ debug ! ( "report_overflow_error_cycle: cycle={:?}" , cycle) ;
223
+
224
+ assert_eq ! ( & cycle[ 0 ] . predicate, & cycle. last( ) . unwrap( ) . predicate) ;
225
+
226
+ try_report_overflow_error_type_of_infinite_size ( infcx, & cycle) ;
227
+ report_overflow_error ( infcx, & cycle[ 0 ] , false ) ;
228
+ }
229
+
230
+ /// If a cycle results from evaluated whether something is Sized, that
231
+ /// is a particular special case that always results from a struct or
232
+ /// enum definition that lacks indirection (e.g., `struct Foo { x: Foo
233
+ /// }`). We wish to report a targeted error for this case.
234
+ pub fn try_report_overflow_error_type_of_infinite_size < ' a , ' tcx > (
235
+ infcx : & InferCtxt < ' a , ' tcx > ,
236
+ cycle : & [ PredicateObligation < ' tcx > ] )
237
+ {
238
+ let sized_trait = match infcx. tcx . lang_items . sized_trait ( ) {
239
+ Some ( v) => v,
240
+ None => return ,
241
+ } ;
242
+ let top_is_sized = {
243
+ match cycle[ 0 ] . predicate {
244
+ ty:: Predicate :: Trait ( ref data) => data. def_id ( ) == sized_trait,
245
+ _ => false ,
246
+ }
247
+ } ;
248
+ if !top_is_sized {
249
+ return ;
250
+ }
251
+
252
+ // The only way to have a type of infinite size is to have,
253
+ // somewhere, a struct/enum type involved. Identify all such types
254
+ // and report the cycle to the user.
255
+
256
+ let struct_enum_tys: Vec < _ > =
257
+ cycle. iter ( )
258
+ . flat_map ( |obligation| match obligation. predicate {
259
+ ty:: Predicate :: Trait ( ref data) => {
260
+ assert_eq ! ( data. def_id( ) , sized_trait) ;
261
+ let self_ty = data. skip_binder ( ) . trait_ref . self_ty ( ) ; // (*)
262
+ // (*) ok to skip binder because this is just
263
+ // error reporting and regions don't really
264
+ // matter
265
+ match self_ty. sty {
266
+ ty:: TyEnum ( ..) | ty:: TyStruct ( ..) => Some ( self_ty) ,
267
+ _ => None ,
268
+ }
269
+ }
270
+ _ => {
271
+ infcx. tcx . sess . span_bug ( obligation. cause . span ,
272
+ & format ! ( "Sized cycle involving non-trait-ref: {:?}" ,
273
+ obligation. predicate) ) ;
274
+ }
275
+ } )
276
+ . collect ( ) ;
277
+
278
+ assert ! ( !struct_enum_tys. is_empty( ) ) ;
279
+
280
+ // This is a bit tricky. We want to pick a "main type" in the
281
+ // listing that is local to the current crate, so we can give a
282
+ // good span to the user. But it might not be the first one in our
283
+ // cycle list. So find the first one that is local and then
284
+ // rotate.
285
+ let ( main_index, main_def_id) =
286
+ struct_enum_tys. iter ( )
287
+ . enumerate ( )
288
+ . filter_map ( |( index, ty) | match ty. sty {
289
+ ty:: TyEnum ( adt_def, _) | ty:: TyStruct ( adt_def, _) if adt_def. did . is_local ( ) =>
290
+ Some ( ( index, adt_def. did ) ) ,
291
+ _ =>
292
+ None ,
293
+ } )
294
+ . next ( )
295
+ . unwrap ( ) ; // should always be SOME local type involved!
296
+
297
+ // Rotate so that the "main" type is at index 0.
298
+ let struct_enum_tys: Vec < _ > =
299
+ struct_enum_tys. iter ( )
300
+ . cloned ( )
301
+ . skip ( main_index)
302
+ . chain ( struct_enum_tys. iter ( ) . cloned ( ) . take ( main_index) )
303
+ . collect ( ) ;
304
+
305
+ let tcx = infcx. tcx ;
306
+ let mut err = recursive_type_with_infinite_size_error ( tcx, main_def_id) ;
307
+ let len = struct_enum_tys. len ( ) ;
308
+ if len > 2 {
309
+ let span = tcx. map . span_if_local ( main_def_id) . unwrap ( ) ;
310
+ err. fileline_note ( span,
311
+ & format ! ( "type `{}` is embedded within `{}`..." ,
312
+ struct_enum_tys[ 0 ] ,
313
+ struct_enum_tys[ 1 ] ) ) ;
314
+ for & next_ty in & struct_enum_tys[ 1 ..len-1 ] {
315
+ err. fileline_note ( span,
316
+ & format ! ( "...which in turn is embedded within `{}`..." , next_ty) ) ;
317
+ }
318
+ err. fileline_note ( span,
319
+ & format ! ( "...which in turn is embedded within `{}`, \
320
+ completing the cycle.",
321
+ struct_enum_tys[ len-1 ] ) ) ;
322
+ }
323
+ err. emit ( ) ;
324
+ infcx. tcx . sess . abort_if_errors ( ) ;
325
+ unreachable ! ( ) ;
326
+ }
327
+
328
+ pub fn recursive_type_with_infinite_size_error < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
329
+ type_def_id : DefId )
330
+ -> DiagnosticBuilder < ' tcx >
331
+ {
332
+ assert ! ( type_def_id. is_local( ) ) ;
333
+ let span = tcx. map . span_if_local ( type_def_id) . unwrap ( ) ;
334
+ let mut err = struct_span_err ! ( tcx. sess, span, E0072 , "recursive type `{}` has infinite size" ,
335
+ tcx. item_path_str( type_def_id) ) ;
336
+ err. fileline_help ( span, & format ! ( "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
337
+ at some point to make `{}` representable",
338
+ tcx. item_path_str( type_def_id) ) ) ;
339
+ err
340
+ }
341
+
204
342
pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
205
343
obligation : & PredicateObligation < ' tcx > ,
206
344
error : & SelectionError < ' tcx > )
0 commit comments