instance: only polymorphize upvar substs
This commit restricts the substitution polymorphization added in #75255 to only apply to the tupled upvar substitution, rather than all substitutions, fixing a bunch of regressions when polymorphization is enabled. Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
8e738539be
commit
fd41bdeff0
@ -85,8 +85,6 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&ty::Generator(_, ref substs, _) => {
|
&ty::Generator(_, ref substs, _) => {
|
||||||
self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
|
|
||||||
|
|
||||||
let substs = substs.as_generator();
|
let substs = substs.as_generator();
|
||||||
let should_remove_further_specializable =
|
let should_remove_further_specializable =
|
||||||
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||||
@ -109,8 +107,6 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&ty::Closure(_, substs) => {
|
&ty::Closure(_, substs) => {
|
||||||
self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
|
|
||||||
|
|
||||||
let substs = substs.as_closure();
|
let substs = substs.as_closure();
|
||||||
let should_remove_further_specializable =
|
let should_remove_further_specializable =
|
||||||
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||||
@ -196,8 +192,6 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&ty::FnDef(_, substs) => {
|
&ty::FnDef(_, substs) => {
|
||||||
self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
|
|
||||||
|
|
||||||
self.add_substs(substs);
|
self.add_substs(substs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,12 +150,6 @@ fn still_further_specializable(&self) -> bool {
|
|||||||
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does this value contain closures, generators or functions such that it may require
|
|
||||||
/// polymorphization?
|
|
||||||
fn may_polymorphize(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
|
/// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
|
||||||
fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {
|
fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {
|
||||||
pub struct Visitor<F>(F);
|
pub struct Visitor<F>(F);
|
||||||
|
@ -492,6 +492,20 @@ fn polymorphize<'tcx>(
|
|||||||
let unused = tcx.unused_generic_params(def_id);
|
let unused = tcx.unused_generic_params(def_id);
|
||||||
debug!("polymorphize: unused={:?}", unused);
|
debug!("polymorphize: unused={:?}", unused);
|
||||||
|
|
||||||
|
// If this is a closure or generator then we need to handle the case where another closure
|
||||||
|
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
|
||||||
|
// the unpolymorphized upvar closure would result in a polymorphized closure producing
|
||||||
|
// multiple mono items (and eventually symbol clashes).
|
||||||
|
let upvars_ty = if tcx.is_closure(def_id) {
|
||||||
|
Some(substs.as_closure().tupled_upvars_ty())
|
||||||
|
} else if tcx.type_of(def_id).is_generator() {
|
||||||
|
Some(substs.as_generator().tupled_upvars_ty())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false);
|
||||||
|
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
|
||||||
|
|
||||||
struct PolymorphizationFolder<'tcx> {
|
struct PolymorphizationFolder<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
};
|
};
|
||||||
@ -512,14 +526,6 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|||||||
self.tcx.mk_closure(def_id, polymorphized_substs)
|
self.tcx.mk_closure(def_id, polymorphized_substs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::FnDef(def_id, substs) => {
|
|
||||||
let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
|
|
||||||
if substs == polymorphized_substs {
|
|
||||||
ty
|
|
||||||
} else {
|
|
||||||
self.tcx.mk_fn_def(def_id, polymorphized_substs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::Generator(def_id, substs, movability) => {
|
ty::Generator(def_id, substs, movability) => {
|
||||||
let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
|
let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
|
||||||
if substs == polymorphized_substs {
|
if substs == polymorphized_substs {
|
||||||
@ -537,24 +543,31 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|||||||
let is_unused = unused.contains(param.index).unwrap_or(false);
|
let is_unused = unused.contains(param.index).unwrap_or(false);
|
||||||
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
|
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
|
||||||
match param.kind {
|
match param.kind {
|
||||||
// If parameter is a const or type parameter..
|
// Upvar case: If parameter is a type parameter..
|
||||||
|
ty::GenericParamDefKind::Type { .. } if
|
||||||
|
// ..and has upvars..
|
||||||
|
has_upvars &&
|
||||||
|
// ..and this param has the same type as the tupled upvars..
|
||||||
|
upvars_ty == Some(substs[param.index as usize].expect_ty()) => {
|
||||||
|
// ..then double-check that polymorphization marked it used..
|
||||||
|
debug_assert!(!is_unused);
|
||||||
|
// ..and polymorphize any closures/generators captured as upvars.
|
||||||
|
let upvars_ty = upvars_ty.unwrap();
|
||||||
|
let polymorphized_upvars_ty = upvars_ty.fold_with(
|
||||||
|
&mut PolymorphizationFolder { tcx });
|
||||||
|
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
|
||||||
|
ty::GenericArg::from(polymorphized_upvars_ty)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Simple case: If parameter is a const or type parameter..
|
||||||
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
|
ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
|
||||||
// ..and is within range and unused..
|
// ..and is within range and unused..
|
||||||
unused.contains(param.index).unwrap_or(false) =>
|
unused.contains(param.index).unwrap_or(false) =>
|
||||||
// ..then use the identity for this parameter.
|
// ..then use the identity for this parameter.
|
||||||
tcx.mk_param_from_def(param),
|
tcx.mk_param_from_def(param),
|
||||||
|
|
||||||
// If the parameter does not contain any closures or generators, then use the
|
// Otherwise, use the parameter as before.
|
||||||
// substitution directly.
|
_ => substs[param.index as usize],
|
||||||
_ if !substs.may_polymorphize() => substs[param.index as usize],
|
|
||||||
|
|
||||||
// Otherwise, use the substitution after polymorphizing.
|
|
||||||
_ => {
|
|
||||||
let arg = substs[param.index as usize];
|
|
||||||
let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx });
|
|
||||||
debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg);
|
|
||||||
ty::GenericArg::from(polymorphized_arg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -575,10 +575,6 @@ pub struct TypeFlags: u32 {
|
|||||||
/// Does this value have parameters/placeholders/inference variables which could be
|
/// Does this value have parameters/placeholders/inference variables which could be
|
||||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
|
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
|
||||||
|
|
||||||
/// Does this value contain closures, generators or functions such that it may require
|
|
||||||
/// polymorphization?
|
|
||||||
const MAY_POLYMORPHIZE = 1 << 18;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
|
|
||||||
// ignore-tidy-linelength
|
|
||||||
|
|
||||||
#![crate_type = "rlib"]
|
|
||||||
|
|
||||||
// Test that only one copy of `Iter::map` and `iter::repeat` are generated.
|
|
||||||
|
|
||||||
fn unused<T>() -> u64 {
|
|
||||||
42
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foo<T>() {
|
|
||||||
let x = [1, 2, 3, std::mem::size_of::<T>()];
|
|
||||||
x.iter().map(|_| ());
|
|
||||||
}
|
|
||||||
|
|
||||||
//~ 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]
|
|
||||||
//~ 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]
|
|
||||||
|
|
||||||
fn bar<T>() {
|
|
||||||
std::iter::repeat(unused::<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0]<fn() -> u64> @@ pr_75255-cgu.1[Internal]
|
|
||||||
|
|
||||||
pub fn dispatch() {
|
|
||||||
foo::<String>();
|
|
||||||
foo::<Vec<String>>();
|
|
||||||
|
|
||||||
bar::<String>();
|
|
||||||
bar::<Vec<String>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are all the items that aren't relevant to the test.
|
|
||||||
//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External]
|
|
||||||
//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn pr_75255::bar[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
|
|
||||||
//~ MONO_ITEM fn pr_75255::bar[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
|
|
Loading…
Reference in New Issue
Block a user