Take const generics into account when monomorphising
Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
This commit is contained in:
parent
2ce19ae3d1
commit
691d054e05
3 changed files with 60 additions and 22 deletions
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue