Skip to content

Commit dc1150a

Browse files
committed
trait_sel: print {Meta,Pointee}Sized impl headers
When printing impl headers in a diagnostic, the compiler has to account for `?Sized` implying `MetaSized` and new `MetaSized` and `PointeeSized` bounds.
1 parent e56c8f5 commit dc1150a

File tree

7 files changed

+186
-17
lines changed

7 files changed

+186
-17
lines changed

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

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
1111
use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
1212
use rustc_hir::def_id::{DefId, LocalDefId};
1313
use rustc_hir::intravisit::Visitor;
14-
use rustc_hir::{self as hir, AmbigArg, LangItem};
14+
use rustc_hir::{self as hir, AmbigArg};
1515
use rustc_infer::traits::{
1616
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
1717
PredicateObligation, SelectionError,
1818
};
1919
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
2020
use rustc_middle::ty::{self, Ty, TyCtxt};
2121
use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
22-
use tracing::{info, instrument};
22+
use tracing::{debug, info, instrument};
2323

2424
pub use self::overflow::*;
2525
use crate::error_reporting::TypeErrCtxt;
@@ -338,19 +338,26 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
338338
let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
339339
let mut w = "impl".to_owned();
340340

341-
let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
341+
#[derive(Debug, Default)]
342+
struct SizednessFound {
343+
sized: bool,
344+
metasized: bool,
345+
}
342346

343-
// FIXME: Currently only handles ?Sized.
344-
// Needs to support ?Move and ?DynSized when they are implemented.
345-
let mut types_without_default_bounds = FxIndexSet::default();
346-
let sized_trait = tcx.lang_items().sized_trait();
347+
let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
348+
349+
let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
347350

348351
let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
349352
if !arg_names.is_empty() {
350-
types_without_default_bounds.extend(args.types());
351353
w.push('<');
352354
w.push_str(&arg_names.join(", "));
353355
w.push('>');
356+
357+
for ty in args.types() {
358+
// `PointeeSized` params might have no predicates.
359+
types_with_sizedness_bounds.insert(ty, SizednessFound::default());
360+
}
354361
}
355362

356363
write!(
@@ -362,24 +369,48 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
362369
)
363370
.unwrap();
364371

365-
// The predicates will contain default bounds like `T: Sized`. We need to
366-
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
367372
let predicates = tcx.predicates_of(impl_def_id).predicates;
368-
let mut pretty_predicates =
369-
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
373+
let mut pretty_predicates = Vec::with_capacity(predicates.len());
374+
375+
let sized_trait = tcx.lang_items().sized_trait();
376+
let metasized_trait = tcx.lang_items().metasized_trait();
370377

371378
for (p, _) in predicates {
372-
if let Some(poly_trait_ref) = p.as_trait_clause() {
373-
if Some(poly_trait_ref.def_id()) == sized_trait {
374-
// FIXME(#120456) - is `swap_remove` correct?
375-
types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
379+
// Accumulate the sizedness bounds for each self ty.
380+
if let Some(trait_clause) = p.as_trait_clause() {
381+
let self_ty = trait_clause.self_ty().skip_binder();
382+
let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
383+
if Some(trait_clause.def_id()) == sized_trait {
384+
sizedness_of.sized = true;
385+
continue;
386+
} else if Some(trait_clause.def_id()) == metasized_trait {
387+
sizedness_of.metasized = true;
376388
continue;
377389
}
378390
}
391+
379392
pretty_predicates.push(p.to_string());
380393
}
381394

382-
pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
395+
for (ty, sizedness) in types_with_sizedness_bounds {
396+
debug!(?ty, ?sizedness);
397+
if !tcx.features().sized_hierarchy() {
398+
if sizedness.sized {
399+
// Maybe a default bound, don't write anything.
400+
} else {
401+
pretty_predicates.push(format!("{ty}: ?Sized"));
402+
}
403+
} else {
404+
if sizedness.sized {
405+
// Maybe a default bound, don't write anything.
406+
pretty_predicates.push(format!("{ty}: Sized"));
407+
} else if sizedness.metasized {
408+
pretty_predicates.push(format!("{ty}: MetaSized"));
409+
} else {
410+
pretty_predicates.push(format!("{ty}: PointeeSized"));
411+
}
412+
}
413+
}
383414

384415
if !pretty_predicates.is_empty() {
385416
write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(sized_hierarchy)]
2+
3+
use std::marker::{MetaSized, PointeeSized};
4+
5+
pub trait SizedTr {}
6+
7+
impl<T: Sized> SizedTr for T {}
8+
9+
pub trait NegSizedTr {}
10+
11+
impl<T: ?Sized> NegSizedTr for T {}
12+
13+
pub trait MetaSizedTr {}
14+
15+
impl<T: MetaSized> MetaSizedTr for T {}
16+
17+
pub trait PointeeSizedTr: PointeeSized {}
18+
19+
impl<T: PointeeSized> PointeeSizedTr for T {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pub trait SizedTr {}
2+
3+
impl<T: Sized> SizedTr for T {}
4+
5+
pub trait NegSizedTr {}
6+
7+
impl<T: ?Sized> NegSizedTr for T {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ aux-build:pretty-print-no-feat-dep.rs
2+
//@ compile-flags: --crate-type=lib
3+
4+
extern crate pretty_print_no_feat_dep;
5+
use pretty_print_no_feat_dep::{SizedTr, NegSizedTr};
6+
7+
// Test that printing the sizedness trait bounds in the conflicting impl error without enabling
8+
// `sized_hierarchy` will continue to print `?Sized`.
9+
//
10+
// It isn't possible to write a test that matches the multiline note containing the important
11+
// diagnostic output being tested - so check the stderr changes carefully!
12+
13+
struct X<T>(T);
14+
15+
impl<T: Sized> SizedTr for X<T> {}
16+
//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
17+
18+
impl<T: ?Sized> NegSizedTr for X<T> {}
19+
//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
2+
--> $DIR/pretty-print-no-feat.rs:15:1
3+
|
4+
LL | impl<T: Sized> SizedTr for X<T> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: conflicting implementation in crate `pretty_print_no_feat_dep`:
8+
- impl<T> SizedTr for T;
9+
10+
error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
11+
--> $DIR/pretty-print-no-feat.rs:18:1
12+
|
13+
LL | impl<T: ?Sized> NegSizedTr for X<T> {}
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= note: conflicting implementation in crate `pretty_print_no_feat_dep`:
17+
- impl<T> NegSizedTr for T
18+
where T: ?Sized;
19+
20+
error: aborting due to 2 previous errors
21+
22+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ aux-build:pretty-print-dep.rs
2+
//@ compile-flags: --crate-type=lib
3+
#![feature(sized_hierarchy)]
4+
5+
// Test that printing the sizedness trait bounds in the conflicting impl error with
6+
// `sized_hierarchy` enabled prints all of the appropriate bounds.
7+
//
8+
// It isn't possible to write a test that matches the multiline note containing the important
9+
// diagnostic output being tested - so check the stderr changes carefully!
10+
11+
use std::marker::{MetaSized, PointeeSized};
12+
13+
extern crate pretty_print_dep;
14+
use pretty_print_dep::{SizedTr, MetaSizedTr, PointeeSizedTr};
15+
16+
struct X<T>(T);
17+
18+
impl<T: Sized> SizedTr for X<T> {}
19+
//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
20+
21+
impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
22+
//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
23+
24+
impl<T: MetaSized> MetaSizedTr for X<T> {}
25+
//~^ ERROR conflicting implementations of trait `MetaSizedTr` for type `X<_>`
26+
27+
impl<T: PointeeSized> PointeeSizedTr for X<T> {}
28+
//~^ ERROR conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
2+
--> $DIR/pretty-print.rs:18:1
3+
|
4+
LL | impl<T: Sized> SizedTr for X<T> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: conflicting implementation in crate `pretty_print_dep`:
8+
- impl<T> SizedTr for T
9+
where T: Sized;
10+
11+
error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
12+
--> $DIR/pretty-print.rs:21:1
13+
|
14+
LL | impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
|
17+
= note: conflicting implementation in crate `pretty_print_dep`:
18+
- impl<T> NegSizedTr for T
19+
where T: MetaSized;
20+
21+
error[E0119]: conflicting implementations of trait `MetaSizedTr` for type `X<_>`
22+
--> $DIR/pretty-print.rs:24:1
23+
|
24+
LL | impl<T: MetaSized> MetaSizedTr for X<T> {}
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: conflicting implementation in crate `pretty_print_dep`:
28+
- impl<T> MetaSizedTr for T
29+
where T: MetaSized;
30+
31+
error[E0119]: conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
32+
--> $DIR/pretty-print.rs:27:1
33+
|
34+
LL | impl<T: PointeeSized> PointeeSizedTr for X<T> {}
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
|
37+
= note: conflicting implementation in crate `pretty_print_dep`:
38+
- impl<T> PointeeSizedTr for T
39+
where T: PointeeSized;
40+
41+
error: aborting due to 4 previous errors
42+
43+
For more information about this error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)