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:
commit
88f755f8a8
74 changed files with 1201 additions and 412 deletions
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2533,7 +2533,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
),
|
||||
))
|
||||
}
|
||||
UnpackedKind::Type(_) => None,
|
||||
UnpackedKind::Type(_) | UnpackedKind::Const(_) => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::monomorphize::Instance;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::mir::interpret::ConstValue;
|
||||
use rustc::session::config::OptLevel;
|
||||
use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts};
|
||||
use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts, LazyConst, ParamConst};
|
||||
use rustc::ty::subst::{SubstsRef, InternalSubsts};
|
||||
use syntax::ast;
|
||||
use syntax::attr::InlineAttr;
|
||||
|
@ -44,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
|
|||
fn is_generic_fn(&self) -> bool {
|
||||
match *self.as_mono_item() {
|
||||
MonoItem::Fn(ref instance) => {
|
||||
instance.substs.types().next().is_some()
|
||||
instance.substs.non_erasable_generics().next().is_some()
|
||||
}
|
||||
MonoItem::Static(..) |
|
||||
MonoItem::GlobalAsm(..) => false,
|
||||
|
@ -267,7 +268,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
|
||||
ty::Adt(adt_def, substs) => {
|
||||
self.push_def_path(adt_def.did, output);
|
||||
self.push_type_params(substs, iter::empty(), output, debug);
|
||||
self.push_generic_params(substs, iter::empty(), output, debug);
|
||||
},
|
||||
ty::Tuple(component_types) => {
|
||||
output.push('(');
|
||||
|
@ -312,7 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
ty::Dynamic(ref trait_data, ..) => {
|
||||
if let Some(principal) = trait_data.principal() {
|
||||
self.push_def_path(principal.def_id(), output);
|
||||
self.push_type_params(
|
||||
self.push_generic_params(
|
||||
principal.skip_binder().substs,
|
||||
trait_data.projection_bounds(),
|
||||
output,
|
||||
|
@ -373,7 +374,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
self.push_def_path(def_id, output);
|
||||
let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
|
||||
let substs = substs.truncate_to(self.tcx, generics);
|
||||
self.push_type_params(substs, iter::empty(), output, debug);
|
||||
self.push_generic_params(substs, iter::empty(), output, debug);
|
||||
}
|
||||
ty::Error |
|
||||
ty::Bound(..) |
|
||||
|
@ -394,6 +395,24 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(const_generics): handle debug printing.
|
||||
pub fn push_const_name(&self, c: &LazyConst<'tcx>, output: &mut String, debug: bool) {
|
||||
match c {
|
||||
LazyConst::Unevaluated(..) => output.push_str("_: _"),
|
||||
LazyConst::Evaluated(Const { ty, val }) => {
|
||||
match val {
|
||||
ConstValue::Infer(..) => output.push_str("_"),
|
||||
ConstValue::Param(ParamConst { name, .. }) => {
|
||||
write!(output, "{}", name).unwrap();
|
||||
}
|
||||
_ => write!(output, "{:?}", c).unwrap(),
|
||||
}
|
||||
output.push_str(": ");
|
||||
self.push_type_name(ty, output, debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_def_path(&self,
|
||||
def_id: DefId,
|
||||
output: &mut String) {
|
||||
|
@ -421,15 +440,15 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
output.pop();
|
||||
}
|
||||
|
||||
fn push_type_params<I>(&self,
|
||||
substs: SubstsRef<'tcx>,
|
||||
projections: I,
|
||||
output: &mut String,
|
||||
debug: bool)
|
||||
where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
|
||||
{
|
||||
fn push_generic_params<I>(
|
||||
&self,
|
||||
substs: SubstsRef<'tcx>,
|
||||
projections: I,
|
||||
output: &mut String,
|
||||
debug: bool,
|
||||
) where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>> {
|
||||
let mut projections = projections.peekable();
|
||||
if substs.types().next().is_none() && projections.peek().is_none() {
|
||||
if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -449,6 +468,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
output.push_str(", ");
|
||||
}
|
||||
|
||||
for const_parameter in substs.consts() {
|
||||
self.push_const_name(const_parameter, output, debug);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
||||
output.pop();
|
||||
output.pop();
|
||||
|
||||
|
@ -460,6 +484,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
|||
output: &mut String,
|
||||
debug: bool) {
|
||||
self.push_def_path(instance.def_id(), output);
|
||||
self.push_type_params(instance.substs, iter::empty(), output, debug);
|
||||
self.push_generic_params(instance.substs, iter::empty(), output, debug);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -448,7 +448,7 @@ fn mono_item_visibility(
|
|||
return Visibility::Hidden
|
||||
}
|
||||
|
||||
let is_generic = instance.substs.types().next().is_some();
|
||||
let is_generic = instance.substs.non_erasable_generics().next().is_some();
|
||||
|
||||
// Upstream `DefId` instances get different handling than local ones
|
||||
if !def_id.is_local() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶m)) => {
|
||||
match (arg, ¶m.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,
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(¶m) {
|
||||
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 {
|
||||
|
|
|
@ -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 ¶m.kind {
|
||||
hir::GenericParamKind::Type { default: Some(ref ty), .. } |
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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>,
|
|||
¶m.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",
|
||||
¶m_ct.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue