diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1f20c70dec5..2ce3bf43cfc 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -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] } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 059af2dbba9..f0d19ec8bf2 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -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(&self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool) - where I: Iterator> - { + fn push_generic_params( + &self, + substs: SubstsRef<'tcx>, + projections: I, + output: &mut String, + debug: bool, + ) where I: Iterator> { 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); } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f342017603e..f98bc476aaf 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -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() {