Skip to content

Commit

Permalink
Auto merge of rust-lang#113522 - fmease:generic-consts, r=cjgillot
Browse files Browse the repository at this point in the history
Implement generic const items

This implements generic parameters and where-clauses on free and associated const items under the experimental feature gate `generic_const_items`. See rust-lang/lang-team#214.

Tracking issue: rust-lang#113521.
Fixes rust-lang#104400.

This PR doesn't include rustfmt support as per [nightly style procedure](https://github.com/rust-lang/style-team/blob/master/nightly-style-procedure.md) and it doesn't add rustdoc JSON support (see [related Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/Rustdoc.20JSON.3A.20Experimental.20rustc.20features)).

CC `@scottmcm` `@compiler-errors` `@WalterSmuts`
r? `@oli-obk`

<details><summary>Resolved Questions</summary>

* Q: Should `const ADD<const N: usize, const M: usize>: usize = N + M; ADD::<0, 1>` trigger the error *generic parameters may not be used in const operations* (which can be unlocked with `#![feature(generic_const_exprs)]`). Currently it doesn't. Or does this fall under [this paragraph](https://github.com/rust-lang/rust/blob/71f71a5397c42fec01f5c1045c638d961fa9f7ca/compiler/rustc_resolve/src/late.rs#L191)?
  * A: No, rust-lang#113522 (comment)
* Q: Should `const UNUSED: () = () where String: Copy;` (with `#![feature(trivial_bounds)]` and with `UNUSED` unused) succeed compilation? Currently it doesn't: *evaluation of constant value failed // entering unreachable code*
  * A: Yes, but postponed until stabilization (latest), rust-lang#113522 (comment)

</details>
  • Loading branch information
bors committed Jul 28, 2023
2 parents b6dd153 + 203d400 commit 04abc37
Show file tree
Hide file tree
Showing 91 changed files with 1,645 additions and 360 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 @@ -2947,6 +2947,7 @@ pub struct StaticItem {
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct ConstItem {
pub defaultness: Defaultness,
pub generics: Generics,
pub ty: P<Ty>,
pub expr: Option<P<Expr>>,
}
Expand Down Expand Up @@ -3058,6 +3059,7 @@ impl ItemKind {
match self {
Self::Fn(box Fn { generics, .. })
| Self::TyAlias(box TyAlias { generics, .. })
| Self::Const(box ConstItem { generics, .. })
| Self::Enum(_, generics)
| Self::Struct(_, generics)
| Self::Union(_, generics)
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 @@ -1149,10 +1149,11 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
}

fn visit_const_item<T: MutVisitor>(
ConstItem { defaultness, ty, expr }: &mut ConstItem,
ConstItem { defaultness, generics, ty, expr }: &mut ConstItem,
visitor: &mut T,
) {
visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
match &item.kind {
ItemKind::ExternCrate(_) => {}
ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
ItemKind::Static(box StaticItem { ty, mutability: _, expr })
| ItemKind::Const(box ConstItem { ty, expr, .. }) => {
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
visitor.visit_generics(generics);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
Expand Down Expand Up @@ -677,7 +681,8 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
visitor.visit_ident(ident);
walk_list!(visitor, visit_attribute, attrs);
match kind {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
visitor.visit_generics(generics);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
Expand Down
55 changes: 39 additions & 16 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Static(ty, *m, body_id)
}
ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
hir::ItemKind::Const(ty, body_id)
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
let (generics, (ty, body_id)) = self.lower_generics(
generics,
Const::No,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_const_item(ty, span, expr.as_deref()),
);
hir::ItemKind::Const(ty, generics, body_id)
}
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
Expand Down Expand Up @@ -715,11 +721,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
let trait_item_def_id = hir_id.expect_owner();

let (generics, kind, has_default) = match &i.kind {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this.lower_ty(
ty,
&ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));

hir::TraitItemKind::Const(ty, body)
},
);
(generics, kind, expr.is_some())
}
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
let asyncness = sig.header.asyncness;
Expand Down Expand Up @@ -817,14 +835,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &i.attrs);

let (generics, kind) = match &i.kind {
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
(
hir::Generics::empty(),
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
)
}
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
&generics,
Const::No,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let body = this.lower_const_body(i.span, expr.as_deref());

hir::ImplItemKind::Const(ty, body)
},
),
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_closures, "const closures are experimental");
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
gate_all!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental");

if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
Expand Down
35 changes: 26 additions & 9 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ impl<'a> State<'a> {
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::ForeignItemKind::Static(ty, mutbl, body) => {
let def = ast::Defaultness::Final;
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
}
ast::ForeignItemKind::Static(ty, mutbl, body) => self.print_item_const(
ident,
Some(*mutbl),
&ast::Generics::default(),
ty,
body.as_deref(),
vis,
ast::Defaultness::Final,
),
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
defaultness,
generics,
Expand Down Expand Up @@ -67,6 +72,7 @@ impl<'a> State<'a> {
&mut self,
ident: Ident,
mutbl: Option<ast::Mutability>,
generics: &ast::Generics,
ty: &ast::Ty,
body: Option<&ast::Expr>,
vis: &ast::Visibility,
Expand All @@ -82,6 +88,7 @@ impl<'a> State<'a> {
};
self.word_space(leading);
self.print_ident(ident);
self.print_generic_params(&generics.params);
self.word_space(":");
self.print_type(ty);
if body.is_some() {
Expand All @@ -92,6 +99,7 @@ impl<'a> State<'a> {
self.word_space("=");
self.print_expr(body);
}
self.print_where_clause(&generics.where_clause);
self.word(";");
self.end(); // end the outer cbox
}
Expand Down Expand Up @@ -158,20 +166,21 @@ impl<'a> State<'a> {
self.word(";");
}
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
let def = ast::Defaultness::Final;
self.print_item_const(
item.ident,
Some(*mutbl),
&ast::Generics::default(),
ty,
body.as_deref(),
&item.vis,
def,
ast::Defaultness::Final,
);
}
ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
self.print_item_const(
item.ident,
None,
generics,
ty,
expr.as_deref(),
&item.vis,
Expand Down Expand Up @@ -515,8 +524,16 @@ impl<'a> State<'a> {
ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness);
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
self.print_item_const(
ident,
None,
generics,
ty,
expr.as_deref(),
vis,
*defaultness,
);
}
ast::AssocItemKind::Type(box ast::TyAlias {
defaultness,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ pub fn expand_test_or_bench(
ast::ItemKind::Const(
ast::ConstItem {
defaultness: ast::Defaultness::Final,
generics: ast::Generics::default(),
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
// test::TestDescAndFn {
expr: Some(
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,16 @@ impl<'a> ExtCtxt<'a> {
span,
name,
AttrVec::new(),
ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()),
ast::ItemKind::Const(
ast::ConstItem {
defaultness,
// FIXME(generic_const_items): Pass the generics as a parameter.
generics: ast::Generics::default(),
ty,
expr: Some(expr),
}
.into(),
),
)
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ declare_features! (
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
/// Allows generic parameters and where-clauses on free & associated const items.
(incomplete, generic_const_items, "CURRENT_RUSTC_VERSION", Some(113521), None),
/// Allows using `..=X` as a patterns in slices.
(active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
/// Allows `if let` guard in match arms.
Expand Down
23 changes: 14 additions & 9 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3130,9 +3130,9 @@ impl<'hir> Item<'hir> {
}
/// Expect an [`ItemKind::Const`] or panic.
#[track_caller]
pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) {
let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
(ty, body)
pub fn expect_const(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId) {
let ItemKind::Const(ty, gen, body) = self.kind else { self.expect_failed("a constant") };
(ty, gen, body)
}
/// Expect an [`ItemKind::Fn`] or panic.
#[track_caller]
Expand Down Expand Up @@ -3319,7 +3319,7 @@ pub enum ItemKind<'hir> {
/// A `static` item.
Static(&'hir Ty<'hir>, Mutability, BodyId),
/// A `const` item.
Const(&'hir Ty<'hir>, BodyId),
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
/// A function declaration.
Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId),
/// A MBE macro definition (`macro_rules!` or `macro`).
Expand Down Expand Up @@ -3372,6 +3372,7 @@ impl ItemKind<'_> {
Some(match *self {
ItemKind::Fn(_, ref generics, _)
| ItemKind::TyAlias(_, ref generics)
| ItemKind::Const(_, ref generics, _)
| ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
Expand Down Expand Up @@ -3567,7 +3568,9 @@ impl<'hir> OwnerNode<'hir> {
match self {
OwnerNode::Item(Item {
kind:
ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
ItemKind::Static(_, _, body)
| ItemKind::Const(_, _, body)
| ItemKind::Fn(_, _, body),
..
})
| OwnerNode::TraitItem(TraitItem {
Expand Down Expand Up @@ -3770,9 +3773,9 @@ impl<'hir> Node<'hir> {
pub fn ty(self) -> Option<&'hir Ty<'hir>> {
match self {
Node::Item(it) => match it.kind {
ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => {
Some(ty)
}
ItemKind::TyAlias(ty, _)
| ItemKind::Static(ty, _, _)
| ItemKind::Const(ty, _, _) => Some(ty),
_ => None,
},
Node::TraitItem(it) => match it.kind {
Expand Down Expand Up @@ -3800,7 +3803,9 @@ impl<'hir> Node<'hir> {
match self {
Node::Item(Item {
kind:
ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
ItemKind::Static(_, _, body)
| ItemKind::Const(_, _, body)
| ItemKind::Fn(_, _, body),
..
})
| Node::TraitItem(TraitItem {
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,17 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
ItemKind::Use(ref path, _) => {
visitor.visit_use(path, item.hir_id());
}
ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => {
ItemKind::Static(ref typ, _, body) => {
visitor.visit_id(item.hir_id());
visitor.visit_ty(typ);
visitor.visit_nested_body(body);
}
ItemKind::Const(ref typ, ref generics, body) => {
visitor.visit_id(item.hir_id());
visitor.visit_ty(typ);
visitor.visit_generics(generics);
visitor.visit_nested_body(body);
}
ItemKind::Fn(ref sig, ref generics, body_id) => {
visitor.visit_id(item.hir_id());
visitor.visit_fn(
Expand Down
Loading

0 comments on commit 04abc37

Please sign in to comment.