@@ -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 {
@@ -420,27 +421,38 @@ fn record_accesses<'a, 'tcx: 'a>(
420421 inlining_map. lock_mut ( ) . record_accesses ( caller, & accesses) ;
421422}
422423
423- // Shrinks string by keeping prefix and suffix of given sizes.
424- fn shrink ( s : String , before : usize , after : usize ) -> String {
425- // An iterator of all byte positions including the end of the string.
426- let positions = || s. char_indices ( ) . map ( |( i, _) | i) . chain ( iter:: once ( s. len ( ) ) ) ;
427-
428- let shrunk = format ! (
429- "{before}...{after}" ,
430- before = & s[ ..positions( ) . nth( before) . unwrap_or( s. len( ) ) ] ,
431- after = & s[ positions( ) . rev( ) . nth( after) . unwrap_or( 0 ) ..] ,
432- ) ;
424+ /// Format instance name that is already known to be too long for rustc.
425+ /// Show only the first and last 32 characters to avoid blasting
426+ /// the user's terminal with thousands of lines of type-name.
427+ ///
428+ /// If the type name is longer than before+after, it will be written to a file.
429+ fn shrunk_instance_name (
430+ tcx : TyCtxt < ' tcx > ,
431+ instance : & Instance < ' tcx > ,
432+ before : usize ,
433+ after : usize ,
434+ ) -> ( String , Option < PathBuf > ) {
435+ let s = instance. to_string ( ) ;
433436
434437 // Only use the shrunk version if it's really shorter.
435438 // This also avoids the case where before and after slices overlap.
436- if shrunk. len ( ) < s. len ( ) { shrunk } else { s }
437- }
439+ if s. chars ( ) . nth ( before + after + 1 ) . is_some ( ) {
440+ // An iterator of all byte positions including the end of the string.
441+ let positions = || s. char_indices ( ) . map ( |( i, _) | i) . chain ( iter:: once ( s. len ( ) ) ) ;
442+
443+ let shrunk = format ! (
444+ "{before}...{after}" ,
445+ before = & s[ ..positions( ) . nth( before) . unwrap_or( s. len( ) ) ] ,
446+ after = & s[ positions( ) . rev( ) . nth( after) . unwrap_or( 0 ) ..] ,
447+ ) ;
448+
449+ let path = tcx. output_filenames ( LOCAL_CRATE ) . temp_path_ext ( "long-type.txt" , None ) ;
450+ let written_to_path = std:: fs:: write ( & path, s) . ok ( ) . map ( |_| path) ;
438451
439- // Format instance name that is already known to be too long for rustc.
440- // Show only the first and last 32 characters to avoid blasting
441- // the user's terminal with thousands of lines of type-name.
442- fn shrunk_instance_name ( instance : & Instance < ' tcx > ) -> String {
443- shrink ( instance. to_string ( ) , 32 , 32 )
452+ ( shrunk, written_to_path)
453+ } else {
454+ ( s, None )
455+ }
444456}
445457
446458fn check_recursion_limit < ' tcx > (
@@ -465,15 +477,16 @@ fn check_recursion_limit<'tcx>(
465477 // more than the recursion limit is assumed to be causing an
466478 // infinite expansion.
467479 if !tcx. sess . recursion_limit ( ) . value_within_limit ( adjusted_recursion_depth) {
468- let error = format ! (
469- "reached the recursion limit while instantiating `{}`" ,
470- shrunk_instance_name( & instance) ,
471- ) ;
480+ let ( shrunk, written_to_path) = shrunk_instance_name ( tcx, & instance, 32 , 32 ) ;
481+ let error = format ! ( "reached the recursion limit while instantiating `{}`" , shrunk) ;
472482 let mut err = tcx. sess . struct_span_fatal ( span, & error) ;
473483 err. span_note (
474484 tcx. def_span ( def_id) ,
475485 & format ! ( "`{}` defined here" , tcx. def_path_str( def_id) ) ,
476486 ) ;
487+ if let Some ( path) = written_to_path {
488+ err. note ( & format ! ( "the full type name has been written to '{}'" , path. display( ) ) ) ;
489+ }
477490 err. emit ( ) ;
478491 FatalError . raise ( ) ;
479492 }
@@ -502,12 +515,13 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
502515 //
503516 // Bail out in these cases to avoid that bad user experience.
504517 if !tcx. sess . type_length_limit ( ) . value_within_limit ( type_length) {
505- let msg = format ! (
506- "reached the type-length limit while instantiating `{}`" ,
507- shrunk_instance_name( & instance) ,
508- ) ;
518+ let ( shrunk, written_to_path) = shrunk_instance_name ( tcx, & instance, 32 , 32 ) ;
519+ let msg = format ! ( "reached the type-length limit while instantiating `{}`" , shrunk) ;
509520 let mut diag = tcx. sess . struct_span_fatal ( tcx. def_span ( instance. def_id ( ) ) , & msg) ;
510- diag. note ( & format ! (
521+ if let Some ( path) = written_to_path {
522+ diag. note ( & format ! ( "the full type name has been written to '{}'" , path. display( ) ) ) ;
523+ }
524+ diag. help ( & format ! (
511525 "consider adding a `#![type_length_limit=\" {}\" ]` attribute to your crate" ,
512526 type_length
513527 ) ) ;
0 commit comments