Skip to content

Commit d9622a8

Browse files
authored
Rollup merge of rust-lang#98371 - compiler-errors:better-opaque-printing, r=oli-obk
Fix printing `impl trait` under binders Before, we would render `impl for<'a> Trait<'a>` like `impl Trait<for<'a> 'a>`, lol.
2 parents d6d97ca + e80cced commit d9622a8

File tree

4 files changed

+166
-114
lines changed

4 files changed

+166
-114
lines changed

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

+120-113
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ pub trait PrettyPrinter<'tcx>:
226226
value.as_ref().skip_binder().print(self)
227227
}
228228

229-
fn wrap_binder<T, F: Fn(&T, Self) -> Result<Self, fmt::Error>>(
229+
fn wrap_binder<T, F: FnOnce(&T, Self) -> Result<Self, fmt::Error>>(
230230
self,
231231
value: &ty::Binder<'tcx, T>,
232232
f: F,
@@ -773,26 +773,26 @@ pub trait PrettyPrinter<'tcx>:
773773
def_id: DefId,
774774
substs: &'tcx ty::List<ty::GenericArg<'tcx>>,
775775
) -> Result<Self::Type, Self::Error> {
776-
define_scoped_cx!(self);
776+
let tcx = self.tcx();
777777

778778
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
779779
// by looking up the projections associated with the def_id.
780-
let bounds = self.tcx().bound_explicit_item_bounds(def_id);
780+
let bounds = tcx.bound_explicit_item_bounds(def_id);
781781

782782
let mut traits = FxIndexMap::default();
783783
let mut fn_traits = FxIndexMap::default();
784784
let mut is_sized = false;
785785

786786
for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
787-
let predicate = predicate.subst(self.tcx(), substs);
787+
let predicate = predicate.subst(tcx, substs);
788788
let bound_predicate = predicate.kind();
789789

790790
match bound_predicate.skip_binder() {
791791
ty::PredicateKind::Trait(pred) => {
792792
let trait_ref = bound_predicate.rebind(pred.trait_ref);
793793

794794
// Don't print + Sized, but rather + ?Sized if absent.
795-
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
795+
if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
796796
is_sized = true;
797797
continue;
798798
}
@@ -801,7 +801,7 @@ pub trait PrettyPrinter<'tcx>:
801801
}
802802
ty::PredicateKind::Projection(pred) => {
803803
let proj_ref = bound_predicate.rebind(pred);
804-
let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
804+
let trait_ref = proj_ref.required_poly_trait_ref(tcx);
805805

806806
// Projection type entry -- the def-id for naming, and the ty.
807807
let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
@@ -817,148 +817,155 @@ pub trait PrettyPrinter<'tcx>:
817817
}
818818
}
819819

820+
write!(self, "impl ")?;
821+
820822
let mut first = true;
821823
// Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
822824
let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
823825

824-
p!("impl");
825-
826826
for (fn_once_trait_ref, entry) in fn_traits {
827-
// Get the (single) generic ty (the args) of this FnOnce trait ref.
828-
let generics = self.tcx().generics_of(fn_once_trait_ref.def_id());
829-
let args =
830-
generics.own_substs_no_defaults(self.tcx(), fn_once_trait_ref.skip_binder().substs);
831-
832-
match (entry.return_ty, args[0].expect_ty()) {
833-
// We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
834-
// a return type.
835-
(Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
836-
let name = if entry.fn_trait_ref.is_some() {
837-
"Fn"
838-
} else if entry.fn_mut_trait_ref.is_some() {
839-
"FnMut"
840-
} else {
841-
"FnOnce"
842-
};
827+
write!(self, "{}", if first { "" } else { " + " })?;
828+
write!(self, "{}", if paren_needed { "(" } else { "" })?;
843829

844-
p!(
845-
write("{}", if first { " " } else { " + " }),
846-
write("{}{}(", if paren_needed { "(" } else { "" }, name)
847-
);
830+
self = self.wrap_binder(&fn_once_trait_ref, |trait_ref, mut cx| {
831+
define_scoped_cx!(cx);
832+
// Get the (single) generic ty (the args) of this FnOnce trait ref.
833+
let generics = tcx.generics_of(trait_ref.def_id);
834+
let args = generics.own_substs_no_defaults(tcx, trait_ref.substs);
835+
836+
match (entry.return_ty, args[0].expect_ty()) {
837+
// We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
838+
// a return type.
839+
(Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
840+
let name = if entry.fn_trait_ref.is_some() {
841+
"Fn"
842+
} else if entry.fn_mut_trait_ref.is_some() {
843+
"FnMut"
844+
} else {
845+
"FnOnce"
846+
};
848847

849-
for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
850-
if idx > 0 {
851-
p!(", ");
848+
p!(write("{}(", name));
849+
850+
for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
851+
if idx > 0 {
852+
p!(", ");
853+
}
854+
p!(print(ty));
852855
}
853-
p!(print(ty));
854-
}
855856

856-
p!(")");
857-
if let Term::Ty(ty) = return_ty.skip_binder() {
858-
if !ty.is_unit() {
859-
p!(" -> ", print(return_ty));
857+
p!(")");
858+
if let Term::Ty(ty) = return_ty.skip_binder() {
859+
if !ty.is_unit() {
860+
p!(" -> ", print(return_ty));
861+
}
860862
}
861-
}
862-
p!(write("{}", if paren_needed { ")" } else { "" }));
863+
p!(write("{}", if paren_needed { ")" } else { "" }));
863864

864-
first = false;
865-
}
866-
// If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
867-
// trait_refs we collected in the OpaqueFnEntry as normal trait refs.
868-
_ => {
869-
if entry.has_fn_once {
870-
traits.entry(fn_once_trait_ref).or_default().extend(
871-
// Group the return ty with its def id, if we had one.
872-
entry
873-
.return_ty
874-
.map(|ty| (self.tcx().lang_items().fn_once_output().unwrap(), ty)),
875-
);
876-
}
877-
if let Some(trait_ref) = entry.fn_mut_trait_ref {
878-
traits.entry(trait_ref).or_default();
865+
first = false;
879866
}
880-
if let Some(trait_ref) = entry.fn_trait_ref {
881-
traits.entry(trait_ref).or_default();
867+
// If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
868+
// trait_refs we collected in the OpaqueFnEntry as normal trait refs.
869+
_ => {
870+
if entry.has_fn_once {
871+
traits.entry(fn_once_trait_ref).or_default().extend(
872+
// Group the return ty with its def id, if we had one.
873+
entry
874+
.return_ty
875+
.map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)),
876+
);
877+
}
878+
if let Some(trait_ref) = entry.fn_mut_trait_ref {
879+
traits.entry(trait_ref).or_default();
880+
}
881+
if let Some(trait_ref) = entry.fn_trait_ref {
882+
traits.entry(trait_ref).or_default();
883+
}
882884
}
883885
}
884-
}
886+
887+
Ok(cx)
888+
})?;
885889
}
886890

887891
// Print the rest of the trait types (that aren't Fn* family of traits)
888892
for (trait_ref, assoc_items) in traits {
889-
p!(
890-
write("{}", if first { " " } else { " + " }),
891-
print(trait_ref.skip_binder().print_only_trait_name())
892-
);
893+
write!(self, "{}", if first { "" } else { " + " })?;
894+
895+
self = self.wrap_binder(&trait_ref, |trait_ref, mut cx| {
896+
define_scoped_cx!(cx);
897+
p!(print(trait_ref.print_only_trait_name()));
893898

894-
let generics = self.tcx().generics_of(trait_ref.def_id());
895-
let args = generics.own_substs_no_defaults(self.tcx(), trait_ref.skip_binder().substs);
899+
let generics = tcx.generics_of(trait_ref.def_id);
900+
let args = generics.own_substs_no_defaults(tcx, trait_ref.substs);
896901

897-
if !args.is_empty() || !assoc_items.is_empty() {
898-
let mut first = true;
902+
if !args.is_empty() || !assoc_items.is_empty() {
903+
let mut first = true;
899904

900-
for ty in args {
901-
if first {
902-
p!("<");
903-
first = false;
904-
} else {
905-
p!(", ");
905+
for ty in args {
906+
if first {
907+
p!("<");
908+
first = false;
909+
} else {
910+
p!(", ");
911+
}
912+
p!(print(ty));
906913
}
907-
p!(print(trait_ref.rebind(*ty)));
908-
}
909914

910-
for (assoc_item_def_id, term) in assoc_items {
911-
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
912-
// unless we can find out what generator return type it comes from.
913-
let term = if let Some(ty) = term.skip_binder().ty()
914-
&& let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
915-
&& Some(*item_def_id) == self.tcx().lang_items().generator_return()
916-
{
917-
if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
918-
let return_ty = substs.as_generator().return_ty();
919-
if !return_ty.is_ty_infer() {
920-
return_ty.into()
915+
for (assoc_item_def_id, term) in assoc_items {
916+
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
917+
// unless we can find out what generator return type it comes from.
918+
let term = if let Some(ty) = term.skip_binder().ty()
919+
&& let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
920+
&& Some(*item_def_id) == tcx.lang_items().generator_return()
921+
{
922+
if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
923+
let return_ty = substs.as_generator().return_ty();
924+
if !return_ty.is_ty_infer() {
925+
return_ty.into()
926+
} else {
927+
continue;
928+
}
921929
} else {
922930
continue;
923931
}
924932
} else {
925-
continue;
926-
}
927-
} else {
928-
term.skip_binder()
929-
};
933+
term.skip_binder()
934+
};
930935

931-
if first {
932-
p!("<");
933-
first = false;
934-
} else {
935-
p!(", ");
936-
}
936+
if first {
937+
p!("<");
938+
first = false;
939+
} else {
940+
p!(", ");
941+
}
937942

938-
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name));
943+
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
939944

940-
match term {
941-
Term::Ty(ty) => {
942-
p!(print(ty))
943-
}
944-
Term::Const(c) => {
945-
p!(print(c));
946-
}
947-
};
948-
}
945+
match term {
946+
Term::Ty(ty) => {
947+
p!(print(ty))
948+
}
949+
Term::Const(c) => {
950+
p!(print(c));
951+
}
952+
};
953+
}
949954

950-
if !first {
951-
p!(">");
955+
if !first {
956+
p!(">");
957+
}
952958
}
953-
}
954959

955-
first = false;
960+
first = false;
961+
Ok(cx)
962+
})?;
956963
}
957964

958965
if !is_sized {
959-
p!(write("{}?Sized", if first { " " } else { " + " }));
966+
write!(self, "{}?Sized", if first { "" } else { " + " })?;
960967
} else if first {
961-
p!(" Sized");
968+
write!(self, "Sized")?;
962969
}
963970

964971
Ok(self)
@@ -1869,7 +1876,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
18691876
self.pretty_in_binder(value)
18701877
}
18711878

1872-
fn wrap_binder<T, C: Fn(&T, Self) -> Result<Self, Self::Error>>(
1879+
fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, Self::Error>>(
18731880
self,
18741881
value: &ty::Binder<'tcx, T>,
18751882
f: C,
@@ -2256,7 +2263,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
22562263
Ok(inner)
22572264
}
22582265

2259-
pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>(
2266+
pub fn pretty_wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, fmt::Error>>(
22602267
self,
22612268
value: &ty::Binder<'tcx, T>,
22622269
f: C,

src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
2222
LL | |
2323
LL | | }
2424
| |_^
25-
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
25+
= note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()`
2626
note: required because it's used within this `async` block
2727
--> $DIR/issue-70935-complex-spans.rs:23:16
2828
|
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait Trait<'a> {}
2+
impl<T> Trait<'_> for T {}
3+
fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {}
4+
5+
fn whatever2() -> impl for<'c> Fn(&'c ()) {
6+
|_: &()| {}
7+
}
8+
9+
fn main() {
10+
let x: u32 = whatever();
11+
//~^ ERROR mismatched types
12+
let x2: u32 = whatever2();
13+
//~^ ERROR mismatched types
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/printing-binder.rs:10:18
3+
|
4+
LL | fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {}
5+
| ------------------------------------------ the found opaque type
6+
...
7+
LL | let x: u32 = whatever();
8+
| --- ^^^^^^^^^^ expected `u32`, found opaque type
9+
| |
10+
| expected due to this
11+
|
12+
= note: expected type `u32`
13+
found opaque type `impl for<'a> Trait<'a> + for<'b> Trait<'b>`
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/printing-binder.rs:12:19
17+
|
18+
LL | fn whatever2() -> impl for<'c> Fn(&'c ()) {
19+
| ----------------------- the found opaque type
20+
...
21+
LL | let x2: u32 = whatever2();
22+
| --- ^^^^^^^^^^^ expected `u32`, found opaque type
23+
| |
24+
| expected due to this
25+
|
26+
= note: expected type `u32`
27+
found opaque type `impl for<'c> Fn(&'c ())`
28+
29+
error: aborting due to 2 previous errors
30+
31+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)