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>,
|
ty: P<Ty>,
|
||||||
/// Span of the `const` keyword.
|
/// Span of the `const` keyword.
|
||||||
kw_span: Span,
|
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 } => {
|
GenericParamKind::Type { default } => {
|
||||||
visit_opt(default, |default| vis.visit_ty(default));
|
visit_opt(default, |default| vis.visit_ty(default));
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { ty, kw_span: _ } => {
|
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||||
vis.visit_ty(ty);
|
vis.visit_ty(ty);
|
||||||
|
visit_opt(default, |default| vis.visit_anon_const(default));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
smallvec![param]
|
smallvec![param]
|
||||||
|
@ -578,7 +578,12 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
|
|||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime => (),
|
GenericParamKind::Lifetime => (),
|
||||||
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
|
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)
|
(hir::ParamName::Plain(param.ident), kind)
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { ref ty, kw_span: _ } => {
|
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
|
||||||
let ty = self
|
let ty = self
|
||||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||||
this.lower_ty(&ty, ImplTraitContext::disallowed())
|
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 {
|
let (ord_kind, ident) = match ¶m.kind {
|
||||||
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
|
GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
|
||||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, 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 ty = pprust::ty_to_string(ty);
|
||||||
let unordered = sess.features_untracked().const_generics;
|
let unordered = sess.features_untracked().const_generics;
|
||||||
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
|
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
|
||||||
@ -775,7 +775,7 @@ fn validate_generic_param_order(
|
|||||||
GenericParamKind::Type { default: None } => (),
|
GenericParamKind::Type { default: None } => (),
|
||||||
GenericParamKind::Lifetime => (),
|
GenericParamKind::Lifetime => (),
|
||||||
// FIXME(const_generics:defaults)
|
// FIXME(const_generics:defaults)
|
||||||
GenericParamKind::Const { ty: _, kw_span: _ } => (),
|
GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
|
||||||
}
|
}
|
||||||
first = false;
|
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(
|
validate_generic_param_order(
|
||||||
|
@ -2668,13 +2668,17 @@ impl<'a> State<'a> {
|
|||||||
s.print_type(default)
|
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.word_space("const");
|
||||||
s.print_ident(param.ident);
|
s.print_ident(param.ident);
|
||||||
s.s.space();
|
s.s.space();
|
||||||
s.word_space(":");
|
s.word_space(":");
|
||||||
s.print_type(ty);
|
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;
|
*default = None;
|
||||||
ast::GenericArg::Type(cx.ty_ident(span, param.ident))
|
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))
|
ast::GenericArg::Const(cx.const_ident(span, param.ident))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -623,6 +623,9 @@ declare_features! (
|
|||||||
/// `:pat2018` and `:pat2021` macro matchers.
|
/// `:pat2018` and `:pat2021` macro matchers.
|
||||||
(active, edition_macro_pats, "1.51.0", Some(54883), None),
|
(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
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -418,6 +418,8 @@ pub enum GenericParamKind<'hir> {
|
|||||||
},
|
},
|
||||||
Const {
|
Const {
|
||||||
ty: &'hir Ty<'hir>,
|
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 {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {}
|
GenericParamKind::Lifetime { .. } => {}
|
||||||
GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
|
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);
|
walk_list!(visitor, visit_param_bound, param.bounds);
|
||||||
}
|
}
|
||||||
|
@ -2205,9 +2205,13 @@ impl<'a> State<'a> {
|
|||||||
self.print_type(&default)
|
self.print_type(&default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { ref ty } => {
|
GenericParamKind::Const { ref ty, ref default } => {
|
||||||
self.word_space(":");
|
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)?;
|
self.expect(&token::Colon)?;
|
||||||
let ty = self.parse_ty()?;
|
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 {
|
Ok(GenericParam {
|
||||||
ident,
|
ident,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
attrs: preceding_attrs.into(),
|
attrs: preceding_attrs.into(),
|
||||||
bounds: Vec::new(),
|
bounds: Vec::new(),
|
||||||
kind: GenericParamKind::Const { ty, kw_span: const_span },
|
kind: GenericParamKind::Const { ty, kw_span: const_span, default },
|
||||||
is_placeholder: false,
|
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.
|
/// Parse a generic argument in a path segment.
|
||||||
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
|
/// 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>> {
|
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
|
||||||
@ -524,17 +541,7 @@ impl<'a> Parser<'a> {
|
|||||||
GenericArg::Lifetime(self.expect_lifetime())
|
GenericArg::Lifetime(self.expect_lifetime())
|
||||||
} else if self.check_const_arg() {
|
} else if self.check_const_arg() {
|
||||||
// Parse const argument.
|
// Parse const argument.
|
||||||
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
|
GenericArg::Const(self.parse_const_arg()?)
|
||||||
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 })
|
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// Parse type argument.
|
||||||
match self.parse_ty() {
|
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.
|
// Allow all following defaults to refer to this type parameter.
|
||||||
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
|
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 {
|
for bound in ¶m.bounds {
|
||||||
self.visit_param_bound(bound);
|
self.visit_param_bound(bound);
|
||||||
}
|
}
|
||||||
|
@ -1343,9 +1343,12 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
|||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::GenericParamKind::Const { ref ty } => {
|
hir::GenericParamKind::Const { ref ty, ref default } => {
|
||||||
self.process_bounds(param.bounds);
|
self.process_bounds(param.bounds);
|
||||||
self.visit_ty(ty);
|
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(),
|
start: offset + text.len(),
|
||||||
end: offset + text.len() + param_text.as_str().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(": ");
|
||||||
param_text.push_str(&ty_to_string(&ty));
|
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() {
|
if !param.bounds.is_empty() {
|
||||||
param_text.push_str(": ");
|
param_text.push_str(": ");
|
||||||
|
@ -368,6 +368,7 @@ symbols! {
|
|||||||
const_fn_transmute,
|
const_fn_transmute,
|
||||||
const_fn_union,
|
const_fn_union,
|
||||||
const_generics,
|
const_generics,
|
||||||
|
const_generics_defaults,
|
||||||
const_if_match,
|
const_if_match,
|
||||||
const_impl_trait,
|
const_impl_trait,
|
||||||
const_in_array_repeat_expressions,
|
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.
|
// We currently only check wf of const params here.
|
||||||
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
|
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
|
||||||
|
|
||||||
// Const parameters are well formed if their
|
// Const parameters are well formed if their type is structural match.
|
||||||
// type is structural match.
|
// FIXME(const_generics_defaults): we also need to check that the `default` is wf.
|
||||||
hir::GenericParamKind::Const { ty: hir_ty } => {
|
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
|
||||||
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
|
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
|
||||||
|
|
||||||
let err_ty_str;
|
let err_ty_str;
|
||||||
|
@ -607,11 +607,12 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
|
|||||||
synthetic,
|
synthetic,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
hir::GenericParamKind::Const { ref ty } => (
|
hir::GenericParamKind::Const { ref ty, default: _ } => (
|
||||||
self.name.ident().name,
|
self.name.ident().name,
|
||||||
GenericParamDefKind::Const {
|
GenericParamDefKind::Const {
|
||||||
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
|
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
|
||||||
ty: ty.clean(cx),
|
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 {
|
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
(l, r),
|
(l, r),
|
||||||
@ -497,7 +501,8 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||||||
&& match (&l.kind, &r.kind) {
|
&& match (&l.kind, &r.kind) {
|
||||||
(Lifetime, Lifetime) => true,
|
(Lifetime, Lifetime) => true,
|
||||||
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
|
(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,
|
_ => false,
|
||||||
}
|
}
|
||||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user