@@ -182,7 +182,8 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
182182/// if the program type checks or not -- and they are unusual
183183/// occurrences in any case.
184184pub 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 )
186187 -> !
187188 where T : fmt:: Display + TypeFoldable < ' tcx >
188189{
@@ -192,7 +193,9 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
192193 "overflow evaluating the requirement `{}`" ,
193194 predicate) ;
194195
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+ }
196199
197200 note_obligation_cause ( infcx, & mut err, obligation) ;
198201
@@ -201,6 +204,141 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
201204 unreachable ! ( ) ;
202205}
203206
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+
204342pub fn report_selection_error < ' a , ' tcx > ( infcx : & InferCtxt < ' a , ' tcx > ,
205343 obligation : & PredicateObligation < ' tcx > ,
206344 error : & SelectionError < ' tcx > )
0 commit comments