Skip to content

Commit 20cea3e

Browse files
Fix printing impl trait under binders
1 parent fdca237 commit 20cea3e

File tree

3 files changed

+178
-113
lines changed

3 files changed

+178
-113
lines changed

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

+133-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,168 @@ pub trait PrettyPrinter<'tcx>:
817817
}
818818
}
819819

820+
{
821+
define_scoped_cx!(self);
822+
p!("impl ");
823+
}
824+
820825
let mut first = true;
821826
// Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
822827
let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
823828

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

844-
p!(
845-
write("{}", if first { " " } else { " + " }),
846-
write("{}{}(", if paren_needed { "(" } else { "" }, name)
847-
);
855+
define_scoped_cx!(self_);
856+
p!(write("{}(", name));
848857

849-
for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
850-
if idx > 0 {
851-
p!(", ");
858+
for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
859+
if idx > 0 {
860+
p!(", ");
861+
}
862+
p!(print(ty));
852863
}
853-
p!(print(ty));
854-
}
855864

856-
p!(")");
857-
if let Term::Ty(ty) = return_ty.skip_binder() {
858-
if !ty.is_unit() {
859-
p!(" -> ", print(return_ty));
865+
p!(")");
866+
if let Term::Ty(ty) = return_ty.skip_binder() {
867+
if !ty.is_unit() {
868+
p!(" -> ", print(return_ty));
869+
}
860870
}
861-
}
862-
p!(write("{}", if paren_needed { ")" } else { "" }));
871+
p!(write("{}", if paren_needed { ")" } else { "" }));
863872

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();
873+
first = false;
879874
}
880-
if let Some(trait_ref) = entry.fn_trait_ref {
881-
traits.entry(trait_ref).or_default();
875+
// If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
876+
// trait_refs we collected in the OpaqueFnEntry as normal trait refs.
877+
_ => {
878+
if entry.has_fn_once {
879+
traits.entry(fn_once_trait_ref).or_default().extend(
880+
// Group the return ty with its def id, if we had one.
881+
entry
882+
.return_ty
883+
.map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)),
884+
);
885+
}
886+
if let Some(trait_ref) = entry.fn_mut_trait_ref {
887+
traits.entry(trait_ref).or_default();
888+
}
889+
if let Some(trait_ref) = entry.fn_trait_ref {
890+
traits.entry(trait_ref).or_default();
891+
}
882892
}
883893
}
884-
}
894+
895+
Ok(self_)
896+
})?;
885897
}
886898

887899
// Print the rest of the trait types (that aren't Fn* family of traits)
888900
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-
);
901+
{
902+
define_scoped_cx!(self);
903+
p!(write("{}", if first { "" } else { " + " }));
904+
}
893905

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);
906+
self = self.wrap_binder(&trait_ref, |trait_ref, mut self_| {
907+
define_scoped_cx!(self_);
908+
p!(print(trait_ref.print_only_trait_name()));
896909

897-
if !args.is_empty() || !assoc_items.is_empty() {
898-
let mut first = true;
910+
let generics = tcx.generics_of(trait_ref.def_id);
911+
let args = generics.own_substs_no_defaults(tcx, trait_ref.substs);
899912

900-
for ty in args {
901-
if first {
902-
p!("<");
903-
first = false;
904-
} else {
905-
p!(", ");
913+
if !args.is_empty() || !assoc_items.is_empty() {
914+
let mut first = true;
915+
916+
for ty in args {
917+
if first {
918+
p!("<");
919+
first = false;
920+
} else {
921+
p!(", ");
922+
}
923+
p!(print(ty));
906924
}
907-
p!(print(trait_ref.rebind(*ty)));
908-
}
909925

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()
926+
for (assoc_item_def_id, term) in assoc_items {
927+
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
928+
// unless we can find out what generator return type it comes from.
929+
let term = if let Some(ty) = term.skip_binder().ty()
930+
&& let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
931+
&& Some(*item_def_id) == tcx.lang_items().generator_return()
932+
{
933+
if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
934+
let return_ty = substs.as_generator().return_ty();
935+
if !return_ty.is_ty_infer() {
936+
return_ty.into()
937+
} else {
938+
continue;
939+
}
921940
} else {
922941
continue;
923942
}
924943
} else {
925-
continue;
926-
}
927-
} else {
928-
term.skip_binder()
929-
};
944+
term.skip_binder()
945+
};
930946

931-
if first {
932-
p!("<");
933-
first = false;
934-
} else {
935-
p!(", ");
936-
}
947+
if first {
948+
p!("<");
949+
first = false;
950+
} else {
951+
p!(", ");
952+
}
937953

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

940-
match term {
941-
Term::Ty(ty) => {
942-
p!(print(ty))
943-
}
944-
Term::Const(c) => {
945-
p!(print(c));
946-
}
947-
};
948-
}
956+
match term {
957+
Term::Ty(ty) => {
958+
p!(print(ty))
959+
}
960+
Term::Const(c) => {
961+
p!(print(c));
962+
}
963+
};
964+
}
949965

950-
if !first {
951-
p!(">");
966+
if !first {
967+
p!(">");
968+
}
952969
}
953-
}
954970

955-
first = false;
971+
first = false;
972+
Ok(self_)
973+
})?;
956974
}
957975

976+
define_scoped_cx!(self);
977+
958978
if !is_sized {
959-
p!(write("{}?Sized", if first { " " } else { " + " }));
979+
p!(write("{}?Sized", if first { "" } else { " + " }));
960980
} else if first {
961-
p!(" Sized");
981+
p!("Sized");
962982
}
963983

964984
Ok(self)
@@ -1869,7 +1889,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
18691889
self.pretty_in_binder(value)
18701890
}
18711891

1872-
fn wrap_binder<T, C: Fn(&T, Self) -> Result<Self, Self::Error>>(
1892+
fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, Self::Error>>(
18731893
self,
18741894
value: &ty::Binder<'tcx, T>,
18751895
f: C,
@@ -2256,7 +2276,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
22562276
Ok(inner)
22572277
}
22582278

2259-
pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>(
2279+
pub fn pretty_wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, fmt::Error>>(
22602280
self,
22612281
value: &ty::Binder<'tcx, T>,
22622282
f: C,
+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)