Handle const generics in typeck

Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
This commit is contained in:
varkor 2019-02-20 01:19:42 +00:00
parent 8e56729b4d
commit c236c241e6
10 changed files with 87 additions and 17 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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