Skip to content

Commit 06707c0

Browse files
authored
Rollup merge of #104469 - estebank:long-types, r=oli-obk
Make "long type" printing type aware and trim types in E0275 Instead of simple string cutting, use a custom printer to hide parts of long printed types. On E0275, check for type length before printing.
2 parents d6298d3 + bcb2655 commit 06707c0

24 files changed

+208
-97
lines changed

compiler/rustc_middle/src/ty/error.rs

+37
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ use rustc_span::{BytePos, Span};
1212
use rustc_target::spec::abi;
1313

1414
use std::borrow::Cow;
15+
use std::collections::hash_map::DefaultHasher;
1516
use std::fmt;
17+
use std::hash::{Hash, Hasher};
18+
use std::path::PathBuf;
19+
20+
use super::print::PrettyPrinter;
1621

1722
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
1823
pub struct ExpectedFound<T> {
@@ -985,6 +990,38 @@ fn foo(&self) -> Self::T { String::new() }
985990
false
986991
}
987992

993+
pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
994+
let length_limit = 50;
995+
let type_limit = 4;
996+
let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
997+
.pretty_print_type(ty)
998+
.expect("could not write to `String`")
999+
.into_buffer();
1000+
if regular.len() <= length_limit {
1001+
return (regular, None);
1002+
}
1003+
let short = FmtPrinter::new_with_limit(
1004+
self,
1005+
hir::def::Namespace::TypeNS,
1006+
rustc_session::Limit(type_limit),
1007+
)
1008+
.pretty_print_type(ty)
1009+
.expect("could not write to `String`")
1010+
.into_buffer();
1011+
if regular == short {
1012+
return (regular, None);
1013+
}
1014+
// Multiple types might be shortened in a single error, ensure we create a file for each.
1015+
let mut s = DefaultHasher::new();
1016+
ty.hash(&mut s);
1017+
let hash = s.finish();
1018+
let path = self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None);
1019+
match std::fs::write(&path, &regular) {
1020+
Ok(_) => (short, Some(path)),
1021+
Err(_) => (regular, None),
1022+
}
1023+
}
1024+
9881025
fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
9891026
FmtPrinter::new(self, hir::def::Namespace::TypeNS)
9901027
.path_generic_args(Ok, args)

compiler/rustc_middle/src/ty/instance.rs

+37-20
Original file line numberDiff line numberDiff line change
@@ -276,28 +276,45 @@ impl<'tcx> InstanceDef<'tcx> {
276276
}
277277
}
278278

279-
impl<'tcx> fmt::Display for Instance<'tcx> {
279+
fn fmt_instance(
280+
f: &mut fmt::Formatter<'_>,
281+
instance: &Instance<'_>,
282+
type_length: rustc_session::Limit,
283+
) -> fmt::Result {
284+
ty::tls::with(|tcx| {
285+
let substs = tcx.lift(instance.substs).expect("could not lift for printing");
286+
287+
let s = FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length)
288+
.print_def_path(instance.def_id(), substs)?
289+
.into_buffer();
290+
f.write_str(&s)
291+
})?;
292+
293+
match instance.def {
294+
InstanceDef::Item(_) => Ok(()),
295+
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
296+
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
297+
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
298+
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
299+
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),
300+
InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
301+
InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
302+
InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty),
303+
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty),
304+
}
305+
}
306+
307+
pub struct ShortInstance<'a, 'tcx>(pub &'a Instance<'tcx>, pub usize);
308+
309+
impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> {
280310
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281-
ty::tls::with(|tcx| {
282-
let substs = tcx.lift(self.substs).expect("could not lift for printing");
283-
let s = FmtPrinter::new(tcx, Namespace::ValueNS)
284-
.print_def_path(self.def_id(), substs)?
285-
.into_buffer();
286-
f.write_str(&s)
287-
})?;
311+
fmt_instance(f, self.0, rustc_session::Limit(self.1))
312+
}
313+
}
288314

289-
match self.def {
290-
InstanceDef::Item(_) => Ok(()),
291-
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
292-
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
293-
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
294-
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
295-
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),
296-
InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
297-
InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"),
298-
InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty),
299-
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty),
300-
}
315+
impl<'tcx> fmt::Display for Instance<'tcx> {
316+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317+
ty::tls::with(|tcx| fmt_instance(f, self, tcx.type_length_limit()))
301318
}
302319
}
303320

compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub use self::context::{
8484
GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
8585
UserTypeAnnotationIndex,
8686
};
87-
pub use self::instance::{Instance, InstanceDef};
87+
pub use self::instance::{Instance, InstanceDef, ShortInstance};
8888
pub use self::list::List;
8989
pub use self::parameterized::ParameterizedOverTcx;
9090
pub use self::rvalue_scopes::RvalueScopes;

compiler/rustc_middle/src/ty/print/pretty.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
1313
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
1414
use rustc_session::config::TrimmedDefPaths;
1515
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
16+
use rustc_session::Limit;
1617
use rustc_span::symbol::{kw, Ident, Symbol};
1718
use rustc_target::abi::Size;
1819
use rustc_target::spec::abi::Abi;
@@ -1583,6 +1584,8 @@ pub struct FmtPrinterData<'a, 'tcx> {
15831584
region_index: usize,
15841585
binder_depth: usize,
15851586
printed_type_count: usize,
1587+
type_length_limit: Limit,
1588+
truncated: bool,
15861589

15871590
pub region_highlight_mode: RegionHighlightMode<'tcx>,
15881591

@@ -1605,6 +1608,10 @@ impl DerefMut for FmtPrinter<'_, '_> {
16051608

16061609
impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
16071610
pub fn new(tcx: TyCtxt<'tcx>, ns: Namespace) -> Self {
1611+
Self::new_with_limit(tcx, ns, tcx.type_length_limit())
1612+
}
1613+
1614+
pub fn new_with_limit(tcx: TyCtxt<'tcx>, ns: Namespace, type_length_limit: Limit) -> Self {
16081615
FmtPrinter(Box::new(FmtPrinterData {
16091616
tcx,
16101617
// Estimated reasonable capacity to allocate upfront based on a few
@@ -1617,6 +1624,8 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
16171624
region_index: 0,
16181625
binder_depth: 0,
16191626
printed_type_count: 0,
1627+
type_length_limit,
1628+
truncated: false,
16201629
region_highlight_mode: RegionHighlightMode::new(tcx),
16211630
ty_infer_name_resolver: None,
16221631
const_infer_name_resolver: None,
@@ -1751,11 +1760,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
17511760
}
17521761

17531762
fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
1754-
let type_length_limit = self.tcx.type_length_limit();
1755-
if type_length_limit.value_within_limit(self.printed_type_count) {
1763+
if self.type_length_limit.value_within_limit(self.printed_type_count) {
17561764
self.printed_type_count += 1;
17571765
self.pretty_print_type(ty)
17581766
} else {
1767+
self.truncated = true;
17591768
write!(self, "...")?;
17601769
Ok(self)
17611770
}

compiler/rustc_monomorphize/src/collector.rs

+8-15
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
197197
use rustc_session::Limit;
198198
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
199199
use rustc_target::abi::Size;
200-
use std::iter;
201200
use std::ops::Range;
202201
use std::path::PathBuf;
203202

@@ -541,29 +540,23 @@ fn collect_items_rec<'tcx>(
541540
}
542541

543542
/// Format instance name that is already known to be too long for rustc.
544-
/// Show only the first and last 32 characters to avoid blasting
543+
/// Show only the first 2 types if it is longer than 32 characters to avoid blasting
545544
/// the user's terminal with thousands of lines of type-name.
546545
///
547546
/// If the type name is longer than before+after, it will be written to a file.
548547
fn shrunk_instance_name<'tcx>(
549548
tcx: TyCtxt<'tcx>,
550549
instance: &Instance<'tcx>,
551-
before: usize,
552-
after: usize,
553550
) -> (String, Option<PathBuf>) {
554551
let s = instance.to_string();
555552

556553
// Only use the shrunk version if it's really shorter.
557554
// This also avoids the case where before and after slices overlap.
558-
if s.chars().nth(before + after + 1).is_some() {
559-
// An iterator of all byte positions including the end of the string.
560-
let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len()));
561-
562-
let shrunk = format!(
563-
"{before}...{after}",
564-
before = &s[..positions().nth(before).unwrap_or(s.len())],
565-
after = &s[positions().rev().nth(after).unwrap_or(0)..],
566-
);
555+
if s.chars().nth(33).is_some() {
556+
let shrunk = format!("{}", ty::ShortInstance(instance, 4));
557+
if shrunk == s {
558+
return (s, None);
559+
}
567560

568561
let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None);
569562
let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
@@ -599,7 +592,7 @@ fn check_recursion_limit<'tcx>(
599592
if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
600593
let def_span = tcx.def_span(def_id);
601594
let def_path_str = tcx.def_path_str(def_id);
602-
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
595+
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
603596
let mut path = PathBuf::new();
604597
let was_written = if written_to_path.is_some() {
605598
path = written_to_path.unwrap();
@@ -641,7 +634,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
641634
//
642635
// Bail out in these cases to avoid that bad user experience.
643636
if !tcx.type_length_limit().value_within_limit(type_length) {
644-
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
637+
let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
645638
let span = tcx.def_span(instance.def_id());
646639
let mut path = PathBuf::new();
647640
let was_written = if written_to_path.is_some() {

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_errors::{
2222
MultiSpan, Style,
2323
};
2424
use rustc_hir as hir;
25+
use rustc_hir::def::Namespace;
2526
use rustc_hir::def_id::DefId;
2627
use rustc_hir::intravisit::Visitor;
2728
use rustc_hir::GenericParam;
@@ -34,6 +35,7 @@ use rustc_middle::traits::select::OverflowError;
3435
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
3536
use rustc_middle::ty::error::ExpectedFound;
3637
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
38+
use rustc_middle::ty::print::{FmtPrinter, Print};
3739
use rustc_middle::ty::{
3840
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
3941
TypeVisitable,
@@ -109,7 +111,10 @@ pub trait TypeErrCtxtExt<'tcx> {
109111
suggest_increasing_limit: bool,
110112
) -> !
111113
where
112-
T: fmt::Display + TypeFoldable<'tcx>;
114+
T: fmt::Display
115+
+ TypeFoldable<'tcx>
116+
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
117+
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
113118

114119
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
115120

@@ -468,15 +473,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
468473
suggest_increasing_limit: bool,
469474
) -> !
470475
where
471-
T: fmt::Display + TypeFoldable<'tcx>,
476+
T: fmt::Display
477+
+ TypeFoldable<'tcx>
478+
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
479+
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
472480
{
473481
let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
482+
let mut pred_str = predicate.to_string();
483+
if pred_str.len() > 50 {
484+
// We don't need to save the type to a file, we will be talking about this type already
485+
// in a separate note when we explain the obligation, so it will be available that way.
486+
pred_str = predicate
487+
.print(FmtPrinter::new_with_limit(
488+
self.tcx,
489+
Namespace::TypeNS,
490+
rustc_session::Limit(6),
491+
))
492+
.unwrap()
493+
.into_buffer();
494+
}
474495
let mut err = struct_span_err!(
475496
self.tcx.sess,
476497
obligation.cause.span,
477498
E0275,
478499
"overflow evaluating the requirement `{}`",
479-
predicate
500+
pred_str,
480501
);
481502

482503
if suggest_increasing_limit {

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -2733,9 +2733,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
27332733
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
27342734
parent_trait_pred.remap_constness_diag(param_env);
27352735
let parent_def_id = parent_trait_pred.def_id();
2736+
let (self_ty, file) =
2737+
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
27362738
let msg = format!(
2737-
"required for `{}` to implement `{}`",
2738-
parent_trait_pred.skip_binder().self_ty(),
2739+
"required for `{self_ty}` to implement `{}`",
27392740
parent_trait_pred.print_modifiers_and_trait_path()
27402741
);
27412742
let mut is_auto_trait = false;
@@ -2764,6 +2765,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
27642765
_ => err.note(&msg),
27652766
};
27662767

2768+
if let Some(file) = file {
2769+
err.note(&format!(
2770+
"the full type name has been written to '{}'",
2771+
file.display(),
2772+
));
2773+
}
27672774
let mut parent_predicate = parent_trait_pred;
27682775
let mut data = &data.derived;
27692776
let mut count = 0;
@@ -2804,11 +2811,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
28042811
count,
28052812
pluralize!(count)
28062813
));
2814+
let (self_ty, file) =
2815+
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
28072816
err.note(&format!(
2808-
"required for `{}` to implement `{}`",
2809-
parent_trait_pred.skip_binder().self_ty(),
2817+
"required for `{self_ty}` to implement `{}`",
28102818
parent_trait_pred.print_modifiers_and_trait_path()
28112819
));
2820+
if let Some(file) = file {
2821+
err.note(&format!(
2822+
"the full type name has been written to '{}'",
2823+
file.display(),
2824+
));
2825+
}
28122826
}
28132827
// #74711: avoid a stack overflow
28142828
ensure_sufficient_stack(|| {

compiler/rustc_trait_selection/src/traits/select/mod.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
4242
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
4343
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
4444
use rustc_middle::ty::fold::BottomUpFolder;
45+
use rustc_middle::ty::print::{FmtPrinter, Print};
4546
use rustc_middle::ty::relate::TypeRelation;
4647
use rustc_middle::ty::SubstsRef;
4748
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
@@ -1081,11 +1082,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10811082
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
10821083
}
10831084

1084-
fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>(
1085+
fn check_recursion_depth<T>(
10851086
&self,
10861087
depth: usize,
10871088
error_obligation: &Obligation<'tcx, T>,
1088-
) -> Result<(), OverflowError> {
1089+
) -> Result<(), OverflowError>
1090+
where
1091+
T: fmt::Display
1092+
+ TypeFoldable<'tcx>
1093+
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
1094+
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
1095+
{
10891096
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
10901097
match self.query_mode {
10911098
TraitQueryMode::Standard => {
@@ -1107,11 +1114,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11071114
/// The weird return type of this function allows it to be used with the `try` (`?`)
11081115
/// operator within certain functions.
11091116
#[inline(always)]
1110-
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
1117+
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V>(
11111118
&self,
11121119
obligation: &Obligation<'tcx, T>,
11131120
error_obligation: &Obligation<'tcx, V>,
1114-
) -> Result<(), OverflowError> {
1121+
) -> Result<(), OverflowError>
1122+
where
1123+
V: fmt::Display
1124+
+ TypeFoldable<'tcx>
1125+
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
1126+
<V as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
1127+
{
11151128
self.check_recursion_depth(obligation.recursion_depth, error_obligation)
11161129
}
11171130

0 commit comments

Comments
 (0)