Handle const generics in typeck
Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
This commit is contained in:
parent
8e56729b4d
commit
c236c241e6
10 changed files with 87 additions and 17 deletions
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue