Skip to content

Commit

Permalink
Auto merge of #80547 - lqd:const_generics_defaults, r=varkor
Browse files Browse the repository at this point in the history
In which we start to parse const generics defaults

As discussed in this [zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/const.20generic.20defaults), this PR extracts the parsing parts from `@JulianKnodt's` PR #75384 for a better user-experience using the newly stabilized `min_const_generics` (albeit temporary) as shown in #80507: trying to use default values on const generics currently results in parse errors, as if the user didn't use the correct syntax (which is somewhat true but also misleading).

This PR extracts (and slightly modifies in a couple places) `@JulianKnodt's` parsing code (with attribution if I've done everything correctly), AST and HIR changes, and feature gate setup.

This feature is now marked as "incomplete" and thus will also print out the expected "const generics default values are unstable" error instead of a syntax error. Note that, as I've only extracted the parsing part, the actual feature will not work at all if enabled. There will be ICEs, and inference errors on the const generics default values themselves.

Fixes #80507.

Once this merges, I'll:
- modify the const generics tracking issue to refer to the `const_generics_defaults` gate rather than the older temporary name it uses there.
- create the GH `F-const_generics_defaults` label

r? `@varkor`
  • Loading branch information
bors committed Jan 1, 2021
2 parents 18d27b2 + 942b7ce commit a609fb4
Show file tree
Hide file tree
Showing 37 changed files with 160 additions and 53 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
},
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
}
};

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down Expand Up @@ -774,8 +774,8 @@ fn validate_generic_param_order(
}
GenericParamKind::Type { default: None } => (),
GenericParamKind::Lifetime => (),
// FIXME(const_generics:defaults)
GenericParamKind::Const { ty: _, kw_span: _ } => (),
// FIXME(const_generics_defaults)
GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
}
first = false;
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
extended_key_value_attributes,
"arbitrary expressions in key-value attributes are unstable"
);
gate_all!(
const_generics_defaults,
"default values for const generic parameters are experimental"
);
if sess.parse_sess.span_diagnostic.err_count() == 0 {
// Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
// involved, so we only emit errors where there are no other parsing errors.
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(":", &param.bounds)
s.print_type_bounds(":", &param.bounds);
if let Some(ref _default) = default {
// FIXME(const_generics_defaults): print the `default` value here
todo!();
}
}
}
});
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_builtin_macros/src/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
})
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ declare_features! (
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),

/// Allows non-trivial generic constants which have to be manually propageted upwards.
/// Allows non-trivial generic constants which have to be manually propagated upwards.
(active, const_evaluatable_checked, "1.48.0", Some(76560), None),

/// Allows basic arithmetic on floating point types in a `const fn`.
Expand Down Expand Up @@ -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
// -------------------------------------------------------------------------
Expand All @@ -647,6 +650,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::repr128,
sym::unsized_locals,
sym::capture_disjoint_fields,
sym::const_generics_defaults,
];

/// Some features are not allowed to be used together at the same time, if
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ pub enum GenericParamKind<'hir> {
},
Const {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<AnonConst>,
},
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!();
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty::GenericParamDefKind::Type { has_default, .. } => {
Some((param.def_id, has_default))
}
ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
ty::GenericParamDefKind::Const => None, // FIXME(const_generics_defaults)
})
.peekable();
let has_default = {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1834,7 +1834,7 @@ impl EncodeContext<'a, 'tcx> {
EntryKind::ConstParam,
true,
);
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ pub trait Printer<'tcx>: Sized {
self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
)
}
ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
ty::GenericParamDefKind::Const => false, // FIXME(const_generics_defaults)
}
})
.count();
Expand Down
18 changes: 16 additions & 2 deletions compiler/rustc_parse/src/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_ast::{
self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
};
use rustc_errors::PResult;
use rustc_span::symbol::kw;
use rustc_span::symbol::{kw, sym};

impl<'a> Parser<'a> {
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
Expand Down Expand Up @@ -56,12 +56,26 @@ impl<'a> Parser<'a> {
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;

// Parse optional const generics default value, taking care of feature gating the spans
// with the unstable syntax mechanism.
let default = if self.eat(&token::Eq) {
// The gated span goes from the `=` to the end of the const argument that follows (and
// which could be a block expression).
let start = self.prev_token.span;
let const_arg = self.parse_const_arg()?;
let span = start.to(const_arg.value.span);
self.sess.gated_spans.gate(sym::const_generics_defaults, span);
Some(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,
})
}
Expand Down
29 changes: 18 additions & 11 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>> {
Expand All @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {

fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
let kind = match &p.kind {
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
hir::GenericParamKind::Type { default, .. } if default.is_some() => {
AnnotationKind::Container
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 &param.bounds {
self.visit_param_bound(bound);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ enum ResolutionError<'a> {
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_save_analysis/src/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_save_analysis/src/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(": ");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
defaults.types += has_default as usize
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
GenericParamDefKind::Const => {
let ty = tcx.at(self.span).type_of(param.def_id);
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
if infer_args {
// No const parameters were provided, we can infer all.
self.astconv.ct_infer(ty, Some(param), self.span).into()
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
// No const parameters were provided, we have to infer them.
self.fcx.var_for_def(self.span, param)
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_typeck/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -785,7 +785,7 @@ fn check_where_clauses<'tcx, 'fcx>(
}

GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
// FIXME(const_generics_defaults)
fcx.tcx.mk_param_from_def(param)
}
}
Expand Down
Loading

0 comments on commit a609fb4

Please sign in to comment.