1
Fork 0

Take const generics into account when monomorphising

Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
This commit is contained in:
varkor 2019-02-20 01:11:37 +00:00
parent 2ce19ae3d1
commit 691d054e05
3 changed files with 60 additions and 22 deletions

View file

@ -466,7 +466,17 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>)
{
let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count();
debug!(" => type length={}", type_length);
let const_length = instance.substs.consts()
.filter_map(|ct| {
if let ty::LazyConst::Evaluated(ct) = ct {
Some(ct.ty.walk())
} else {
None
}
})
.flatten()
.count();
debug!(" => type length={}, const length={}", type_length, const_length);
// Rust code can easily create exponentially-long types using only a
// polynomial recursion depth. Even with the default recursion
@ -475,7 +485,9 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
//
// Bail out in these cases to avoid that bad user experience.
let type_length_limit = *tcx.sess.type_length_limit.get();
if type_length > type_length_limit {
// We include the const length in the type length, as it's better
// to be overly conservative.
if type_length + const_length > type_length_limit {
// The instance name is already known to be too long for rustc. Use
// `{:.64}` to avoid blasting the user's terminal with thousands of
// lines of type-name.
@ -490,7 +502,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diag.note(&format!(
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
type_length_limit*2));
type_length_limit * 2));
diag.emit();
tcx.sess.abort_if_errors();
}
@ -759,10 +771,10 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
return false
}
// If this instance has no type parameters, it cannot be a shared
// If this instance has non-erasable parameters, it cannot be a shared
// monomorphization. Non-generic instances are already handled above
// by `is_reachable_non_generic()`
if substs.types().next().is_none() {
if substs.non_erasable_generics().next().is_none() {
return false
}
@ -1113,14 +1125,16 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
continue;
}
if tcx.generics_of(method.def_id).own_counts().types != 0 {
let counts = tcx.generics_of(method.def_id).own_counts();
if counts.types + counts.consts != 0 {
continue;
}
let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize]
}
}

View file

@ -1,8 +1,9 @@
use crate::monomorphize::Instance;
use rustc::hir;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::interpret::ConstValue;
use rustc::session::config::OptLevel;
use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts};
use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts, LazyConst, ParamConst};
use rustc::ty::subst::{SubstsRef, InternalSubsts};
use syntax::ast;
use syntax::attr::InlineAttr;
@ -44,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
fn is_generic_fn(&self) -> bool {
match *self.as_mono_item() {
MonoItem::Fn(ref instance) => {
instance.substs.types().next().is_some()
instance.substs.non_erasable_generics().next().is_some()
}
MonoItem::Static(..) |
MonoItem::GlobalAsm(..) => false,
@ -267,7 +268,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
ty::Adt(adt_def, substs) => {
self.push_def_path(adt_def.did, output);
self.push_type_params(substs, iter::empty(), output, debug);
self.push_generic_params(substs, iter::empty(), output, debug);
},
ty::Tuple(component_types) => {
output.push('(');
@ -312,7 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
ty::Dynamic(ref trait_data, ..) => {
if let Some(principal) = trait_data.principal() {
self.push_def_path(principal.def_id(), output);
self.push_type_params(
self.push_generic_params(
principal.skip_binder().substs,
trait_data.projection_bounds(),
output,
@ -373,7 +374,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
self.push_def_path(def_id, output);
let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
let substs = substs.truncate_to(self.tcx, generics);
self.push_type_params(substs, iter::empty(), output, debug);
self.push_generic_params(substs, iter::empty(), output, debug);
}
ty::Error |
ty::Bound(..) |
@ -394,6 +395,24 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
}
}
// FIXME(const_generics): handle debug printing.
pub fn push_const_name(&self, c: &LazyConst<'tcx>, output: &mut String, debug: bool) {
match c {
LazyConst::Unevaluated(..) => output.push_str("_: _"),
LazyConst::Evaluated(Const { ty, val }) => {
match val {
ConstValue::Infer(..) => output.push_str("_"),
ConstValue::Param(ParamConst { name, .. }) => {
write!(output, "{}", name).unwrap();
}
_ => write!(output, "{:?}", c).unwrap(),
}
output.push_str(": ");
self.push_type_name(ty, output, debug);
}
}
}
pub fn push_def_path(&self,
def_id: DefId,
output: &mut String) {
@ -421,15 +440,15 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output.pop();
}
fn push_type_params<I>(&self,
substs: SubstsRef<'tcx>,
projections: I,
output: &mut String,
debug: bool)
where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
{
fn push_generic_params<I>(
&self,
substs: SubstsRef<'tcx>,
projections: I,
output: &mut String,
debug: bool,
) where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>> {
let mut projections = projections.peekable();
if substs.types().next().is_none() && projections.peek().is_none() {
if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
return;
}
@ -449,6 +468,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output.push_str(", ");
}
for const_parameter in substs.consts() {
self.push_const_name(const_parameter, output, debug);
output.push_str(", ");
}
output.pop();
output.pop();
@ -460,6 +484,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output: &mut String,
debug: bool) {
self.push_def_path(instance.def_id(), output);
self.push_type_params(instance.substs, iter::empty(), output, debug);
self.push_generic_params(instance.substs, iter::empty(), output, debug);
}
}

View file

@ -448,7 +448,7 @@ fn mono_item_visibility(
return Visibility::Hidden
}
let is_generic = instance.substs.types().next().is_some();
let is_generic = instance.substs.non_erasable_generics().next().is_some();
// Upstream `DefId` instances get different handling than local ones
if !def_id.is_local() {