diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3111546c6e198..cc7e081f2cce3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1431,10 +1431,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // We cannot just match on `TyKind::Infer` as `(_)` is represented as // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer` if ty.is_maybe_parenthesised_infer() { - return GenericArg::Infer(hir::InferArg { + return GenericArg::Infer(self.arena.alloc(hir::InferArg { hir_id: self.lower_node_id(ty.id), span: self.lower_span(ty.span), - }); + kind: hir::InferArgKind::TypeOrConst, + })); } match &ty.kind { @@ -1471,14 +1472,13 @@ impl<'hir> LoweringContext<'_, 'hir> { Err(e) => e.emit(self), }; let ct = self.arena.alloc(ct); - // note: this allows direct_const_arg!(_) to be inferred to a type. a little - // wonky. return match ct.try_as_ambig_ct() { Some(ct) => GenericArg::Const(ct), - None => GenericArg::Infer(hir::InferArg { + None => GenericArg::Infer(self.arena.alloc(hir::InferArg { hir_id: ct.hir_id, span: ct.span, - }), + kind: hir::InferArgKind::Const, + })), }; } _ => {} @@ -1489,7 +1489,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let ct = self.lower_anon_const_to_const_arg_and_alloc(ct); match ct.try_as_ambig_ct() { Some(ct) => GenericArg::Const(ct), - None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }), + None => GenericArg::Infer(self.arena.alloc(hir::InferArg { + hir_id: ct.hir_id, + span: ct.span, + kind: hir::InferArgKind::Const, + })), } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e4d6f052c2246..252296fcae90f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -547,11 +547,23 @@ pub struct ConstArgArrayExpr<'hir> { pub elems: &'hir [&'hir ConstArg<'hir>], } +/// Tracks what a [GenericArg::Infer] can be inferred to based on its syntax. +#[derive(Clone, Copy, Debug, PartialEq, Eq, StableHash)] +pub enum InferArgKind { + /// A bare _, e.g. S<_>. Whether it is a type or const argument is + /// determined during HIR ty lowering. + TypeOrConst, + /// An infer argument with unambiguous const syntax, e.g. S<{ _ }> or + /// S. It can only be inferred to a const. + Const, +} + #[derive(Clone, Copy, Debug, StableHash)] pub struct InferArg { #[stable_hash(ignore)] pub hir_id: HirId, pub span: Span, + pub kind: InferArgKind, } impl InferArg { @@ -574,7 +586,7 @@ pub enum GenericArg<'hir> { /// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In /// such cases they *are* represented by the `Infer` variants on [`TyKind`] and /// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const. - Infer(InferArg), + Infer(&'hir InferArg), } impl GenericArg<'_> { @@ -601,7 +613,8 @@ impl GenericArg<'_> { GenericArg::Lifetime(_) => "lifetime", GenericArg::Type(_) => "type", GenericArg::Const(_) => "constant", - GenericArg::Infer(_) => "placeholder", + GenericArg::Infer(InferArg { kind: InferArgKind::TypeOrConst, .. }) => "placeholder", + GenericArg::Infer(InferArg { kind: InferArgKind::Const, .. }) => "constant", } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 83b6e08e22b3c..3b721392519a7 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -981,7 +981,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( GenericArg::Type(ty) => visitor.visit_ty(ty), GenericArg::Const(ct) => visitor.visit_const_arg(ct), GenericArg::Infer(inf) => { - let InferArg { hir_id, span } = inf; + let InferArg { hir_id, span, kind: _ } = inf; visitor.visit_infer(*hir_id, *span, InferKind::Ambig(inf)) } } @@ -1446,7 +1446,7 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::R } pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result { - let InferArg { hir_id, span: _ } = inf; + let InferArg { hir_id, span: _, kind: _ } = inf; visitor.visit_id(*hir_id) } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index dcc5579e14339..e0bd6ed2741ce 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -219,7 +219,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { "synthetic HIR should have its `generics_of` explicitly fed" ), - Node::ConstArg(..) => { + Node::ConstArg(..) | Node::Infer(hir::InferArg { kind: hir::InferArgKind::Const, .. }) => { // These can show up in mGCA when representing "direct" const arguments. The // DefCollector cannot know whether an anon const will be represented by an actual HIR // Node::AnonConst, or whether it will be represented directly, so it must generate a diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 45c2ed205c74d..24be708ffd5a5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -254,7 +254,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( match (arg, ¶m.kind, arg_count.explicit_late_bound) { (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) | ( - GenericArg::Type(_) | GenericArg::Infer(_), + GenericArg::Type(_) + | GenericArg::Infer(hir::InferArg { + kind: hir::InferArgKind::TypeOrConst, + .. + }), GenericParamDefKind::Type { .. }, _, ) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b32a23f53f8cc..228600fa76794 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1428,7 +1428,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // anywhere so we don't need to encode it for other crates. // FIXME(mgca): This probably isn't true, they probably are accessed, but, test case? if def_kind == DefKind::AnonConst - && matches!(tcx.hir_node_by_def_id(local_id), hir::Node::ConstArg(_)) + && matches!( + tcx.hir_node_by_def_id(local_id), + hir::Node::ConstArg(_) + | hir::Node::Infer(hir::InferArg { kind: hir::InferArgKind::Const, .. }) + ) { continue; } diff --git a/tests/ui/const-generics/mgca/braced-const-infer-in-body.rs b/tests/ui/const-generics/mgca/braced-const-infer-in-body.rs new file mode 100644 index 0000000000000..a696ff5964e7f --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer-in-body.rs @@ -0,0 +1,23 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/160798 +#![crate_type = "lib"] +#![feature(min_generic_const_args)] +#![feature(macroless_generic_const_args)] + +trait Trait {} + +impl Trait for i32 {} + +struct S; + +fn main() { + // Const-only infer args used for a type parameter are rejected. + let _z: &[&dyn Trait<{ _ }>] = &[&0i32]; + //~^ ERROR: constant provided when a type was expected + let _y: &dyn Trait = &0i32; + //~^ ERROR: constant provided when a type was expected + + let _a: S<{ _ }> = S::<3>; + let _b: S = S::<3>; + let _c: S<{ core::direct_const_arg!(_) }> = S::<3>; + let _d: S<_> = S::<3>; +} diff --git a/tests/ui/const-generics/mgca/braced-const-infer-in-body.stderr b/tests/ui/const-generics/mgca/braced-const-infer-in-body.stderr new file mode 100644 index 0000000000000..dec966c111253 --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer-in-body.stderr @@ -0,0 +1,15 @@ +error[E0747]: constant provided when a type was expected + --> $DIR/braced-const-infer-in-body.rs:14:28 + | +LL | let _z: &[&dyn Trait<{ _ }>] = &[&0i32]; + | ^ + +error[E0747]: constant provided when a type was expected + --> $DIR/braced-const-infer-in-body.rs:16:48 + | +LL | let _y: &dyn Trait = &0i32; + | ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/mgca/braced-const-infer.rs b/tests/ui/const-generics/mgca/braced-const-infer.rs index e5b2df8af5568..ad68bb499f084 100644 --- a/tests/ui/const-generics/mgca/braced-const-infer.rs +++ b/tests/ui/const-generics/mgca/braced-const-infer.rs @@ -4,6 +4,6 @@ trait Trait {} -impl dyn Trait<{_}> {} //~ ERROR: the placeholder `_` is not allowed within types on item signatures +impl dyn Trait<{_}> {} //~ ERROR: constant provided when a type was expected fn main() {} diff --git a/tests/ui/const-generics/mgca/braced-const-infer.stderr b/tests/ui/const-generics/mgca/braced-const-infer.stderr index d8ffee4cd0e8f..eb8d877e618e5 100644 --- a/tests/ui/const-generics/mgca/braced-const-infer.stderr +++ b/tests/ui/const-generics/mgca/braced-const-infer.stderr @@ -1,9 +1,9 @@ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations +error[E0747]: constant provided when a type was expected --> $DIR/braced-const-infer.rs:7:17 | LL | impl dyn Trait<{_}> {} - | ^ not allowed in type signatures + | ^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0121`. +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.rs b/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.rs index c3b1bef810592..9e2c744c617c5 100644 --- a/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.rs +++ b/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.rs @@ -1,12 +1,13 @@ -//@ check-pass -//! It is very weird and mostly a compiler implementation quirk that direct_const_arg!(_) is allowed -//! to infer to a type rather than forcing it to be a constant. This test simply tracks/asserts the -//! current behavior. +//! `direct_const_arg!(_)` used to be allowed to infer to a type as a compiler +//! implementation quirk. Since it uses explicit const argument syntax, +//! it is now rejected when passed as a type argument #![feature(min_generic_const_args)] struct S(T); fn main() { let _: S = S(2u32); + //~^ ERROR: constant provided when a type was expected let _: S<{ core::direct_const_arg!(_) }> = S(2u32); + //~^ ERROR: constant provided when a type was expected } diff --git a/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.stderr b/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.stderr new file mode 100644 index 0000000000000..07e0faf0ba792 --- /dev/null +++ b/tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.stderr @@ -0,0 +1,15 @@ +error[E0747]: constant provided when a type was expected + --> $DIR/direct_const_arg-infer-as-type.rs:9:38 + | +LL | let _: S = S(2u32); + | ^ + +error[E0747]: constant provided when a type was expected + --> $DIR/direct_const_arg-infer-as-type.rs:11:40 + | +LL | let _: S<{ core::direct_const_arg!(_) }> = S(2u32); + | ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs index ef36148467c00..d96cd92aef628 100644 --- a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs @@ -3,7 +3,8 @@ #![allow(incomplete_features)] macro_rules! y { ( $($matcher:tt)*) => { - _ //~ ERROR: the placeholder `_` is not allowed within types on item signatures + _ //~ ERROR: constant provided when a type was expected + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures }; } @@ -15,6 +16,6 @@ const y: A< x } }, -> = 1; //~ ERROR: mismatched types +> = 1; fn main() {} diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr index 406206c59e18f..68160da0595a1 100644 --- a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr @@ -1,5 +1,5 @@ error[E0392]: type parameter `T` is never used - --> $DIR/macro-const-arg-infer.rs:10:10 + --> $DIR/macro-const-arg-infer.rs:11:10 | LL | struct A; | ^ unused type parameter @@ -7,23 +7,18 @@ LL | struct A; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error[E0308]: mismatched types - --> $DIR/macro-const-arg-infer.rs:18:5 +error[E0747]: constant provided when a type was expected + --> $DIR/macro-const-arg-infer.rs:6:9 | -LL | const y: A< - | __________- -LL | | { -LL | | y! { +LL | _ + | ^ +... +LL | / y! { LL | | x LL | | } -LL | | }, -LL | | > = 1; - | | - ^ expected `A<_>`, found integer - | |_| - | expected because of the type of the constant + | |_________- in this macro invocation | - = note: expected struct `A<_>` - found type `{integer}` + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/macro-const-arg-infer.rs:6:9 @@ -40,5 +35,5 @@ LL | | } error: aborting due to 3 previous errors -Some errors have detailed explanations: E0121, E0308, E0392. +Some errors have detailed explanations: E0121, E0392, E0747. For more information about an error, try `rustc --explain E0121`.