mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #74953 - JulianKnodt:master, r=lcnr
Remove restriction on type parameters preceding consts w/ feature const-generics Removed the restriction on type parameters preceding const parameters when the feature const-generics is enabled. Builds on #74676, which deals with unsorted generic parameters. This just lifts the check in lowering the AST to HIR that permits consts and types to be reordered with respect to each other. Lifetimes still must precede both This change is not intended for min-const-generics, and is gated behind the `#![feature(const_generics)]`. One thing is that it also permits type parameters without a default to come after consts, which I expected to not work, and was hoping to get more guidance on whether that should be permitted or how to prevent it otherwise. I did not go through the RFC process for this pull request because there was prior work to get this feature added. In the previous PR that was cited, work was done to enable this change. r? @lcnr
This commit is contained in:
commit
08324fe6f7
@ -35,6 +35,7 @@ use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
@ -309,19 +310,49 @@ pub type GenericBounds = Vec<GenericBound>;
|
||||
/// Specifies the enforced ordering for generic parameters. In the future,
|
||||
/// if we wanted to relax this order, we could override `PartialEq` and
|
||||
/// `PartialOrd`, to allow the kinds to be unordered.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
#[derive(Hash, Clone, Copy)]
|
||||
pub enum ParamKindOrd {
|
||||
Lifetime,
|
||||
Type,
|
||||
Const,
|
||||
// `unordered` is only `true` if `sess.has_features().const_generics`
|
||||
// is active. Specifically, if it's only `min_const_generics`, it will still require
|
||||
// ordering consts after types.
|
||||
Const { unordered: bool },
|
||||
}
|
||||
|
||||
impl Ord for ParamKindOrd {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
use ParamKindOrd::*;
|
||||
let to_int = |v| match v {
|
||||
Lifetime => 0,
|
||||
Type | Const { unordered: true } => 1,
|
||||
// technically both consts should be ordered equally,
|
||||
// but only one is ever encountered at a time, so this is
|
||||
// fine.
|
||||
Const { unordered: false } => 2,
|
||||
};
|
||||
|
||||
to_int(*self).cmp(&to_int(*other))
|
||||
}
|
||||
}
|
||||
impl PartialOrd for ParamKindOrd {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl PartialEq for ParamKindOrd {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
impl Eq for ParamKindOrd {}
|
||||
|
||||
impl fmt::Display for ParamKindOrd {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ParamKindOrd::Lifetime => "lifetime".fmt(f),
|
||||
ParamKindOrd::Type => "type".fmt(f),
|
||||
ParamKindOrd::Const => "const".fmt(f),
|
||||
ParamKindOrd::Const { .. } => "const".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -773,13 +773,13 @@ fn validate_generic_param_order<'a>(
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"reorder the parameters: lifetimes, then types{}",
|
||||
if sess.features_untracked().const_generics
|
||||
|| sess.features_untracked().min_const_generics
|
||||
{
|
||||
", then consts"
|
||||
"reorder the parameters: lifetimes{}",
|
||||
if sess.features_untracked().const_generics {
|
||||
", then consts and types"
|
||||
} else if sess.features_untracked().min_const_generics {
|
||||
", then consts, then types"
|
||||
} else {
|
||||
""
|
||||
", then types"
|
||||
},
|
||||
),
|
||||
ordered_params.clone(),
|
||||
@ -1156,7 +1156,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
|
||||
GenericParamKind::Const { ref ty, kw_span: _ } => {
|
||||
let ty = pprust::ty_to_string(ty);
|
||||
(ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
|
||||
let unordered = self.session.features_untracked().const_generics;
|
||||
(
|
||||
ParamKindOrd::Const { unordered },
|
||||
Some(format!("const {}: {}", param.ident, ty)),
|
||||
)
|
||||
}
|
||||
};
|
||||
(kind, Some(&*param.bounds), param.ident.span, ident)
|
||||
|
@ -489,10 +489,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
kind,
|
||||
);
|
||||
|
||||
let unordered = sess.features_untracked().const_generics;
|
||||
let kind_ord = match kind {
|
||||
"lifetime" => ParamKindOrd::Lifetime,
|
||||
"type" => ParamKindOrd::Type,
|
||||
"constant" => ParamKindOrd::Const,
|
||||
"constant" => ParamKindOrd::Const { unordered },
|
||||
// It's more concise to match on the string representation, though it means
|
||||
// the match is non-exhaustive.
|
||||
_ => bug!("invalid generic parameter kind {}", kind),
|
||||
@ -500,17 +501,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let arg_ord = match arg {
|
||||
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
|
||||
GenericArg::Type(_) => ParamKindOrd::Type,
|
||||
GenericArg::Const(_) => ParamKindOrd::Const,
|
||||
GenericArg::Const(_) => ParamKindOrd::Const { unordered },
|
||||
};
|
||||
|
||||
// This note will be true as long as generic parameters are strictly ordered by their kind.
|
||||
let (first, last) =
|
||||
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
|
||||
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
|
||||
|
||||
if let Some(help) = help {
|
||||
err.help(help);
|
||||
// This note is only true when generic parameters are strictly ordered by their kind.
|
||||
if kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
|
||||
let (first, last) =
|
||||
if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
|
||||
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
|
||||
if let Some(help) = help {
|
||||
err.help(help);
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
@ -672,7 +675,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
ParamKindOrd::Type
|
||||
}
|
||||
GenericParamDefKind::Const => {
|
||||
ParamKindOrd::Const
|
||||
ParamKindOrd::Const {
|
||||
unordered: tcx
|
||||
.sess
|
||||
.features_untracked()
|
||||
.const_generics,
|
||||
}
|
||||
}
|
||||
},
|
||||
param,
|
||||
|
@ -1,14 +1,13 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Bad<const N: usize, T> { //~ ERROR type parameters must be declared prior
|
||||
struct Bad<const N: usize, T> {
|
||||
arr: [u8; { N }],
|
||||
another: T,
|
||||
}
|
||||
|
||||
struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
|
||||
//~^ ERROR type parameters must be declared prior
|
||||
//~| ERROR lifetime parameters must be declared prior
|
||||
//~^ ERROR lifetime parameters must be declared prior
|
||||
a: &'a T,
|
||||
b: &'b U,
|
||||
}
|
||||
|
@ -1,39 +1,18 @@
|
||||
error: type parameters must be declared prior to const parameters
|
||||
--> $DIR/argument_order.rs:4:28
|
||||
|
|
||||
LL | struct Bad<const N: usize, T> {
|
||||
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
|
||||
|
||||
error: lifetime parameters must be declared prior to const parameters
|
||||
--> $DIR/argument_order.rs:9:32
|
||||
|
|
||||
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
|
||||
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
|
||||
|
||||
error: type parameters must be declared prior to const parameters
|
||||
--> $DIR/argument_order.rs:9:36
|
||||
|
|
||||
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
|
||||
| ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/argument_order.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
|
||||
|
||||
error[E0747]: lifetime provided when a type was expected
|
||||
--> $DIR/argument_order.rs:17:23
|
||||
--> $DIR/argument_order.rs:16:23
|
||||
|
|
||||
LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: lifetime arguments must be provided before type arguments
|
||||
= help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
|
||||
= help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>`
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0747`.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
type Array<T, const N: usize> = [T; N];
|
||||
|
||||
|
@ -1,21 +1,9 @@
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/const-arg-type-arg-misordered.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
error[E0747]: constant provided when a type was expected
|
||||
--> $DIR/const-arg-type-arg-misordered.rs:6:35
|
||||
|
|
||||
LL | fn foo<const N: usize>() -> Array<N, ()> {
|
||||
| ^
|
||||
|
|
||||
= note: type arguments must be provided before constant arguments
|
||||
= help: reorder the arguments: types, then consts: `<T, N>`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0747`.
|
||||
|
@ -5,8 +5,6 @@ fn bar<const X: (), 'a>(_: &'a ()) {
|
||||
//~^ ERROR lifetime parameters must be declared prior to const parameters
|
||||
}
|
||||
|
||||
fn foo<const X: (), T>(_: &T) {
|
||||
//~^ ERROR type parameters must be declared prior to const parameters
|
||||
}
|
||||
fn foo<const X: (), T>(_: &T) {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -2,13 +2,7 @@ error: lifetime parameters must be declared prior to const parameters
|
||||
--> $DIR/const-param-before-other-params.rs:4:21
|
||||
|
|
||||
LL | fn bar<const X: (), 'a>(_: &'a ()) {
|
||||
| --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
|
||||
| --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>`
|
||||
|
||||
error: type parameters must be declared prior to const parameters
|
||||
--> $DIR/const-param-before-other-params.rs:8:21
|
||||
|
|
||||
LL | fn foo<const X: (), T>(_: &T) {
|
||||
| --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
|
20
src/test/ui/const-generics/defaults/complex-unord-param.rs
Normal file
20
src/test/ui/const-generics/defaults/complex-unord-param.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// run-pass
|
||||
// Checks a complicated usage of unordered params
|
||||
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
|
||||
args: &'a [&'a [T; M]; N],
|
||||
specifier: A,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let array = [1, 2, 3];
|
||||
let nest = [&array];
|
||||
let _ = NestedArrays {
|
||||
args: &nest,
|
||||
specifier: true,
|
||||
};
|
||||
}
|
12
src/test/ui/const-generics/defaults/intermixed-lifetime.rs
Normal file
12
src/test/ui/const-generics/defaults/intermixed-lifetime.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// Checks that lifetimes cannot be interspersed between consts and types.
|
||||
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
|
||||
//~^ Error lifetime parameters must be declared prior to const parameters
|
||||
|
||||
struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
|
||||
//~^ Error lifetime parameters must be declared prior to type parameters
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error: lifetime parameters must be declared prior to const parameters
|
||||
--> $DIR/intermixed-lifetime.rs:6:28
|
||||
|
|
||||
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
|
||||
| -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
|
||||
|
||||
error: lifetime parameters must be declared prior to type parameters
|
||||
--> $DIR/intermixed-lifetime.rs:9:37
|
||||
|
|
||||
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
|
||||
| --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -0,0 +1,8 @@
|
||||
error: type parameters must be declared prior to const parameters
|
||||
--> $DIR/needs-feature.rs:10:26
|
||||
|
|
||||
LL | struct A<const N: usize, T=u32>(T);
|
||||
| -----------------^----- help: reorder the parameters: lifetimes, then consts, then types: `<T, const N: usize>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,18 @@
|
||||
error: type parameters must be declared prior to const parameters
|
||||
--> $DIR/needs-feature.rs:10:26
|
||||
|
|
||||
LL | struct A<const N: usize, T=u32>(T);
|
||||
| -----------------^----- help: reorder the parameters: lifetimes, then types: `<T, const N: usize>`
|
||||
|
||||
error[E0658]: const generics are unstable
|
||||
--> $DIR/needs-feature.rs:10:16
|
||||
|
|
||||
LL | struct A<const N: usize, T=u32>(T);
|
||||
| ^
|
||||
|
|
||||
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
|
||||
= help: add `#![feature(min_const_generics)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
17
src/test/ui/const-generics/defaults/needs-feature.rs
Normal file
17
src/test/ui/const-generics/defaults/needs-feature.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//[full] run-pass
|
||||
// Verifies that having generic parameters after constants is not permitted without the
|
||||
// `const_generics` feature.
|
||||
// revisions: none min full
|
||||
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![cfg_attr(full, allow(incomplete_features))]
|
||||
#![cfg_attr(min, feature(min_const_generics))]
|
||||
|
||||
struct A<const N: usize, T=u32>(T);
|
||||
//[none]~^ ERROR type parameters must be declared prior
|
||||
//[none]~| ERROR const generics are unstable
|
||||
//[min]~^^^ ERROR type parameters must be declared prior
|
||||
|
||||
fn main() {
|
||||
let _: A<3> = A(0);
|
||||
}
|
15
src/test/ui/const-generics/defaults/simple-defaults.rs
Normal file
15
src/test/ui/const-generics/defaults/simple-defaults.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// run-pass
|
||||
// Checks some basic test cases for defaults.
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct FixedOutput<'a, const N: usize, T=u32> {
|
||||
out: &'a [T; N],
|
||||
}
|
||||
|
||||
trait FixedOutputter {
|
||||
fn out(&self) -> FixedOutput<'_, 10>;
|
||||
}
|
||||
|
||||
fn main() {}
|
10
src/test/ui/const-generics/type-after-const-ok.rs
Normal file
10
src/test/ui/const-generics/type-after-const-ok.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// run-pass
|
||||
// Verifies that having generic parameters after constants is permitted
|
||||
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct A<const N: usize, T>(T);
|
||||
|
||||
fn main() {}
|
@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
|
||||
--> $DIR/issue-59508-1.rs:12:25
|
||||
|
|
||||
LL | pub fn do_things<T, 'a, 'b: 'a>() {
|
||||
| ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
|
||||
| ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-59508-1.rs:2:12
|
||||
|
Loading…
Reference in New Issue
Block a user