Skip to content

Commit 9044b78

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 e6238ba commit 9044b78

File tree

9 files changed

+252
-16
lines changed

9 files changed

+252
-16
lines changed

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

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
1313
use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
1414
use rustc_hir::def_id::{DefId, LocalDefId};
1515
use rustc_hir::intravisit::Visitor;
16-
use rustc_hir::{self as hir, AmbigArg, LangItem};
16+
use rustc_hir::{self as hir, AmbigArg};
1717
use rustc_infer::traits::solve::Goal;
1818
use rustc_infer::traits::{
1919
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
@@ -334,19 +334,26 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
334334
let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
335335
let mut w = "impl".to_owned();
336336

337-
let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
337+
#[derive(Debug, Default)]
338+
struct SizednessFound {
339+
sized: bool,
340+
meta_sized: bool,
341+
}
338342

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

344347
let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
345348
if !arg_names.is_empty() {
346-
types_without_default_bounds.extend(args.types());
347349
w.push('<');
348350
w.push_str(&arg_names.join(", "));
349351
w.push('>');
352+
353+
for ty in args.types() {
354+
// `PointeeSized` params might have no predicates.
355+
types_with_sizedness_bounds.insert(ty, SizednessFound::default());
356+
}
350357
}
351358

352359
write!(
@@ -358,24 +365,47 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
358365
)
359366
.unwrap();
360367

361-
// The predicates will contain default bounds like `T: Sized`. We need to
362-
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
363368
let predicates = tcx.predicates_of(impl_def_id).predicates;
364-
let mut pretty_predicates =
365-
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
369+
let mut pretty_predicates = Vec::with_capacity(predicates.len());
370+
371+
let sized_trait = tcx.lang_items().sized_trait();
372+
let meta_sized_trait = tcx.lang_items().meta_sized_trait();
366373

367374
for (p, _) in predicates {
368-
if let Some(poly_trait_ref) = p.as_trait_clause() {
369-
if Some(poly_trait_ref.def_id()) == sized_trait {
370-
// FIXME(#120456) - is `swap_remove` correct?
371-
types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
375+
// Accumulate the sizedness bounds for each self ty.
376+
if let Some(trait_clause) = p.as_trait_clause() {
377+
let self_ty = trait_clause.self_ty().skip_binder();
378+
let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
379+
if Some(trait_clause.def_id()) == sized_trait {
380+
sizedness_of.sized = true;
381+
continue;
382+
} else if Some(trait_clause.def_id()) == meta_sized_trait {
383+
sizedness_of.meta_sized = true;
372384
continue;
373385
}
374386
}
387+
375388
pretty_predicates.push(p.to_string());
376389
}
377390

378-
pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
391+
for (ty, sizedness) in types_with_sizedness_bounds {
392+
if !tcx.features().sized_hierarchy() {
393+
if sizedness.sized {
394+
// Maybe a default bound, don't write anything.
395+
} else {
396+
pretty_predicates.push(format!("{ty}: ?Sized"));
397+
}
398+
} else {
399+
if sizedness.sized {
400+
// Maybe a default bound, don't write anything.
401+
pretty_predicates.push(format!("{ty}: Sized"));
402+
} else if sizedness.meta_sized {
403+
pretty_predicates.push(format!("{ty}: MetaSized"));
404+
} else {
405+
pretty_predicates.push(format!("{ty}: PointeeSized"));
406+
}
407+
}
408+
}
379409

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