Skip to content

Commit 0d9924a

Browse files
committed
instance: always polymorphize substs
By always polymorphizing substitutions, functions which take closures as arguments (e.g. `impl Fn()`) can have fewer mono items when some of the argument closures can be polymorphized. Signed-off-by: David Wood <[email protected]>
1 parent d9deced commit 0d9924a

File tree

2 files changed

+45
-38
lines changed

2 files changed

+45
-38
lines changed

src/librustc_middle/ty/instance.rs

+8-38
Original file line numberDiff line numberDiff line change
@@ -492,25 +492,6 @@ fn polymorphize<'tcx>(
492492
let unused = tcx.unused_generic_params(def_id);
493493
debug!("polymorphize: unused={:?}", unused);
494494

495-
if unused.is_empty() {
496-
// Exit early if every parameter was used.
497-
return substs;
498-
}
499-
500-
// If this is a closure or generator then we need to handle the case where another closure
501-
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
502-
// the unpolymorphized upvar closure would result in a polymorphized closure producing
503-
// multiple mono items (and eventually symbol clashes).
504-
let upvars_ty = if tcx.is_closure(def_id) {
505-
Some(substs.as_closure().tupled_upvars_ty())
506-
} else if tcx.type_of(def_id).is_generator() {
507-
Some(substs.as_generator().tupled_upvars_ty())
508-
} else {
509-
None
510-
};
511-
let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false);
512-
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
513-
514495
struct PolymorphizationFolder<'tcx> {
515496
tcx: TyCtxt<'tcx>,
516497
};
@@ -540,31 +521,20 @@ fn polymorphize<'tcx>(
540521
let is_unused = unused.contains(param.index).unwrap_or(false);
541522
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
542523
match param.kind {
543-
// Upvar case: If parameter is a type parameter..
544-
ty::GenericParamDefKind::Type { .. } if
545-
// ..and has upvars..
546-
has_upvars &&
547-
// ..and this param has the same type as the tupled upvars..
548-
upvars_ty == Some(substs[param.index as usize].expect_ty()) => {
549-
// ..then double-check that polymorphization marked it used..
550-
debug_assert!(!is_unused);
551-
// ..and polymorphize any closures/generators captured as upvars.
552-
let upvars_ty = upvars_ty.unwrap();
553-
let polymorphized_upvars_ty = upvars_ty.fold_with(
554-
&mut PolymorphizationFolder { tcx });
555-
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
556-
ty::GenericArg::from(polymorphized_upvars_ty)
557-
},
558-
559-
// Simple case: If parameter is a const or type parameter..
524+
// If parameter is a const or type parameter..
560525
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
561526
// ..and is within range and unused..
562527
unused.contains(param.index).unwrap_or(false) =>
563528
// ..then use the identity for this parameter.
564529
tcx.mk_param_from_def(param),
565530

566-
// Otherwise, use the parameter as before.
567-
_ => substs[param.index as usize],
531+
// Otherwise, use the parameter as before (polymorphizing any closures or generators).
532+
_ => {
533+
let arg = substs[param.index as usize];
534+
let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx });
535+
debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg);
536+
ty::GenericArg::from(polymorphized_arg)
537+
}
568538
}
569539
})
570540
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
2+
// ignore-tidy-linelength
3+
4+
#![crate_type = "rlib"]
5+
6+
// Test that only one copy of `Iter::map` is generated.
7+
8+
fn foo<T>() {
9+
let x = [1, 2, 3, std::mem::size_of::<T>()];
10+
x.iter().map(|_| ());
11+
}
12+
13+
pub fn dispatch() {
14+
foo::<String>();
15+
foo::<Vec<String>>();
16+
}
17+
18+
//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0]<core::slice[0]::Iter[0]<usize>, pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.0[External]
19+
//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0]<core::slice[0]::Iter[0]<usize>, (), pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.1[Internal]
20+
21+
// These are all the items that aren't relevant to the test.
22+
//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
23+
//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
24+
//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal]
25+
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal]
26+
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal]
27+
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal]
28+
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal]
29+
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal]
30+
//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal]
31+
//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal]
32+
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal]
33+
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal]
34+
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal]
35+
//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External]
36+
//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
37+
//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]

0 commit comments

Comments
 (0)