提交 61f33bfd 编写于 作者: J Julian Knodt 提交者: Rémy Rakic

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
上级 f8ab56bf
......@@ -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 @@ fn lower_generic_param(
(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 &param.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 @@ fn visit_generics(&mut self, generics: &'a Generics) {
}
}
}
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 @@ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::Generic
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(":", &param.bounds)
s.print_type_bounds(":", &param.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 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// `: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 @@ pub fn print_generic_param(&mut self, param: &GenericParam<'_>) {
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 @@ fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'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 @@ pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool
}
}
/// 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 @@ fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
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 @@ fn visit_generics(&mut self, generics: &'ast Generics) {
// 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 &param.bounds {
self.visit_param_bound(bound);
}
......
......@@ -1343,9 +1343,12 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'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 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
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 @@
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 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
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))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册