@@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
197197use rustc_span:: source_map:: { dummy_spanned, respan, Span , Spanned , DUMMY_SP } ;
198198use smallvec:: SmallVec ;
199199use std:: iter;
200+ use std:: path:: PathBuf ;
200201
201202#[ derive( PartialEq ) ]
202203pub enum MonoItemCollectionMode {
@@ -418,27 +419,38 @@ fn record_accesses<'a, 'tcx: 'a>(
418419 inlining_map. lock_mut ( ) . record_accesses ( caller, & accesses) ;
419420}
420421
421- // Shrinks string by keeping prefix and suffix of given sizes.
422- fn shrink ( s : String , before : usize , after : usize ) -> String {
423- // An iterator of all byte positions including the end of the string.
424- let positions = || s. char_indices ( ) . map ( |( i, _) | i) . chain ( iter:: once ( s. len ( ) ) ) ;
425-
426- let shrunk = format ! (
427- "{before}...{after}" ,
428- before = & s[ ..positions( ) . nth( before) . unwrap_or( s. len( ) ) ] ,
429- after = & s[ positions( ) . rev( ) . nth( after) . unwrap_or( 0 ) ..] ,
430- ) ;
422+ /// Format instance name that is already known to be too long for rustc.
423+ /// Show only the first and last 32 characters to avoid blasting
424+ /// the user's terminal with thousands of lines of type-name.
425+ ///
426+ /// If the type name is longer than before+after, it will be written to a file.
427+ fn shrunk_instance_name (
428+ tcx : TyCtxt < ' tcx > ,
429+ instance : & Instance < ' tcx > ,
430+ before : usize ,
431+ after : usize ,
432+ ) -> ( String , Option < PathBuf > ) {
433+ let s = instance. to_string ( ) ;
431434
432435 // Only use the shrunk version if it's really shorter.
433436 // This also avoids the case where before and after slices overlap.
434- if shrunk. len ( ) < s. len ( ) { shrunk } else { s }
435- }
437+ if s. chars ( ) . nth ( before + after + 1 ) . is_some ( ) {
438+ // An iterator of all byte positions including the end of the string.
439+ let positions = || s. char_indices ( ) . map ( |( i, _) | i) . chain ( iter:: once ( s. len ( ) ) ) ;
440+
441+ let shrunk = format ! (
442+ "{before}...{after}" ,
443+ before = & s[ ..positions( ) . nth( before) . unwrap_or( s. len( ) ) ] ,
444+ after = & s[ positions( ) . rev( ) . nth( after) . unwrap_or( 0 ) ..] ,
445+ ) ;
446+
447+ let path = tcx. output_filenames ( LOCAL_CRATE ) . temp_path_ext ( "long-type.txt" , None ) ;
448+ let written_to_path = std:: fs:: write ( & path, s) . ok ( ) . map ( |_| path) ;
436449
437- // Format instance name that is already known to be too long for rustc.
438- // Show only the first and last 32 characters to avoid blasting
439- // the user's terminal with thousands of lines of type-name.
440- fn shrunk_instance_name ( instance : & Instance < ' tcx > ) -> String {
441- shrink ( instance. to_string ( ) , 32 , 32 )
450+ ( shrunk, written_to_path)
451+ } else {
452+ ( s, None )
453+ }
442454}
443455
444456fn check_recursion_limit < ' tcx > (
@@ -463,15 +475,16 @@ fn check_recursion_limit<'tcx>(
463475 // more than the recursion limit is assumed to be causing an
464476 // infinite expansion.
465477 if !tcx. sess . recursion_limit ( ) . value_within_limit ( adjusted_recursion_depth) {
466- let error = format ! (
467- "reached the recursion limit while instantiating `{}`" ,
468- shrunk_instance_name( & instance) ,
469- ) ;
478+ let ( shrunk, written_to_path) = shrunk_instance_name ( tcx, & instance, 32 , 32 ) ;
479+ let error = format ! ( "reached the recursion limit while instantiating `{}`" , shrunk) ;
470480 let mut err = tcx. sess . struct_span_fatal ( span, & error) ;
471481 err. span_note (
472482 tcx. def_span ( def_id) ,
473483 & format ! ( "`{}` defined here" , tcx. def_path_str( def_id) ) ,
474484 ) ;
485+ if let Some ( path) = written_to_path {
486+ err. note ( & format ! ( "the full type name has been written to '{}'" , path. display( ) ) ) ;
487+ }
475488 err. emit ( ) ;
476489 FatalError . raise ( ) ;
477490 }
@@ -500,12 +513,13 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
500513 //
501514 // Bail out in these cases to avoid that bad user experience.
502515 if !tcx. sess . type_length_limit ( ) . value_within_limit ( type_length) {
503- let msg = format ! (
504- "reached the type-length limit while instantiating `{}`" ,
505- shrunk_instance_name( & instance) ,
506- ) ;
516+ let ( shrunk, written_to_path) = shrunk_instance_name ( tcx, & instance, 32 , 32 ) ;
517+ let msg = format ! ( "reached the type-length limit while instantiating `{}`" , shrunk) ;
507518 let mut diag = tcx. sess . struct_span_fatal ( tcx. def_span ( instance. def_id ( ) ) , & msg) ;
508- diag. note ( & format ! (
519+ if let Some ( path) = written_to_path {
520+ diag. note ( & format ! ( "the full type name has been written to '{}'" , path. display( ) ) ) ;
521+ }
522+ diag. help ( & format ! (
509523 "consider adding a `#![type_length_limit=\" {}\" ]` attribute to your crate" ,
510524 type_length
511525 ) ) ;
0 commit comments