first pass at default values for const generics
- Adds optional default values to const generic parameters in the AST and HIR - Parses these optional default values - Adds a `const_generics_defaults` feature gate
This commit is contained in:
parent
f8ab56bf32
commit
61f33bfd29
@ -368,6 +368,8 @@ pub enum GenericParamKind {
|
||||
ty: P<Ty>,
|
||||
/// Span of the `const` keyword.
|
||||
kw_span: Span,
|
||||
/// Optional default value for the const generic param
|
||||
default: Option<AnonConst>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -790,8 +790,9 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
|
||||
GenericParamKind::Type { default } => {
|
||||
visit_opt(default, |default| vis.visit_ty(default));
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _ } => {
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(default, |default| vis.visit_anon_const(default));
|
||||
}
|
||||
}
|
||||
smallvec![param]
|
||||
|
@ -578,7 +578,12 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime => (),
|
||||
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
|
||||
GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
|
||||
GenericParamKind::Const { ref ty, ref default, .. } => {
|
||||
visitor.visit_ty(ty);
|
||||
if let Some(default) = default {
|
||||
visitor.visit_anon_const(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2242,13 +2242,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
(hir::ParamName::Plain(param.ident), kind)
|
||||
}
|
||||
GenericParamKind::Const { ref ty, kw_span: _ } => {
|
||||
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
|
||||
let ty = self
|
||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||
this.lower_ty(&ty, ImplTraitContext::disallowed())
|
||||
});
|
||||
let default = default.as_ref().map(|def| self.lower_anon_const(def));
|
||||
|
||||
(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty })
|
||||
(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty, default })
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -733,7 +733,7 @@ fn validate_generic_param_order(
|
||||
let (ord_kind, ident) = match ¶m.kind {
|
||||
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
|
||||
GenericParamKind::Const { ref ty, kw_span: _ } => {
|
||||
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
|
||||
let ty = pprust::ty_to_string(ty);
|
||||
let unordered = sess.features_untracked().const_generics;
|
||||
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
|
||||
@ -775,7 +775,7 @@ fn validate_generic_param_order(
|
||||
GenericParamKind::Type { default: None } => (),
|
||||
GenericParamKind::Lifetime => (),
|
||||
// FIXME(const_generics:defaults)
|
||||
GenericParamKind::Const { ty: _, kw_span: _ } => (),
|
||||
GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
@ -1166,6 +1166,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if !self.session.features_untracked().const_generics_defaults {
|
||||
if let GenericParamKind::Const { default: Some(ref default), .. } = param.kind {
|
||||
let mut err = self.err_handler().struct_span_err(
|
||||
default.value.span,
|
||||
"default values for const generic parameters are unstable",
|
||||
);
|
||||
err.help(
|
||||
"add `#![feature(const_generics_defaults)]` \
|
||||
to the crate attributes to enable",
|
||||
);
|
||||
err.emit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validate_generic_param_order(
|
||||
|
@ -2668,13 +2668,17 @@ impl<'a> State<'a> {
|
||||
s.print_type(default)
|
||||
}
|
||||
}
|
||||
ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
|
||||
ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
|
||||
s.word_space("const");
|
||||
s.print_ident(param.ident);
|
||||
s.s.space();
|
||||
s.word_space(":");
|
||||
s.print_type(ty);
|
||||
s.print_type_bounds(":", ¶m.bounds)
|
||||
s.print_type_bounds(":", ¶m.bounds);
|
||||
if let Some(ref _default) = default {
|
||||
// FIXME(const_generics_defaults): print the `default` value here
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -145,7 +145,8 @@ fn inject_impl_of_structural_trait(
|
||||
*default = None;
|
||||
ast::GenericArg::Type(cx.ty_ident(span, param.ident))
|
||||
}
|
||||
ast::GenericParamKind::Const { ty: _, kw_span: _ } => {
|
||||
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
|
||||
*default = None;
|
||||
ast::GenericArg::Const(cx.const_ident(span, param.ident))
|
||||
}
|
||||
})
|
||||
|
@ -623,6 +623,9 @@ declare_features! (
|
||||
/// `:pat2018` and `:pat2021` macro matchers.
|
||||
(active, edition_macro_pats, "1.51.0", Some(54883), None),
|
||||
|
||||
/// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
|
||||
(active, const_generics_defaults, "1.51.0", Some(44580), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -418,6 +418,8 @@ pub enum GenericParamKind<'hir> {
|
||||
},
|
||||
Const {
|
||||
ty: &'hir Ty<'hir>,
|
||||
/// Optional default value for the const generic param
|
||||
default: Option<AnonConst>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -877,7 +877,12 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
|
||||
GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
|
||||
GenericParamKind::Const { ref ty, ref default } => {
|
||||
visitor.visit_ty(ty);
|
||||
if let Some(ref default) = default {
|
||||
visitor.visit_anon_const(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
walk_list!(visitor, visit_param_bound, param.bounds);
|
||||
}
|
||||
|
@ -2205,9 +2205,13 @@ impl<'a> State<'a> {
|
||||
self.print_type(&default)
|
||||
}
|
||||
}
|
||||
GenericParamKind::Const { ref ty } => {
|
||||
GenericParamKind::Const { ref ty, ref default } => {
|
||||
self.word_space(":");
|
||||
self.print_type(ty)
|
||||
self.print_type(ty);
|
||||
if let Some(ref _default) = default {
|
||||
// FIXME(const_generics_defaults): print the `default` value here
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,12 +56,15 @@ impl<'a> Parser<'a> {
|
||||
self.expect(&token::Colon)?;
|
||||
let ty = self.parse_ty()?;
|
||||
|
||||
// Parse optional const generics default value.
|
||||
let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
|
||||
|
||||
Ok(GenericParam {
|
||||
ident,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: preceding_attrs.into(),
|
||||
bounds: Vec::new(),
|
||||
kind: GenericParamKind::Const { ty, kw_span: const_span },
|
||||
kind: GenericParamKind::Const { ty, kw_span: const_span, default },
|
||||
is_placeholder: false,
|
||||
})
|
||||
}
|
||||
|
@ -515,6 +515,23 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by
|
||||
/// the caller.
|
||||
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
|
||||
// Parse const argument.
|
||||
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
|
||||
self.parse_block_expr(
|
||||
None,
|
||||
self.token.span,
|
||||
BlockCheckMode::Default,
|
||||
ast::AttrVec::new(),
|
||||
)?
|
||||
} else {
|
||||
self.handle_unambiguous_unbraced_const_arg()?
|
||||
};
|
||||
Ok(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
}
|
||||
|
||||
/// Parse a generic argument in a path segment.
|
||||
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
|
||||
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
|
||||
@ -524,17 +541,7 @@ impl<'a> Parser<'a> {
|
||||
GenericArg::Lifetime(self.expect_lifetime())
|
||||
} else if self.check_const_arg() {
|
||||
// Parse const argument.
|
||||
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
|
||||
self.parse_block_expr(
|
||||
None,
|
||||
self.token.span,
|
||||
BlockCheckMode::Default,
|
||||
ast::AttrVec::new(),
|
||||
)?
|
||||
} else {
|
||||
self.handle_unambiguous_unbraced_const_arg()?
|
||||
};
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
GenericArg::Const(self.parse_const_arg()?)
|
||||
} else if self.check_type() {
|
||||
// Parse type argument.
|
||||
match self.parse_ty() {
|
||||
|
@ -586,7 +586,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
// Allow all following defaults to refer to this type parameter.
|
||||
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
|
||||
}
|
||||
GenericParamKind::Const { ref ty, kw_span: _ } => {
|
||||
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
|
||||
// FIXME(const_generics_defaults): handle `default` value here
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
|
@ -1343,9 +1343,12 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
hir::GenericParamKind::Const { ref ty } => {
|
||||
hir::GenericParamKind::Const { ref ty, ref default } => {
|
||||
self.process_bounds(param.bounds);
|
||||
self.visit_ty(ty);
|
||||
if let Some(default) = default {
|
||||
self.visit_anon_const(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -614,9 +614,13 @@ impl<'hir> Sig for hir::Generics<'hir> {
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + param_text.as_str().len(),
|
||||
});
|
||||
if let hir::GenericParamKind::Const { ref ty } = param.kind {
|
||||
if let hir::GenericParamKind::Const { ref ty, ref default } = param.kind {
|
||||
param_text.push_str(": ");
|
||||
param_text.push_str(&ty_to_string(&ty));
|
||||
if let Some(ref _default) = default {
|
||||
// FIXME(const_generics_defaults): push the `default` value here
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
if !param.bounds.is_empty() {
|
||||
param_text.push_str(": ");
|
||||
|
@ -368,6 +368,7 @@ symbols! {
|
||||
const_fn_transmute,
|
||||
const_fn_union,
|
||||
const_generics,
|
||||
const_generics_defaults,
|
||||
const_if_match,
|
||||
const_impl_trait,
|
||||
const_in_array_repeat_expressions,
|
||||
|
@ -286,9 +286,9 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
||||
// We currently only check wf of const params here.
|
||||
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
|
||||
|
||||
// Const parameters are well formed if their
|
||||
// type is structural match.
|
||||
hir::GenericParamKind::Const { ty: hir_ty } => {
|
||||
// Const parameters are well formed if their type is structural match.
|
||||
// FIXME(const_generics_defaults): we also need to check that the `default` is wf.
|
||||
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
|
||||
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
|
||||
|
||||
let err_ty_str;
|
||||
|
@ -607,11 +607,12 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
|
||||
synthetic,
|
||||
},
|
||||
),
|
||||
hir::GenericParamKind::Const { ref ty } => (
|
||||
hir::GenericParamKind::Const { ref ty, default: _ } => (
|
||||
self.name.ident().name,
|
||||
GenericParamDefKind::Const {
|
||||
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
|
||||
ty: ty.clean(cx),
|
||||
// FIXME(const_generics_defaults): add `default` field here to the docs
|
||||
},
|
||||
),
|
||||
};
|
||||
|
@ -407,6 +407,10 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_anon_const(l: &AnonConst, r: &AnonConst) -> bool {
|
||||
eq_expr(&l.value, &r.value)
|
||||
}
|
||||
|
||||
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
||||
matches!(
|
||||
(l, r),
|
||||
@ -497,7 +501,8 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(Lifetime, Lifetime) => true,
|
||||
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
|
||||
(Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r),
|
||||
(Const { ty: lt, kw_span: _ , default: ld}, Const { ty: rt, kw_span: _, default: rd }) =>
|
||||
eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
|
||||
_ => false,
|
||||
}
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
|
Loading…
x
Reference in New Issue
Block a user