1
Fork 0

Auto merge of #58583 - varkor:const-generics-ty, r=oli-obk

Add const generics to ty (and transitive dependencies)

Split out from #53645. This work is a collaborative effort with @yodaldevoid.

There are a number of stubs. Some I plan to leave for the next PRs (e.g. `infer` and `rustdoc`). Others I can either fix up in this PR, or as follow ups (which would avoid the time-consuming rebasing).

It was a little hard to split this up, as so much depends on ty and friends. Apologies for the large diff.

r? @eddyb
This commit is contained in:
bors 2019-03-07 00:27:07 +00:00
commit 88f755f8a8
74 changed files with 1201 additions and 412 deletions

View file

@ -74,6 +74,7 @@ for ty::subst::UnpackedKind<'gcx> {
match self {
ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
ty::subst::UnpackedKind::Const(ct) => ct.hash_stable(hcx, hasher),
}
}
}
@ -134,6 +135,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
}
}
impl<'gcx, 'tcx> HashStable<StableHashingContext<'gcx>> for ty::ConstVid<'tcx> {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
self.index.hash_stable(hcx, hasher);
}
}
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundVar {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
@ -297,6 +307,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::VariantFlags {
}
}
impl_stable_hash_for!(
impl<'tcx> for enum ty::InferConst<'tcx> [ ty::InferConst ] {
Var(vid),
Fresh(i),
Canonical(debruijn, var),
}
);
impl_stable_hash_for!(enum ty::VariantDiscr {
Explicit(def_id),
Relative(distance)
@ -310,11 +328,14 @@ impl_stable_hash_for!(struct ty::FieldDef {
impl_stable_hash_for!(
impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
Param(param),
Infer(infer),
Scalar(val),
Slice(a, b),
ByRef(ptr, alloc),
}
);
impl_stable_hash_for!(struct crate::mir::interpret::RawConst<'tcx> {
alloc_id,
ty,
@ -518,6 +539,7 @@ impl_stable_hash_for!(struct ty::GenericParamDef {
impl_stable_hash_for!(enum ty::GenericParamDefKind {
Lifetime,
Type { has_default, object_lifetime_default, synthetic },
Const,
});
impl_stable_hash_for!(
@ -736,6 +758,11 @@ for ty::FloatVid
}
}
impl_stable_hash_for!(struct ty::ParamConst {
index,
name
});
impl_stable_hash_for!(struct ty::ParamTy {
idx,
name

View file

@ -443,6 +443,9 @@ impl<'tcx> CanonicalVarValues<'tcx> {
UnpackedKind::Lifetime(..) => tcx.mk_region(
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
).into(),
UnpackedKind::Const(..) => {
unimplemented!() // FIXME(const_generics)
}
})
.collect()
}

View file

@ -315,6 +315,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
obligations.extend(ok.into_obligations());
}
(UnpackedKind::Const(..), UnpackedKind::Const(..)) => {
unimplemented!() // FIXME(const_generics)
}
_ => {
bug!(
"kind mismatch, cannot unify {:?} and {:?}",
@ -473,6 +477,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
opt_values[br.assert_bound_var()] = Some(*original_value);
}
}
UnpackedKind::Const(..) => {
unimplemented!() // FIXME(const_generics)
}
}
}
@ -568,6 +575,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
ty::OutlivesPredicate(t1, r2)
)
),
UnpackedKind::Const(..) => {
// Consts cannot outlive one another, so we don't expect to
// ecounter this branch.
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
}
}
)
})
@ -602,6 +614,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
obligations
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
}
(UnpackedKind::Const(..), UnpackedKind::Const(..)) => {
unimplemented!() // FIXME(const_generics)
}
_ => {
bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
}

View file

@ -449,7 +449,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
let origin = *variables.var_origin(vid);
let new_var_id = variables.new_var(self.for_universe, false, origin);
let u = self.tcx().mk_var(new_var_id);
let u = self.tcx().mk_ty_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}",
vid, u);
return Ok(u);

View file

@ -691,17 +691,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
) -> SubstsRef<'tcx> {
let generics = self.tcx.generics_of(def_id);
let mut num_supplied_defaults = 0;
let mut type_params = generics
.params
.iter()
.rev()
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => None,
ty::GenericParamDefKind::Type { has_default, .. } => {
Some((param.def_id, has_default))
}
})
.peekable();
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => None,
ty::GenericParamDefKind::Type { has_default, .. } => Some((param.def_id, has_default)),
ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
}).peekable();
let has_default = {
let has_default = type_params.peek().map(|(_, has_default)| has_default);
*has_default.unwrap_or(&false)

View file

@ -656,7 +656,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
type_variables
.unsolved_variables()
.into_iter()
.map(|t| self.tcx.mk_var(t))
.map(|t| self.tcx.mk_ty_var(t))
.chain(
(0..int_unification_table.len())
.map(|i| ty::IntVid { index: i as u32 })
@ -981,7 +981,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false, origin))
self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
}
pub fn next_ty_var_in_universe(
@ -992,11 +992,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let vid = self.type_variables
.borrow_mut()
.new_var(universe, false, origin);
self.tcx.mk_var(vid)
self.tcx.mk_ty_var(vid)
}
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true, origin))
self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
}
pub fn next_int_var_id(&self) -> IntVid {
@ -1081,7 +1081,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
TypeVariableOrigin::TypeParameterDefinition(span, param.name),
);
self.tcx.mk_var(ty_var_id).into()
self.tcx.mk_ty_var(ty_var_id).into()
}
GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
}
}

View file

@ -310,7 +310,7 @@ where
ty::Projection(projection_ty)
if D::normalization() == NormalizationStrategy::Lazy =>
{
return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_var(vid)));
return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
}
_ => (),
@ -764,7 +764,7 @@ where
// the universe `_universe`.
let new_var_id = variables.new_var(self.universe, false, origin);
let u = self.tcx().mk_var(new_var_id);
let u = self.tcx().mk_ty_var(new_var_id);
debug!(
"generalize: replacing original vid={:?} with new={:?}",
vid,

View file

@ -381,10 +381,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
substs,
item_def_id: _,
}) => {
for r in substs.regions() {
bound_region(r);
for k in substs {
match k.unpack() {
UnpackedKind::Lifetime(lt) => bound_region(lt),
UnpackedKind::Type(ty) => types.push(ty),
UnpackedKind::Const(_) => {
// Const parameters don't impose constraints.
}
}
}
types.extend(substs.types());
}
Component::EscapingProjection(more_components) => {

View file

@ -67,6 +67,7 @@ use crate::hir;
use crate::traits::ObligationCause;
use crate::ty::outlives::Component;
use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
use crate::ty::subst::UnpackedKind;
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// Registers that the given region obligation must be resolved
@ -430,13 +431,18 @@ where
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
debug!("projection_must_outlive: no declared bounds");
for component_ty in projection_ty.substs.types() {
self.type_must_outlive(origin.clone(), component_ty, region);
}
for r in projection_ty.substs.regions() {
self.delegate
.push_sub_region_constraint(origin.clone(), region, r);
for k in projection_ty.substs {
match k.unpack() {
UnpackedKind::Lifetime(lt) => {
self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
}
UnpackedKind::Type(ty) => {
self.type_must_outlive(origin.clone(), ty, region);
}
UnpackedKind::Const(_) => {
// Const parameters don't impose constraints.
}
}
}
return;

View file

@ -1974,7 +1974,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
object_lifetime_default,
..
} => Some(object_lifetime_default),
GenericParamDefKind::Lifetime => None,
GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
})
.collect()
})

View file

@ -1,6 +1,6 @@
use std::fmt;
use crate::ty::{Ty, layout::{HasDataLayout, Size}};
use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}};
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
@ -17,6 +17,12 @@ pub struct RawConst<'tcx> {
/// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
/// A const generic parameter.
Param(ParamConst),
/// Infer the value of the const.
Infer(InferConst<'tcx>),
/// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
///
/// Not using the enum `Value` to encode that this must not be `Undef`.
@ -43,6 +49,8 @@ impl<'tcx> ConstValue<'tcx> {
#[inline]
pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
ConstValue::Param(_) |
ConstValue::Infer(_) |
ConstValue::ByRef(..) |
ConstValue::Slice(..) => None,
ConstValue::Scalar(val) => Some(val),

View file

@ -389,7 +389,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize].to_string()
},
GenericParamDefKind::Lifetime => continue,

View file

@ -1010,7 +1010,8 @@ fn vtable_methods<'a, 'tcx>(
InternalSubsts::for_item(tcx, 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

@ -310,7 +310,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
}
// We can't monomorphize things like `fn foo<A>(...)`.
if self.generics_of(method.def_id).own_counts().types != 0 {
let own_counts = self.generics_of(method.def_id).own_counts();
if own_counts.types + own_counts.consts != 0 {
return Some(MethodViolationCode::Generic);
}

View file

@ -280,7 +280,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
let generics = tcx.generics_of(trait_ref.def_id);
let generic_map = generics.params.iter().filter_map(|param| {
let value = match param.kind {
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const => {
trait_ref.substs[param.index as usize].to_string()
},
GenericParamDefKind::Lifetime => return None

View file

@ -21,8 +21,8 @@ use crate::middle::lang_items;
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::{self, Mir, interpret, ProjectionKind};
use crate::mir::interpret::Allocation;
use crate::ty::subst::{Kind, InternalSubsts, Subst, SubstsRef};
use crate::mir::interpret::{ConstValue, Allocation};
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions;
use crate::traits;
use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals};
@ -31,8 +31,9 @@ use crate::ty::{TyS, TyKind, List};
use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst};
use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
use crate::ty::RegionKind;
use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid};
use crate::ty::TyKind::*;
use crate::ty::{InferConst, ParamConst};
use crate::ty::GenericParamDefKind;
use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
use crate::ty::query;
@ -872,6 +873,18 @@ impl CanonicalUserType<'gcx> {
}
_ => false,
},
UnpackedKind::Const(ct) => match ct {
ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(debruijn, b)),
..
}) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(*debruijn, ty::INNERMOST);
cvar == *b
}
_ => false,
},
}
})
},
@ -2120,15 +2133,19 @@ macro_rules! sty_debug_print {
#[derive(Copy, Clone)]
struct DebugStat {
total: usize,
region_infer: usize,
lt_infer: usize,
ty_infer: usize,
both_infer: usize,
ct_infer: usize,
all_infer: usize,
}
pub fn go(tcx: TyCtxt<'_, '_, '_>) {
let mut total = DebugStat {
total: 0,
region_infer: 0, ty_infer: 0, both_infer: 0,
lt_infer: 0,
ty_infer: 0,
ct_infer: 0,
all_infer: 0,
};
$(let mut $variant = total;)*
@ -2139,31 +2156,35 @@ macro_rules! sty_debug_print {
ty::Error => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
variant.total += 1;
total.total += 1;
if region { total.region_infer += 1; variant.region_infer += 1 }
if lt { total.lt_infer += 1; variant.lt_infer += 1 }
if ty { total.ty_infer += 1; variant.ty_infer += 1 }
if region && ty { total.both_infer += 1; variant.both_infer += 1 }
if ct { total.ct_infer += 1; variant.ct_infer += 1 }
if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
}
println!("Ty interner total ty region both");
println!("Ty interner total ty lt ct all");
$(println!(" {:18}: {uses:6} {usespc:4.1}%, \
{ty:4.1}% {region:5.1}% {both:4.1}%",
stringify!($variant),
uses = $variant.total,
usespc = $variant.total as f64 * 100.0 / total.total as f64,
ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
region = $variant.region_infer as f64 * 100.0 / total.total as f64,
both = $variant.both_infer as f64 * 100.0 / total.total as f64);
)*
{ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
stringify!($variant),
uses = $variant.total,
usespc = $variant.total as f64 * 100.0 / total.total as f64,
ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
lt = $variant.lt_infer as f64 * 100.0 / total.total as f64,
ct = $variant.ct_infer as f64 * 100.0 / total.total as f64,
all = $variant.all_infer as f64 * 100.0 / total.total as f64);
)*
println!(" total {uses:6} \
{ty:4.1}% {region:5.1}% {both:4.1}%",
uses = total.total,
ty = total.ty_infer as f64 * 100.0 / total.total as f64,
region = total.region_infer as f64 * 100.0 / total.total as f64,
both = total.both_infer as f64 * 100.0 / total.total as f64)
{ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
uses = total.total,
ty = total.ty_infer as f64 * 100.0 / total.total as f64,
lt = total.lt_infer as f64 * 100.0 / total.total as f64,
ct = total.ct_infer as f64 * 100.0 / total.total as f64,
all = total.all_infer as f64 * 100.0 / total.total as f64)
}
}
@ -2518,7 +2539,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let adt_def = self.adt_def(def_id);
let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
match param.kind {
GenericParamDefKind::Lifetime => bug!(),
GenericParamDefKind::Lifetime |
GenericParamDefKind::Const => {
bug!()
}
GenericParamDefKind::Type { has_default, .. } => {
if param.index == 0 {
ty.into()
@ -2659,10 +2683,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
#[inline]
pub fn mk_var(self, v: TyVid) -> Ty<'tcx> {
pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
self.mk_infer(TyVar(v))
}
#[inline]
pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> {
self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Var(v)),
ty,
}))
}
#[inline]
pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
self.mk_infer(IntVar(v))
@ -2685,6 +2717,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_ty(Param(ParamTy { idx: index, name: name }))
}
#[inline]
pub fn mk_const_param(
self,
index: u32,
name: InternedString,
ty: Ty<'tcx>
) -> &'tcx LazyConst<'tcx> {
self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(ParamConst { index, name }),
ty,
}))
}
#[inline]
pub fn mk_self_type(self) -> Ty<'tcx> {
self.mk_ty_param(0, keywords::SelfUpper.name().as_interned_str())
@ -2695,7 +2740,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
GenericParamDefKind::Lifetime => {
self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
}
GenericParamDefKind::Type {..} => self.mk_ty_param(param.index, param.name).into(),
GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(),
GenericParamDefKind::Const => {
self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into()
}
}
}

View file

@ -1,5 +1,6 @@
use crate::ty::subst::SubstsRef;
use crate::ty::{self, Ty, TypeFlags, TypeFoldable};
use crate::ty::subst::{SubstsRef, UnpackedKind};
use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst};
use crate::mir::interpret::ConstValue;
#[derive(Debug)]
pub struct FlagComputation {
@ -232,6 +233,21 @@ impl FlagComputation {
}
}
fn add_const(&mut self, c: &ty::LazyConst<'_>) {
match c {
ty::LazyConst::Unevaluated(_, substs) => self.add_substs(substs),
// Only done to add the binder for the type. The type flags are
// included in `Const::type_flags`.
ty::LazyConst::Evaluated(ty::Const { ty, val }) => {
self.add_ty(ty);
if let ConstValue::Infer(InferConst::Canonical(debruijn, _)) = val {
self.add_binder(*debruijn)
}
}
}
self.add_flags(c.type_flags());
}
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs);
self.add_ty(projection.ty);
@ -242,12 +258,12 @@ impl FlagComputation {
}
fn add_substs(&mut self, substs: SubstsRef<'_>) {
for ty in substs.types() {
self.add_ty(ty);
}
for r in substs.regions() {
self.add_region(r);
for kind in substs {
match kind.unpack() {
UnpackedKind::Type(ty) => self.add_ty(ty),
UnpackedKind::Lifetime(lt) => self.add_region(lt),
UnpackedKind::Const(ct) => self.add_const(ct),
}
}
}
}

View file

@ -91,7 +91,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
self.has_type_flags(TypeFlags::HAS_TY_INFER)
}
fn needs_infer(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
self.has_type_flags(
TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER | TypeFlags::HAS_CT_INFER
)
}
fn has_placeholders(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER)
@ -117,7 +119,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
}
/// Indicates whether this value references only 'global'
/// types/lifetimes that are the same regardless of what fn we are
/// generic parameters that are the same regardless of what fn we are
/// in. This is used for caching.
fn is_global(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
@ -841,14 +843,13 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
}
fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
if let ty::LazyConst::Unevaluated(..) = c {
let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
TypeFlags::HAS_PROJECTION;
if projection_flags.intersects(self.flags) {
return true;
}
let flags = c.type_flags();
debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
if flags.intersects(self.flags) {
true
} else {
c.super_visit_with(self)
}
c.super_visit_with(self)
}
}

View file

@ -54,14 +54,14 @@ use crate::hir;
pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST};
pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{InferTy, ParamTy, ParamConst, InferConst, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TyKind, PolyTraitRef};
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const, LazyConst};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::RegionKind;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid};
pub use self::sty::{TyVid, IntVid, FloatVid, ConstVid, RegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::InferTy::*;
pub use self::sty::RegionKind::*;
@ -451,6 +451,8 @@ bitflags! {
const HAS_TY_PLACEHOLDER = 1 << 14;
const HAS_CT_INFER = 1 << 15;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
@ -462,6 +464,7 @@ bitflags! {
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_TY_INFER.bits |
TypeFlags::HAS_RE_INFER.bits |
TypeFlags::HAS_CT_INFER.bits |
TypeFlags::HAS_RE_PLACEHOLDER.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits |
TypeFlags::HAS_FREE_REGIONS.bits |
@ -837,7 +840,8 @@ pub enum GenericParamDefKind {
has_default: bool,
object_lifetime_default: ObjectLifetimeDefault,
synthetic: Option<hir::SyntheticTyParamKind>,
}
},
Const,
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
@ -880,6 +884,7 @@ impl GenericParamDef {
pub struct GenericParamCount {
pub lifetimes: usize,
pub types: usize,
pub consts: usize,
}
/// Information about the formal type/lifetime parameters associated
@ -915,6 +920,7 @@ impl<'a, 'gcx, 'tcx> Generics {
match param.kind {
GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
GenericParamDefKind::Type { .. } => own_counts.types += 1,
GenericParamDefKind::Const => own_counts.consts += 1,
};
}
@ -924,7 +930,7 @@ impl<'a, 'gcx, 'tcx> Generics {
pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
for param in &self.params {
match param.kind {
GenericParamDefKind::Type { .. } => return true,
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => return true,
GenericParamDefKind::Lifetime => {}
}
}
@ -944,7 +950,7 @@ impl<'a, 'gcx, 'tcx> Generics {
if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
let param = &self.params[index as usize];
match param.kind {
ty::GenericParamDefKind::Lifetime => param,
GenericParamDefKind::Lifetime => param,
_ => bug!("expected lifetime parameter, but found another generic parameter")
}
} else {
@ -961,7 +967,7 @@ impl<'a, 'gcx, 'tcx> Generics {
if let Some(index) = param.idx.checked_sub(self.parent_count as u32) {
let param = &self.params[index as usize];
match param.kind {
ty::GenericParamDefKind::Type {..} => param,
GenericParamDefKind::Type { .. } => param,
_ => bug!("expected type parameter, but found another generic parameter")
}
} else {
@ -969,6 +975,23 @@ impl<'a, 'gcx, 'tcx> Generics {
.type_param(param, tcx)
}
}
/// Returns the `ConstParameterDef` associated with this `ParamConst`.
pub fn const_param(&'tcx self,
param: &ParamConst,
tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> &GenericParamDef {
if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
let param = &self.params[index as usize];
match param.kind {
GenericParamDefKind::Const => param,
_ => bug!("expected const parameter, but found another generic parameter")
}
} else {
tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
.const_param(param, tcx)
}
}
}
/// Bounds on generics.

View file

@ -705,6 +705,9 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> {
(UnpackedKind::Type(unpacked), x) => {
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
}
(UnpackedKind::Const(_), _) => {
unimplemented!() // FIXME(const_generics)
}
}
}
}

View file

@ -5,12 +5,13 @@
use crate::mir::ProjectionKind;
use crate::mir::interpret::ConstValue;
use crate::ty::{self, Lift, Ty, TyCtxt};
use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use smallvec::SmallVec;
use crate::mir::interpret;
use std::marker::PhantomData;
use std::rc::Rc;
///////////////////////////////////////////////////////////////////////////
@ -49,6 +50,7 @@ CloneTypeFoldableAndLiftImpls! {
crate::ty::BoundRegion,
crate::ty::ClosureKind,
crate::ty::IntVarValue,
crate::ty::ParamConst,
crate::ty::ParamTy,
crate::ty::UniverseIndex,
crate::ty::Variance,
@ -503,6 +505,14 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
type Lifted = ConstValue<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ConstValue::Param(param) => Some(ConstValue::Param(param)),
ConstValue::Infer(infer) => {
Some(ConstValue::Infer(match infer {
InferConst::Var(vid) => InferConst::Var(vid.lift_to_tcx(tcx)?),
InferConst::Fresh(i) => InferConst::Fresh(i),
InferConst::Canonical(debrujin, var) => InferConst::Canonical(debrujin, var),
}))
}
ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)),
ConstValue::ByRef(ptr, alloc) => Some(ConstValue::ByRef(
@ -512,6 +522,16 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
}
}
impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> {
type Lifted = ConstVid<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
Some(ConstVid {
index: self.index,
phantom: PhantomData,
})
}
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
//

View file

@ -16,6 +16,7 @@ use crate::mir::interpret::{Scalar, Pointer};
use smallvec::SmallVec;
use std::iter;
use std::cmp::Ordering;
use std::marker::PhantomData;
use rustc_target::spec::abi;
use syntax::ast::{self, Ident};
use syntax::symbol::{keywords, InternedString};
@ -1061,6 +1062,26 @@ impl<'a, 'gcx, 'tcx> ParamTy {
}
}
#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
pub struct ParamConst {
pub index: u32,
pub name: InternedString,
}
impl<'a, 'gcx, 'tcx> ParamConst {
pub fn new(index: u32, name: InternedString) -> ParamConst {
ParamConst { index, name }
}
pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
ParamConst::new(def.index, def.name)
}
pub fn to_const(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> {
tcx.mk_const_param(self.index, self.name, ty)
}
}
/// A [De Bruijn index][dbi] is a standard means of representing
/// regions (and perhaps later types) in a higher-ranked setting. In
/// particular, imagine a type like this:
@ -1229,6 +1250,12 @@ pub struct TyVid {
pub index: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct ConstVid<'tcx> {
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct IntVid {
pub index: u32,
@ -2083,6 +2110,22 @@ impl<'tcx> LazyConst<'tcx> {
pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
self.assert_usize(tcx).expect("expected `LazyConst` to contain a usize")
}
pub fn type_flags(&self) -> TypeFlags {
// FIXME(const_generics): incorporate substs flags.
let flags = match self {
LazyConst::Unevaluated(..) => {
TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION
}
LazyConst::Evaluated(c) => {
c.type_flags()
}
};
debug!("type_flags({:?}) = {:?}", self, flags);
flags
}
}
/// Typed constant value.
@ -2198,6 +2241,44 @@ impl<'tcx> Const<'tcx> {
self.assert_usize(tcx).unwrap_or_else(||
bug!("expected constant usize, got {:#?}", self))
}
pub fn type_flags(&self) -> TypeFlags {
let mut flags = self.ty.flags;
match self.val {
ConstValue::Param(_) => {
flags |= TypeFlags::HAS_FREE_LOCAL_NAMES;
flags |= TypeFlags::HAS_PARAMS;
}
ConstValue::Infer(infer) => {
flags |= TypeFlags::HAS_FREE_LOCAL_NAMES;
flags |= TypeFlags::HAS_CT_INFER;
match infer {
InferConst::Fresh(_) |
InferConst::Canonical(_, _) => {}
InferConst::Var(_) => {
flags |= TypeFlags::KEEP_IN_LOCAL_TCX;
}
}
}
_ => {}
}
debug!("type_flags({:?}) = {:?}", self, flags);
flags
}
}
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {}
/// An inference variable for a const, for use in const generics.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum InferConst<'tcx> {
/// Infer the value of the const.
Var(ConstVid<'tcx>),
/// A fresh const variable. See `infer::freshen` for more details.
Fresh(u32),
/// Canonicalized const variable, used only when preparing a trait query.
Canonical(DebruijnIndex, BoundVar),
}

View file

@ -2,8 +2,9 @@
use crate::hir::def_id::DefId;
use crate::infer::canonical::Canonical;
use crate::ty::{self, Lift, List, Ty, TyCtxt};
use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::mir::interpret::ConstValue;
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
use syntax_pos::{Span, DUMMY_SP};
@ -17,24 +18,26 @@ use std::mem;
use std::num::NonZeroUsize;
/// An entity in the Rust type system, which can be one of
/// several kinds (only types and lifetimes for now).
/// several kinds (types, lifetimes, and consts).
/// To reduce memory usage, a `Kind` is a interned pointer,
/// with the lowest 2 bits being reserved for a tag to
/// indicate the type (`Ty` or `Region`) it points to.
/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Kind<'tcx> {
ptr: NonZeroUsize,
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::LazyConst<'tcx>)>
}
const TAG_MASK: usize = 0b11;
const TYPE_TAG: usize = 0b00;
const REGION_TAG: usize = 0b01;
const CONST_TAG: usize = 0b10;
#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)]
pub enum UnpackedKind<'tcx> {
Lifetime(ty::Region<'tcx>),
Type(Ty<'tcx>),
Const(&'tcx ty::LazyConst<'tcx>),
}
impl<'tcx> UnpackedKind<'tcx> {
@ -50,6 +53,11 @@ impl<'tcx> UnpackedKind<'tcx> {
assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
(TYPE_TAG, ty as *const _ as usize)
}
UnpackedKind::Const(ct) => {
// Ensure we can use the tag bits.
assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0);
(CONST_TAG, ct as *const _ as usize)
}
};
Kind {
@ -85,6 +93,12 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
}
}
impl<'tcx> From<&'tcx ty::LazyConst<'tcx>> for Kind<'tcx> {
fn from(c: &'tcx ty::LazyConst<'tcx>) -> Kind<'tcx> {
UnpackedKind::Const(c).pack()
}
}
impl<'tcx> Kind<'tcx> {
#[inline]
pub fn unpack(self) -> UnpackedKind<'tcx> {
@ -93,6 +107,7 @@ impl<'tcx> Kind<'tcx> {
match ptr & TAG_MASK {
REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
CONST_TAG => UnpackedKind::Const(&*((ptr & !TAG_MASK) as *const _)),
_ => intrinsics::unreachable()
}
}
@ -104,6 +119,7 @@ impl<'tcx> fmt::Debug for Kind<'tcx> {
match self.unpack() {
UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
UnpackedKind::Const(ct) => write!(f, "{:?}", ct),
}
}
}
@ -113,6 +129,7 @@ impl<'tcx> fmt::Display for Kind<'tcx> {
match self.unpack() {
UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
UnpackedKind::Type(ty) => write!(f, "{}", ty),
UnpackedKind::Const(ct) => write!(f, "{}", ct),
}
}
}
@ -122,8 +139,9 @@ impl<'a, 'tcx> Lift<'tcx> for Kind<'a> {
fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match self.unpack() {
UnpackedKind::Lifetime(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
UnpackedKind::Type(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
UnpackedKind::Lifetime(lt) => lt.lift_to_tcx(tcx).map(|lt| lt.into()),
UnpackedKind::Type(ty) => ty.lift_to_tcx(tcx).map(|ty| ty.into()),
UnpackedKind::Const(ct) => ct.lift_to_tcx(tcx).map(|ct| ct.into()),
}
}
}
@ -133,6 +151,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
match self.unpack() {
UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
UnpackedKind::Const(ct) => ct.fold_with(folder).into(),
}
}
@ -140,6 +159,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
match self.unpack() {
UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
UnpackedKind::Type(ty) => ty.visit_with(visitor),
UnpackedKind::Const(ct) => ct.visit_with(visitor),
}
}
}
@ -195,6 +215,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
ty::BoundRegion::BrNamed(param.def_id, param.name)
)).into()
}
ty::GenericParamDefKind::Const => {
tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(
InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index))
),
ty: tcx.type_of(def_id),
})).into()
}
}
})
}
@ -283,6 +312,29 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
})
}
#[inline]
pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::LazyConst<'tcx>> + 'a {
self.iter().filter_map(|k| {
if let UnpackedKind::Const(ct) = k.unpack() {
Some(ct)
} else {
None
}
})
}
#[inline]
pub fn non_erasable_generics(
&'a self
) -> impl DoubleEndedIterator<Item = UnpackedKind<'tcx>> + 'a {
self.iter().filter_map(|k| {
match k.unpack() {
UnpackedKind::Lifetime(_) => None,
generic => Some(generic),
}
})
}
#[inline]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
if let UnpackedKind::Type(ty) = self[i].unpack() {
@ -301,6 +353,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
}
}
#[inline]
pub fn const_at(&self, i: usize) -> &'tcx ty::LazyConst<'tcx> {
if let UnpackedKind::Const(ct) = self[i].unpack() {
ct
} else {
bug!("expected const for param #{} in {:?}", i, self);
}
}
#[inline]
pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> {
self.type_at(def.index as usize).into()
@ -469,6 +530,21 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
return t1;
}
fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
if !c.needs_subst() {
return c;
}
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(p),
..
}) = c {
self.const_for_param(*p, c)
} else {
c.super_fold_with(self)
}
}
}
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
@ -494,6 +570,34 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
self.shift_vars_through_binders(ty)
}
fn const_for_param(
&self,
p: ParamConst,
source_cn: &'tcx ty::LazyConst<'tcx>
) -> &'tcx ty::LazyConst<'tcx> {
// Look up the const in the substitutions. It really should be in there.
let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack());
let cn = match opt_cn {
Some(UnpackedKind::Const(cn)) => cn,
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
span,
"Const parameter `{:?}` ({:?}/{}) out of range \
when substituting (root type={:?}) substs={:?}",
p,
source_cn,
p.index,
self.root_ty,
self.substs,
);
}
};
// FIXME(const_generics): shift const through binders
cn
}
/// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
/// when we are substituting a type with escaping bound vars into a context where we have
/// passed through binders. That's quite a mouthful. Let's see an example:

View file

@ -12,6 +12,7 @@ use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind};
use crate::ty::query::TyCtxtAt;
use crate::ty::TyKind::*;
use crate::ty::layout::{Integer, IntegerExt};
use crate::mir::interpret::ConstValue;
use crate::util::common::ErrorReported;
use crate::middle::lang_items;
@ -495,8 +496,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}) => {
!impl_generics.type_param(pt, self).pure_wrt_drop
}
UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => {
// not a type or region param - this should be reported
UnpackedKind::Const(&ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(ref pc),
..
})) => {
!impl_generics.const_param(pc, self).pure_wrt_drop
}
UnpackedKind::Lifetime(_) |
UnpackedKind::Type(_) |
UnpackedKind::Const(_) => {
// Not a type, const or region param: this should be reported
// as an error.
false
}
@ -587,15 +596,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
Some(ty::Binder::bind(env_ty))
}
/// Given the `DefId` of some item that has no type parameters, make
/// Given the `DefId` of some item that has no type or const parameters, make
/// a suitable "empty substs" for it.
pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> {
InternalSubsts::for_item(self, item_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => self.types.re_erased.into(),
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } => {
bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
}
GenericParamDefKind::Const { .. } => {
bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id)
}
}
})
}

View file

@ -8,7 +8,8 @@ use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind, ParamConst};
use crate::mir::interpret::ConstValue;
use crate::util::nodemap::FxHashSet;
use std::cell::Cell;
@ -478,6 +479,7 @@ impl PrintContext {
GenericParamDefKind::Type { has_default, .. } => {
Some((param.def_id, has_default))
}
GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
}).peekable();
let has_default = {
let has_default = type_params.peek().map(|(_, has_default)| has_default);
@ -571,6 +573,14 @@ impl PrintContext {
)?;
}
// FIXME(const_generics::defaults)
let consts = substs.consts();
for ct in consts {
start_or_continue(f, "<", ", ")?;
ct.print_display(f, self)?;
}
start_or_continue(f, "", ">")?;
// For values, also print their name and type parameters.
@ -763,7 +773,8 @@ impl fmt::Debug for ty::GenericParamDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let type_name = match self.kind {
ty::GenericParamDefKind::Lifetime => "Lifetime",
ty::GenericParamDefKind::Type {..} => "Type",
ty::GenericParamDefKind::Type { .. } => "Type",
ty::GenericParamDefKind::Const => "Const",
};
write!(f, "{}({}, {:?}, {})",
type_name,
@ -1088,6 +1099,12 @@ impl fmt::Debug for ty::TyVid {
}
}
impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "_#{}f", self.index)
}
}
impl fmt::Debug for ty::IntVid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "_#{}i", self.index)
@ -1448,7 +1465,12 @@ define_print! {
write!(f, "_")?;
}
ty::LazyConst::Evaluated(c) => ty::tls::with(|tcx| {
write!(f, "{}", c.unwrap_usize(tcx))
match c.val {
ConstValue::Infer(..) => write!(f, "_"),
ConstValue::Param(ParamConst { name, .. }) =>
write!(f, "{}", name),
_ => write!(f, "{}", c.unwrap_usize(tcx)),
}
})?,
}
write!(f, "]")
@ -1472,6 +1494,37 @@ define_print! {
}
}
define_print! {
('tcx) ConstValue<'tcx>, (self, f, cx) {
display {
match self {
ConstValue::Infer(..) => write!(f, "_"),
ConstValue::Param(ParamConst { name, .. }) => write!(f, "{}", name),
_ => write!(f, "{:?}", self),
}
}
}
}
define_print! {
('tcx) ty::Const<'tcx>, (self, f, cx) {
display {
write!(f, "{} : {}", self.val, self.ty)
}
}
}
define_print! {
('tcx) ty::LazyConst<'tcx>, (self, f, cx) {
display {
match self {
ty::LazyConst::Unevaluated(..) => write!(f, "_ : _"),
ty::LazyConst::Evaluated(c) => write!(f, "{}", c),
}
}
}
}
define_print! {
() ty::ParamTy, (self, f, cx) {
display {
@ -1483,6 +1536,17 @@ define_print! {
}
}
define_print! {
() ty::ParamConst, (self, f, cx) {
display {
write!(f, "{}", self.name)
}
debug {
write!(f, "{}/#{}", self.name, self.index)
}
}
}
define_print! {
('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate<T, U>,
(self, f, cx) {

View file

@ -113,7 +113,7 @@ pub fn get_fn(
unsafe {
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
let is_generic = instance.substs.types().next().is_some();
let is_generic = instance.substs.non_erasable_generics().next().is_some();
if is_generic {
// This is a monomorphization. Its expected visibility depends

View file

@ -263,7 +263,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def: InstanceDef::Item(def_id),
substs,
}) = mono_item {
if substs.types().next().is_some() {
if substs.non_erasable_generics().next().is_some() {
symbols.push((ExportedSymbol::Generic(def_id, substs),
SymbolExportLevel::Rust));
}

View file

@ -76,6 +76,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
}
let val = match val.val {
ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"),
ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"),
ConstValue::Scalar(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,

View file

@ -172,7 +172,7 @@ fn get_symbol_hash<'a, 'tcx>(
assert!(!substs.needs_subst());
substs.hash_stable(&mut hcx, &mut hasher);
let is_generic = substs.types().next().is_some();
let is_generic = substs.non_erasable_generics().next().is_some();
let avoid_cross_crate_conflicts =
// If this is an instance of a generic function, we also hash in
// the ID of the instantiating crate. This avoids symbol conflicts

View file

@ -604,7 +604,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
search_stack.push((ty, hir_ty));
}
(UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => {
(UnpackedKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
// Lifetimes cannot be found in consts, so we don't need
// to search anything here.
}
(UnpackedKind::Lifetime(_), _)
| (UnpackedKind::Type(_), _)
| (UnpackedKind::Const(_), _) => {
// I *think* that HIR lowering should ensure this
// doesn't happen, even in erroneous
// programs. Else we should use delay-span-bug.

View file

@ -99,6 +99,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
param_env,
).type_must_outlive(origin, t1, r2);
}
UnpackedKind::Const(_) => {
// Consts cannot outlive one another, so we
// don't need to handle any relations here.
}
}
}

View file

@ -2533,7 +2533,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
),
))
}
UnpackedKind::Type(_) => None,
UnpackedKind::Type(_) | UnpackedKind::Const(_) => None,
}
})
.collect();

View file

@ -5,7 +5,7 @@ use crate::hair::cx::to_ref::ToRef;
use crate::hair::util::UserAnnotatedTyHelpers;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def::{Def, CtorKind};
use rustc::mir::interpret::{GlobalId, ErrorHandled};
use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue};
use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::ty::cast::CastKind as TyCastKind;
@ -699,7 +699,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
};
let source = if let Some((did, offset, var_ty)) = var {
let mk_const = |literal| Expr {
let mk_lazy_const = |literal| Expr {
temp_lifetime,
ty: var_ty,
span: expr.span,
@ -708,7 +708,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
user_ty: None
},
}.to_ref();
let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
let offset = mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
cx.tcx,
offset as u128,
cx.param_env.and(var_ty),
@ -718,7 +718,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs));
let lhs = mk_lazy_const(ty::LazyConst::Unevaluated(did, substs));
let bin = ExprKind::Binary {
op: BinOp::Add,
lhs,
@ -925,7 +925,26 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
))),
user_ty,
}
},
}
Def::ConstParam(def_id) => {
let node_id = cx.tcx.hir().as_local_node_id(def_id).unwrap();
let item_id = cx.tcx.hir().get_parent_node(node_id);
let item_def_id = cx.tcx.hir().local_def_id(item_id);
let generics = cx.tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&cx.tcx.hir().local_def_id(node_id)];
let name = cx.tcx.hir().name(node_id).as_interned_str();
let val = ConstValue::Param(ty::ParamConst::new(index, name));
ExprKind::Literal {
literal: cx.tcx.mk_lazy_const(
ty::LazyConst::Evaluated(ty::Const {
val,
ty: cx.tables().node_type(expr.hir_id),
})
),
user_ty: None,
}
}
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {

View file

@ -589,11 +589,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
val: ty::Const<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let val = self.monomorphize(val)?;
let layout = from_known_layout(layout, || {
let ty = self.monomorphize(val.ty)?;
self.layout_of(ty)
self.layout_of(val.ty)
})?;
let op = match val.val {
ConstValue::Param(_) | ConstValue::Infer(_) => bug!(),
ConstValue::ByRef(ptr, alloc) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.

View file

@ -466,7 +466,16 @@ 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()
.flat_map(|ct| {
let ty = match ct {
ty::LazyConst::Evaluated(ct) => ct.ty,
ty::LazyConst::Unevaluated(def_id, _) => tcx.type_of(*def_id),
};
ty.walk()
})
.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 +484,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 +501,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 +770,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 +1124,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() {

View file

@ -2,7 +2,7 @@ use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::mir::*;
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::VariantIdx;
use rustc::ty::subst::{Subst, InternalSubsts};
use rustc::ty::query::Providers;
@ -450,12 +450,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
) {
let tcx = self.tcx;
let substs = InternalSubsts::for_item(tcx, self.def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
GenericParamDefKind::Type {..} => ty.into(),
}
});
let substs = tcx.mk_substs_trait(ty, &[]);
// `func == Clone::clone(&ty) -> ty`
let func_ty = tcx.mk_fn_def(self.def_id, substs);

View file

@ -558,9 +558,10 @@ fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: D
// FIXME: when we make this a hard error, this should have its
// own error code.
let message = if tcx.generics_of(def_id).own_counts().types != 0 {
let counts = tcx.generics_of(def_id).own_counts();
let message = if counts.types + counts.consts != 0 {
"#[derive] can't be used on a #[repr(packed)] struct with \
type parameters (error E0133)".to_string()
type or const parameters (error E0133)".to_string()
} else {
"#[derive] can't be used on a #[repr(packed)] struct that \
does not derive Copy (error E0133)".to_string()

View file

@ -259,7 +259,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
// inlining. This is to ensure that the final crate doesn't have MIR that
// reference unexported symbols
if callsite.callee.is_local() {
if callsite.substs.types().count() == 0 && !hinted {
if callsite.substs.non_erasable_generics().count() == 0 && !hinted {
debug!(" callee is an exported function - not inlining");
return false;
}

View file

@ -748,12 +748,15 @@ impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
for param in &self.ev.tcx.generics_of(self.item_def_id).params {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Type { has_default, .. } => {
if has_default {
self.visit(self.ev.tcx.type_of(param.def_id));
}
}
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Const => {
self.visit(self.ev.tcx.type_of(param.def_id));
}
}
}
self
@ -1517,12 +1520,15 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
for param in &self.tcx.generics_of(self.item_def_id).params {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Type { has_default, .. } => {
if has_default {
self.visit(self.tcx.type_of(param.def_id));
}
}
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Const => {
self.visit(self.tcx.type_of(param.def_id));
}
}
}
self

View file

@ -32,11 +32,12 @@ use rustc::traits::{
InEnvironment,
ChalkCanonicalGoal,
};
use rustc::ty::{self, TyCtxt};
use rustc::ty::{self, TyCtxt, InferConst};
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use rustc::ty::query::Providers;
use rustc::ty::subst::{Kind, UnpackedKind};
use rustc_data_structures::sync::Lrc;
use rustc::mir::interpret::ConstValue;
use syntax_pos::DUMMY_SP;
use std::fmt::{self, Debug};
@ -287,6 +288,16 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
}
_ => false,
},
UnpackedKind::Const(ct) => match ct {
ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
..
}) => {
debug_assert_eq!(*debruijn, ty::INNERMOST);
cvar == *bound_ct
}
_ => false,
}
})
}

View file

@ -3,7 +3,7 @@
//! instance of `AstConv`.
use errors::{Applicability, DiagnosticId};
use crate::hir::{self, GenericArg, GenericArgs};
use crate::hir::{self, GenericArg, GenericArgs, ExprKind};
use crate::hir::def::Def;
use crate::hir::def_id::DefId;
use crate::hir::HirVec;
@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
use rustc::ty::wf::object_region_bounds;
use rustc::mir::interpret::ConstValue;
use rustc_data_structures::sync::Lrc;
use rustc_target::spec::abi;
use crate::require_c_abi_if_c_variadic;
@ -273,6 +274,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let param_counts = def.own_counts();
let arg_counts = args.own_counts();
let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0;
let mut defaults: ty::GenericParamCount = Default::default();
for param in &def.params {
@ -281,6 +283,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
GenericParamDefKind::Type { has_default, .. } => {
defaults.types += has_default as usize
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
}
};
}
@ -311,11 +316,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
}
}
let check_kind_count = |kind,
required,
permitted,
provided,
offset| {
let check_kind_count = |kind, required, permitted, provided, offset| {
debug!(
"check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}",
kind,
required,
permitted,
provided,
offset
);
// We enforce the following: `required` <= `provided` <= `permitted`.
// For kinds without defaults (i.e., lifetimes), `required == permitted`.
// For other kinds (i.e., types), `permitted` may be greater than `required`.
@ -384,6 +393,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
0,
);
}
// FIXME(const_generics:defaults)
if !infer_consts || arg_counts.consts > param_counts.consts {
check_kind_count(
"const",
param_counts.consts,
param_counts.consts,
arg_counts.consts,
arg_counts.lifetimes + arg_counts.types,
);
}
// Note that type errors are currently be emitted *after* const errors.
if !infer_types
|| arg_counts.types > param_counts.types - defaults.types - has_self as usize {
check_kind_count(
@ -495,7 +515,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
(Some(&arg), Some(&param)) => {
match (arg, &param.kind) {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime)
| (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => {
| (GenericArg::Type(_), GenericParamDefKind::Type { .. })
| (GenericArg::Const(_), GenericParamDefKind::Const) => {
substs.push(provided_kind(param, arg));
args.next();
params.next();
@ -606,6 +627,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.ast_ty_to_ty(&ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into()
}
_ => unreachable!(),
}
},
@ -654,6 +678,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
tcx.types.err.into()
}
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// We've already errored above about the mismatch.
tcx.types.err.into()
}
}
},
);
@ -1609,6 +1638,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
// Case 3. Reference to a top-level value.
Def::Fn(def_id) |
Def::Const(def_id) |
Def::ConstParam(def_id) |
Def::Static(def_id, _) => {
path_segs.push(PathSeg(def_id, last));
}
@ -1797,10 +1827,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, def, segment, false).0
}
hir::TyKind::Array(ref ty, ref length) => {
let length_def_id = tcx.hir().local_def_id_from_hir_id(length.hir_id);
let substs = InternalSubsts::identity_for_item(tcx, length_def_id);
let length = ty::LazyConst::Unevaluated(length_def_id, substs);
let length = tcx.mk_lazy_const(length);
let length = self.ast_const_to_const(length, tcx.types.usize);
let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
@ -1837,6 +1864,42 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
result_ty
}
pub fn ast_const_to_const(
&self,
ast_const: &hir::AnonConst,
ty: Ty<'tcx>
) -> &'tcx ty::LazyConst<'tcx> {
debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const);
let tcx = self.tcx();
let def_id = tcx.hir().local_def_id_from_hir_id(ast_const.hir_id);
let mut lazy_const = ty::LazyConst::Unevaluated(
def_id,
InternalSubsts::identity_for_item(tcx, def_id),
);
let expr = &tcx.hir().body(ast_const.body).value;
if let ExprKind::Path(ref qpath) = expr.node {
if let hir::QPath::Resolved(_, ref path) = qpath {
if let Def::ConstParam(def_id) = path.def {
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
let item_id = tcx.hir().get_parent_node(node_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
let name = tcx.hir().name(node_id).as_interned_str();
lazy_const = ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(ty::ParamConst::new(index, name)),
ty,
})
}
}
};
tcx.mk_lazy_const(lazy_const)
}
pub fn impl_trait_ty_to_ty(
&self,
def_id: DefId,

View file

@ -99,11 +99,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => {
span_bug!(expr.span, "closure has region param")
span_bug!(expr.span, "closure has lifetime param")
}
GenericParamDefKind::Type {..} => {
self.infcx
.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
GenericParamDefKind::Type { .. } => {
self.infcx.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
}
GenericParamDefKind::Const => {
span_bug!(expr.span, "closure has const param")
}
}
});

View file

@ -6,7 +6,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef};
use rustc::util::common::ErrorReported;
use errors::Applicability;
use errors::{Applicability, DiagnosticId};
use syntax_pos::Span;
@ -576,55 +576,78 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Ok(())
}
fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
trait_m: &ty::AssociatedItem,
trait_item_span: Option<Span>)
-> Result<(), ErrorReported> {
let impl_m_generics = tcx.generics_of(impl_m.def_id);
let trait_m_generics = tcx.generics_of(trait_m.def_id);
let num_impl_m_type_params = impl_m_generics.own_counts().types;
let num_trait_m_type_params = trait_m_generics.own_counts().types;
fn compare_number_of_generics<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_: &ty::AssociatedItem,
impl_span: Span,
trait_: &ty::AssociatedItem,
trait_span: Option<Span>,
) -> Result<(), ErrorReported> {
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
if num_impl_m_type_params != num_trait_m_type_params {
let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap();
let impl_m_item = tcx.hir().expect_impl_item(impl_m_node_id);
let span = if impl_m_item.generics.params.is_empty()
|| impl_m_item.generics.span.is_dummy() // impl Trait in argument position (#55374)
{
impl_m_span
} else {
impl_m_item.generics.span
};
let matchings = [
("type", trait_own_counts.types, impl_own_counts.types),
("const", trait_own_counts.consts, impl_own_counts.consts),
];
let mut err = struct_span_err!(tcx.sess, span, E0049,
"method `{}` has {} but its trait declaration has {}",
trait_m.ident,
potentially_plural_count(num_impl_m_type_params, "type parameter"),
potentially_plural_count(num_trait_m_type_params, "type parameter")
);
let mut err_occurred = false;
for &(kind, trait_count, impl_count) in &matchings {
if impl_count != trait_count {
err_occurred = true;
let mut suffix = None;
let impl_node_id = tcx.hir().as_local_node_id(impl_.def_id).unwrap();
let impl_item = tcx.hir().expect_impl_item(impl_node_id);
let span = if impl_item.generics.params.is_empty()
|| impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374)
impl_span
} else {
impl_item.generics.span
};
if let Some(span) = trait_item_span {
err.span_label(span, format!("expected {}",
potentially_plural_count(num_trait_m_type_params, "type parameter")));
} else {
suffix = Some(format!(", expected {}", num_trait_m_type_params));
let mut err = tcx.sess.struct_span_err_with_code(
span,
&format!(
"method `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
trait_.ident,
impl_count,
if impl_count != 1 { "s" } else { "" },
trait_count,
if trait_count != 1 { "s" } else { "" },
kind = kind,
),
DiagnosticId::Error("E0049".into()),
);
let mut suffix = None;
if let Some(span) = trait_span {
err.span_label(
span,
format!("expected {} {} parameter{}", trait_count, kind,
if trait_count != 1 { "s" } else { "" })
);
} else {
suffix = Some(format!(", expected {}", trait_count));
}
err.span_label(
span,
format!("found {} {} parameter{}{}", impl_count, kind,
if impl_count != 1 { "s" } else { "" },
suffix.unwrap_or_else(|| String::new())),
);
err.emit();
}
err.span_label(span,
format!("found {}{}",
potentially_plural_count(num_impl_m_type_params, "type parameter"),
suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
err.emit();
return Err(ErrorReported);
}
Ok(())
if err_occurred {
Err(ErrorReported)
} else {
Ok(())
}
}
fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -725,12 +748,12 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_m_generics = tcx.generics_of(trait_m.def_id);
let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
GenericParamDefKind::Lifetime => None,
GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
});
let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
match param.kind {
GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
GenericParamDefKind::Lifetime => None,
GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
}
});
for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic))

View file

@ -313,6 +313,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
match kind.unpack() {
UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r),
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
UnpackedKind::Const(_) => {
// Generic consts don't add constraints.
}
}
}
Ok(())

View file

@ -341,6 +341,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.to_ty(ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
}
_ => unreachable!(),
}
},

View file

@ -283,8 +283,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const => {}
GenericParamDefKind::Type { .. } => {
if param.index == 0 {
return self_ty.into();
} else if let Some(ref input_types) = opt_input_types {

View file

@ -1528,7 +1528,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
// `impl_self_ty()` for an explanation.
self.tcx.types.re_erased.into()
}
GenericParamDefKind::Type {..} => self.var_for_def(self.span, param),
GenericParamDefKind::Type { .. }
| GenericParamDefKind::Const => {
self.var_for_def(self.span, param)
}
}
}
});
@ -1545,10 +1548,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
InternalSubsts::for_item(self.tcx, def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(),
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } => {
self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder(
self.tcx.def_span(def_id))).into()
}
GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
}
})
}

View file

@ -2437,6 +2437,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty
}
pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
AstConv::ast_const_to_const(self, ast_c, ty)
}
// If the type given by the user has free regions, save it for later, since
// NLL would like to enforce those. Also pass in types that involve
// projections, since those can resolve to `'static` bounds (modulo #54940,
@ -5501,6 +5505,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
self.to_ty(ty).into()
}
(GenericParamDefKind::Const, GenericArg::Const(ct)) => {
self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
}
_ => unreachable!(),
}
},
@ -5528,6 +5535,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.var_for_def(span, param)
}
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// No const parameters were provided, we have to infer them.
self.var_for_def(span, param)
}
}
},
);
@ -5685,11 +5697,19 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics: &ty::Generics,
ty: Ty<'tcx>) {
let own_counts = generics.own_counts();
debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty);
debug!(
"check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})",
own_counts.types,
own_counts.consts,
ty
);
// FIXME(const_generics): we probably want to check the bounds for const parameters too.
if own_counts.types == 0 {
return;
}
// Make a vector of booleans initially false, set to true when used.
let mut types_used = vec![false; own_counts.types];

View file

@ -81,7 +81,7 @@ use rustc::hir::def_id::DefId;
use rustc::infer::outlives::env::OutlivesEnvironment;
use rustc::infer::{self, RegionObligation, SuppressRegionErrors};
use rustc::ty::adjustment;
use rustc::ty::subst::SubstsRef;
use rustc::ty::subst::{SubstsRef, UnpackedKind};
use rustc::ty::{self, Ty};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -1407,13 +1407,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
let origin = infer::ParameterInScope(origin, expr_span);
for region in substs.regions() {
self.sub_regions(origin.clone(), expr_region, region);
}
for ty in substs.types() {
let ty = self.resolve_type(ty);
self.type_must_outlive(origin.clone(), ty, expr_region);
for kind in substs {
match kind.unpack() {
UnpackedKind::Lifetime(lt) => {
self.sub_regions(origin.clone(), expr_region, lt);
}
UnpackedKind::Type(ty) => {
let ty = self.resolve_type(ty);
self.type_must_outlive(origin.clone(), ty, expr_region);
}
UnpackedKind::Const(_) => {
// Const parameters don't impose constraints.
}
}
}
}
}

View file

@ -6,6 +6,7 @@ use rustc::traits::{self, ObligationCauseCode};
use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate};
use rustc::ty::subst::{Subst, InternalSubsts};
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::mir::interpret::ConstValue;
use rustc::middle::lang_items;
use rustc::infer::opaque_types::may_define_existential_type;
@ -436,7 +437,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
// struct Foo<T = Vec<[u32]>> { .. }
// Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
for param in &generics.params {
if let GenericParamDefKind::Type {..} = param.kind {
if let GenericParamDefKind::Type { .. } = param.kind {
if is_our_default(&param) {
let ty = fcx.tcx.type_of(param.def_id);
// ignore dependent defaults -- that is, where the default of one type
@ -464,7 +465,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
// All regions are identity.
fcx.tcx.mk_param_from_def(param)
}
GenericParamDefKind::Type {..} => {
GenericParamDefKind::Type { .. } => {
// If the param has a default,
if is_our_default(param) {
let default_ty = fcx.tcx.type_of(param.def_id);
@ -477,6 +478,10 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
// Mark unwanted params as err.
fcx.tcx.types.err.into()
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
fcx.tcx.types.err.into()
}
}
});
// Now we build the substituted predicates.
@ -497,6 +502,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool {
true
}
fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(param),
..
}) = c {
self.params.insert(param.index);
}
c.super_visit_with(self)
}
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count);
@ -617,11 +632,10 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
for (subst, param) in substs.iter().zip(&generics.params) {
match subst.unpack() {
ty::subst::UnpackedKind::Type(ty) => match ty.sty {
ty::Param(..) => {},
ty::Param(..) => {}
// prevent `fn foo() -> Foo<u32>` from being defining
_ => {
tcx
.sess
tcx.sess
.struct_span_err(
span,
"non-defining existential type use \
@ -636,8 +650,9 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
),
)
.emit();
},
}, // match ty
}
}
ty::subst::UnpackedKind::Lifetime(region) => {
let param_span = tcx.def_span(param.def_id);
if let ty::ReStatic = region {
@ -658,7 +673,31 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
} else {
seen.entry(region).or_default().push(param_span);
}
},
}
ty::subst::UnpackedKind::Const(ct) => match ct {
ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(_),
..
}) => {}
_ => {
tcx.sess
.struct_span_err(
span,
"non-defining existential type use \
in defining scope",
)
.span_note(
tcx.def_span(param.def_id),
&format!(
"used non-generic const {} for \
generic parameter",
ty,
),
)
.emit();
}
}
} // match subst
} // for (subst, param)
for (_, spans) in seen {
@ -942,7 +981,9 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) {
let parent = tcx.generics_of(generics.parent.unwrap());
let impl_params: FxHashMap<_, _> = parent.params.iter().flat_map(|param| match param.kind {
GenericParamDefKind::Lifetime => None,
GenericParamDefKind::Type {..} => Some((param.name, param.def_id)),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
Some((param.name, param.def_id))
}
}).collect();
for method_param in &generics.params {

View file

@ -1004,67 +1004,65 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
ast_generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Type {
ref default,
synthetic,
..
} => {
if param.name.ident().name == keywords::SelfUpper.name() {
span_bug!(
param.span,
"`Self` should not be the name of a regular parameter"
);
}
if !allow_defaults && default.is_some() {
if !tcx.features().default_type_parameter_fallback {
tcx.lint_hir(
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
param.hir_id,
.filter_map(|param| {
let kind = match param.kind {
GenericParamKind::Type {
ref default,
synthetic,
..
} => {
if param.name.ident().name == keywords::SelfUpper.name() {
span_bug!(
param.span,
&format!(
"defaults for type parameters are only allowed in \
`struct`, `enum`, `type`, or `trait` definitions."
),
"`Self` should not be the name of a regular parameter"
);
}
}
let ty_param = ty::GenericParamDef {
index: type_start + i as u32,
name: param.name.ident().as_interned_str(),
def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Type {
if !allow_defaults && default.is_some() {
if !tcx.features().default_type_parameter_fallback {
tcx.lint_hir(
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
param.hir_id,
param.span,
&format!(
"defaults for type parameters are only allowed in \
`struct`, `enum`, `type`, or `trait` definitions."
),
);
}
}
ty::GenericParamDefKind::Type {
has_default: default.is_some(),
object_lifetime_default: object_lifetime_defaults
.as_ref()
.map_or(rl::Set1::Empty, |o| o[i]),
synthetic,
},
};
i += 1;
Some(ty_param)
}
GenericParamKind::Const { .. } => {
if param.name.ident().name == keywords::SelfUpper.name() {
span_bug!(
param.span,
"`Self` should not be the name of a regular parameter",
);
}
}
GenericParamKind::Const { .. } => {
if param.name.ident().name == keywords::SelfUpper.name() {
span_bug!(
param.span,
"`Self` should not be the name of a regular parameter",
);
}
// Emit an error, but skip the parameter rather than aborting to
// continue to get other errors.
tcx.sess.struct_span_err(
param.span,
"const generics in any position are currently unsupported",
).emit();
None
}
_ => None,
}),
ty::GenericParamDefKind::Const
}
_ => return None,
};
let param_def = ty::GenericParamDef {
index: type_start + i as u32,
name: param.name.ident().as_interned_str(),
def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id),
pure_wrt_drop: param.pure_wrt_drop,
kind,
};
i += 1;
Some(param_def)
})
);
// provide junk type parameter defs - the only place that
@ -1284,44 +1282,111 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
tcx.mk_closure(def_id, substs)
}
Node::AnonConst(_) => match tcx.hir().get_by_hir_id(
tcx.hir().get_parent_node_by_hir_id(hir_id))
{
Node::Ty(&hir::Ty {
node: hir::TyKind::Array(_, ref constant),
..
})
| Node::Ty(&hir::Ty {
node: hir::TyKind::Typeof(ref constant),
..
})
| Node::Expr(&hir::Expr {
node: ExprKind::Repeat(_, ref constant),
..
}) if constant.hir_id == hir_id =>
{
tcx.types.usize
}
Node::AnonConst(_) => {
let parent_node = tcx.hir().get_by_hir_id(tcx.hir().get_parent_node_by_hir_id(hir_id));
match parent_node {
Node::Ty(&hir::Ty {
node: hir::TyKind::Array(_, ref constant),
..
})
| Node::Ty(&hir::Ty {
node: hir::TyKind::Typeof(ref constant),
..
})
| Node::Expr(&hir::Expr {
node: ExprKind::Repeat(_, ref constant),
..
}) if constant.hir_id == hir_id =>
{
tcx.types.usize
}
Node::Variant(&Spanned {
node:
VariantKind {
disr_expr: Some(ref e),
..
},
..
}) if e.hir_id == hir_id =>
{
tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id))
.repr
.discr_type()
.to_ty(tcx)
}
Node::Variant(&Spanned {
node:
VariantKind {
disr_expr: Some(ref e),
..
},
..
}) if e.hir_id == hir_id =>
{
tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id))
.repr
.discr_type()
.to_ty(tcx)
}
x => {
bug!("unexpected const parent in type_of_def_id(): {:?}", x);
Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => {
let path = match parent_node {
Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => {
path
}
Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => {
&*path
}
_ => unreachable!(),
};
match path {
QPath::Resolved(_, ref path) => {
let mut arg_index = 0;
let mut found_const = false;
for seg in &path.segments {
if let Some(generic_args) = &seg.args {
let args = &generic_args.args;
for arg in args {
if let GenericArg::Const(ct) = arg {
if ct.value.hir_id == hir_id {
found_const = true;
break;
}
arg_index += 1;
}
}
}
}
// Sanity check to make sure everything is as expected.
if !found_const {
bug!("no arg matching AnonConst in path")
}
match path.def {
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
Def::Struct(def_id)
| Def::Union(def_id)
| Def::Enum(def_id)
| Def::Fn(def_id) => {
let generics = tcx.generics_of(def_id);
let mut param_index = 0;
for param in &generics.params {
if let ty::GenericParamDefKind::Const = param.kind {
if param_index == arg_index {
return tcx.type_of(param.def_id);
}
param_index += 1;
}
}
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
return tcx.types.err;
}
Def::Err => tcx.types.err,
x => bug!("unexpected const parent path def {:?}", x),
}
}
x => bug!("unexpected const parent path {:?}", x),
}
}
x => {
bug!("unexpected const parent in type_of_def_id(): {:?}", x);
}
}
},
}
Node::GenericParam(param) => match &param.kind {
hir::GenericParamKind::Type { default: Some(ref ty), .. } |

View file

@ -1,6 +1,7 @@
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use rustc::util::nodemap::FxHashSet;
use rustc::mir::interpret::ConstValue;
use syntax::source_map::Span;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -14,6 +15,10 @@ impl From<ty::EarlyBoundRegion> for Parameter {
fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) }
}
impl From<ty::ParamConst> for Parameter {
fn from(param: ty::ParamConst) -> Self { Parameter(param.index) }
}
/// Returns the set of parameters constrained by the impl header.
pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>)
@ -72,6 +77,16 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
}
false
}
fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
if let ty::LazyConst::Evaluated(ty::Const {
val: ConstValue::Param(data),
..
}) = c {
self.parameters.push(Parameter::from(*data));
}
false
}
}
pub fn identify_constrained_type_params<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>,

View file

@ -423,7 +423,7 @@ impl Foo for Bar {
E0049: r##"
This error indicates that an attempted implementation of a trait method
has the wrong number of type parameters.
has the wrong number of type or const parameters.
For example, the trait below has a method `foo` with a type parameter `T`,
but the implementation of `foo` for the type `Bar` is missing this parameter:
@ -1032,6 +1032,7 @@ enum NightsWatch {}
```
"##,
// FIXME(const_generics:docs): example of inferring const parameter.
E0087: r##"
#### Note: this error code is no longer emitted by the compiler.
@ -1152,8 +1153,8 @@ fn main() {
"##,
E0091: r##"
You gave an unnecessary type parameter in a type alias. Erroneous code
example:
You gave an unnecessary type or const parameter in a type alias. Erroneous
code example:
```compile_fail,E0091
type Foo<T> = u32; // error: type parameter `T` is unused
@ -1161,7 +1162,7 @@ type Foo<T> = u32; // error: type parameter `T` is unused
type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
```
Please check you didn't write too many type parameters. Example:
Please check you didn't write too many parameters. Example:
```
type Foo = u32; // ok!

View file

@ -120,7 +120,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
for param in &impl_generics.params {
match param.kind {
// Disallow ANY unconstrained type parameters.
ty::GenericParamDefKind::Type {..} => {
ty::GenericParamDefKind::Type { .. } => {
let param_ty = ty::ParamTy::for_def(param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
report_unused_parameter(tcx,
@ -139,6 +139,15 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&param.name.to_string());
}
}
ty::GenericParamDefKind::Const => {
let param_ct = ty::ParamConst::for_def(param);
if !input_parameters.contains(&ctp::Parameter::from(param_ct)) {
report_unused_parameter(tcx,
tcx.def_span(param.def_id),
"const",
&param_ct.to_string());
}
}
}
}

View file

@ -98,14 +98,22 @@ fn inferred_outlives_crate<'tcx>(
.map(|(&def_id, set)| {
let vec: Vec<ty::Predicate<'tcx>> = set
.iter()
.map(
.filter_map(
|ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind(
ty::OutlivesPredicate(ty1, region2),
)),
UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives(
ty::Binder::bind(ty::OutlivesPredicate(region1, region2)),
),
UnpackedKind::Type(ty1) => {
Some(ty::Predicate::TypeOutlives(ty::Binder::bind(
ty::OutlivesPredicate(ty1, region2)
)))
}
UnpackedKind::Lifetime(region1) => {
Some(ty::Predicate::RegionOutlives(
ty::Binder::bind(ty::OutlivesPredicate(region1, region2))
))
}
UnpackedKind::Const(_) => {
// Generic consts don't impose any constraints.
None
}
},
).collect();
(def_id, Lrc::new(vec))

View file

@ -118,6 +118,10 @@ pub fn insert_outlives_predicate<'tcx>(
}
required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
}
UnpackedKind::Const(_) => {
// Generic consts don't impose any constraints.
}
}
}

View file

@ -4,7 +4,8 @@
//! We walk the set of items and, for each member, generate new constraints.
use hir::def_id::DefId;
use rustc::ty::subst::{UnpackedKind, SubstsRef};
use rustc::mir::interpret::ConstValue;
use rustc::ty::subst::{SubstsRef, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -229,12 +230,19 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// Trait are always invariant so we can take advantage of that.
let variance_i = self.invariant(variance);
for ty in substs.types() {
self.add_constraints_from_ty(current, ty, variance_i);
}
for region in substs.regions() {
self.add_constraints_from_region(current, region, variance_i);
for k in substs {
match k.unpack() {
UnpackedKind::Lifetime(lt) => {
self.add_constraints_from_region(current, lt, variance_i)
}
UnpackedKind::Type(ty) => {
self.add_constraints_from_ty(current, ty, variance_i)
}
UnpackedKind::Const(ct) => {
self.add_constraints_from_const(current, ct, variance_i)
}
}
}
}
@ -267,7 +275,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
}
ty::Array(typ, _) |
ty::Array(typ, len) => {
self.add_constraints_from_ty(current, typ, variance);
self.add_constraints_from_const(current, len, variance);
}
ty::Slice(typ) => {
self.add_constraints_from_ty(current, typ, variance);
}
@ -383,6 +395,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
UnpackedKind::Type(ty) => {
self.add_constraints_from_ty(current, ty, variance_i)
}
UnpackedKind::Const(ct) => {
self.add_constraints_from_const(current, ct, variance_i)
}
}
}
}
@ -434,6 +449,26 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
}
fn add_constraints_from_const(
&mut self,
current: &CurrentItem,
ct: &ty::LazyConst<'tcx>,
variance: VarianceTermPtr<'a>
) {
debug!(
"add_constraints_from_const(ct={:?}, variance={:?})",
ct,
variance
);
if let ty::LazyConst::Evaluated(ct) = ct {
self.add_constraints_from_ty(current, ct.ty, variance);
if let ConstValue::Param(ref data) = ct.val {
self.add_constraint(current, data.index, variance);
}
}
}
/// Adds constraints appropriate for a mutability-type pair
/// appearing in a context with ambient variance `variance`
fn add_constraints_from_mt(&mut self,

View file

@ -1482,6 +1482,9 @@ impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
synthetic: None,
})
}
ty::GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
};
GenericParamDef {
@ -1629,6 +1632,9 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
}
Some(param.clean(cx))
}
ty::GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
}).collect::<Vec<GenericParamDef>>();
let mut where_predicates = preds.predicates.iter()
@ -1678,6 +1684,9 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
.flat_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
ty::GenericParamDefKind::Type { .. } => None,
ty::GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
}).chain(simplify::ty_params(stripped_typarams).into_iter())
.collect(),
where_predicates: simplify::where_clauses(cx, where_predicates),

View file

@ -221,6 +221,9 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
ty::GenericParamDefKind::Type { .. } => {
args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
}
ty::GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
}
}
}

View file

@ -1,23 +1,22 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn u32_identity<const X: u32>() -> u32 {
//~^ ERROR const generics in any position are currently unsupported
fn i32_identity<const X: i32>() -> i32 {
5
}
fn foo_a() {
u32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
i32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
}
fn foo_b() {
u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
}
fn foo_c() {
u32_identity::< -1 >(); // ok
i32_identity::< -1 >(); // ok
}
fn main() {
u32_identity::<5>(); // ok
i32_identity::<5>(); // ok
}

View file

@ -1,13 +1,13 @@
error: expected identifier, found `<-`
--> $DIR/const-expression-parameter.rs:10:19
--> $DIR/const-expression-parameter.rs:9:19
|
LL | u32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
LL | i32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
| ^^ expected identifier
error: expected one of `,` or `>`, found `+`
--> $DIR/const-expression-parameter.rs:14:22
--> $DIR/const-expression-parameter.rs:13:22
|
LL | u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
LL | i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
| ^ expected one of `,` or `>` here
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
@ -16,11 +16,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error: const generics in any position are currently unsupported
--> $DIR/const-expression-parameter.rs:4:23
|
LL | fn u32_identity<const X: u32>() -> u32 {
| ^
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

View file

@ -3,7 +3,6 @@
const fn const_u32_identity<const X: u32>() -> u32 {
//~^ ERROR const parameters are not permitted in `const fn`
//~^^ ERROR const generics in any position are currently unsupported
X
}

View file

@ -9,16 +9,9 @@ error: const parameters are not permitted in `const fn`
|
LL | / const fn const_u32_identity<const X: u32>() -> u32 {
LL | | //~^ ERROR const parameters are not permitted in `const fn`
LL | | //~^^ ERROR const generics in any position are currently unsupported
LL | | X
LL | | }
| |_^
error: const generics in any position are currently unsupported
--> $DIR/const-fn-with-const-param.rs:4:35
|
LL | const fn const_u32_identity<const X: u32>() -> u32 {
| ^
error: aborting due to 2 previous errors
error: aborting due to previous error

View file

@ -1,14 +1,12 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn foo<const X: (), T>(_: T) {
fn foo<const X: (), T>(_: &T) {
//~^ ERROR type parameters must be declared prior to const parameters
//~^^ ERROR const generics in any position are currently unsupported
}
fn bar<const X: (), 'a>(_: &'a ()) {
//~^ ERROR lifetime parameters must be declared prior to const parameters
//~^^ ERROR const generics in any position are currently unsupported
}
fn main() {}

View file

@ -7,26 +7,14 @@ LL | #![feature(const_generics)]
error: type parameters must be declared prior to const parameters
--> $DIR/const-param-before-other-params.rs:4:21
|
LL | fn foo<const X: (), T>(_: T) {
LL | fn foo<const X: (), T>(_: &T) {
| --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
error: lifetime parameters must be declared prior to const parameters
--> $DIR/const-param-before-other-params.rs:9:21
--> $DIR/const-param-before-other-params.rs:8:21
|
LL | fn bar<const X: (), 'a>(_: &'a ()) {
| --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
error: const generics in any position are currently unsupported
--> $DIR/const-param-before-other-params.rs:4:14
|
LL | fn foo<const X: (), T>(_: T) {
| ^
error: const generics in any position are currently unsupported
--> $DIR/const-param-before-other-params.rs:9:14
|
LL | fn bar<const X: (), 'a>(_: &'a ()) {
| ^
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

View file

@ -2,7 +2,6 @@
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn foo<const X: u32>() {
//~^ ERROR const generics in any position are currently unsupported
fn bar() -> u32 {
X //~ ERROR can't use generic parameters from outer function
}

View file

@ -5,22 +5,15 @@ LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0401]: can't use generic parameters from outer function
--> $DIR/const-param-from-outer-fn.rs:7:9
--> $DIR/const-param-from-outer-fn.rs:6:9
|
LL | fn foo<const X: u32>() {
| - const variable from outer function
LL | //~^ ERROR const generics in any position are currently unsupported
LL | fn bar() -> u32 {
| --- try adding a local generic parameter in this method instead
LL | X //~ ERROR can't use generic parameters from outer function
| ^ use of generic parameter from outer function
error: const generics in any position are currently unsupported
--> $DIR/const-param-from-outer-fn.rs:4:14
|
LL | fn foo<const X: u32>() {
| ^
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0401`.

View file

@ -4,5 +4,7 @@
#![deny(non_upper_case_globals)]
fn noop<const x: u32>() {
//~^ ERROR const generics in any position are currently unsupported
//~^ ERROR const parameter `x` should have an upper case name
}
fn main() {}

View file

@ -4,16 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0601]: `main` function not found in crate `const_parameter_uppercase_lint`
|
= note: consider adding a `main` function to `$DIR/const-parameter-uppercase-lint.rs`
error: const generics in any position are currently unsupported
error: const parameter `x` should have an upper case name
--> $DIR/const-parameter-uppercase-lint.rs:6:15
|
LL | fn noop<const x: u32>() {
| ^
| ^ help: convert the identifier to upper case: `X`
|
note: lint level defined here
--> $DIR/const-parameter-uppercase-lint.rs:4:9
|
LL | #![deny(non_upper_case_globals)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0601`.

View file

@ -1,4 +1,4 @@
error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133)
error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133)
--> $DIR/deriving-with-repr-packed.rs:8:16
|
LL | #[derive(Copy, Clone, PartialEq, Eq)]
@ -12,7 +12,7 @@ LL | #![deny(safe_packed_borrows)]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133)
error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133)
--> $DIR/deriving-with-repr-packed.rs:8:23
|
LL | #[derive(Copy, Clone, PartialEq, Eq)]

View file

@ -1,7 +1,5 @@
fn foo<const X: ()>() {} //~ ERROR const generics are unstable
//~^ const generics in any position are currently unsupported
struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
//~^ const generics in any position are currently unsupported
fn main() {}

View file

@ -7,25 +7,13 @@ LL | fn foo<const X: ()>() {} //~ ERROR const generics are unstable
= help: add #![feature(const_generics)] to the crate attributes to enable
error[E0658]: const generics are unstable (see issue #44580)
--> $DIR/feature-gate-const_generics.rs:4:18
--> $DIR/feature-gate-const_generics.rs:3:18
|
LL | struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
| ^
|
= help: add #![feature(const_generics)] to the crate attributes to enable
error: const generics in any position are currently unsupported
--> $DIR/feature-gate-const_generics.rs:1:14
|
LL | fn foo<const X: ()>() {} //~ ERROR const generics are unstable
| ^
error: const generics in any position are currently unsupported
--> $DIR/feature-gate-const_generics.rs:4:18
|
LL | struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
| ^
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.