Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
})),
};
}
_ => {}
Expand All @@ -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,
})),
}
}
}
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<direct_const_arg!(_)>. It can only be inferred to a const.
Const,
}

@khyperia khyperia Aug 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a short comment here, explaining the purpose of this, if there's no other comment elsewhere in code - "S::<_> is allowed to infer to either a type or a const, but S::<{ _ }> must infer to a constant, so this tracks that" kind of thing, idk exact phrasing. just, having concrete examples of "why is this a thing / when does it happen" is super useful for me personally when reading code!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a short description.


#[derive(Clone, Copy, Debug, StableHash)]
pub struct InferArg {
#[stable_hash(ignore)]
pub hir_id: HirId,
pub span: Span,
pub kind: InferArgKind,
}

impl InferArg {
Expand All @@ -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<'_> {
Expand All @@ -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",
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
Expand Down Expand Up @@ -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)
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
match (arg, &param.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 { .. },
_,
)
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/const-generics/mgca/braced-const-infer-in-body.rs
Original file line number Diff line number Diff line change
@@ -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<T> {}

impl Trait<i32> for i32 {}

struct S<const N: usize>;

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<core::direct_const_arg!(_)> = &0i32;
//~^ ERROR: constant provided when a type was expected

let _a: S<{ _ }> = S::<3>;
let _b: S<core::direct_const_arg!(_)> = S::<3>;
let _c: S<{ core::direct_const_arg!(_) }> = S::<3>;
let _d: S<_> = S::<3>;
}
15 changes: 15 additions & 0 deletions tests/ui/const-generics/mgca/braced-const-infer-in-body.stderr
Original file line number Diff line number Diff line change
@@ -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<core::direct_const_arg!(_)> = &0i32;
| ^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0747`.
2 changes: 1 addition & 1 deletion tests/ui/const-generics/mgca/braced-const-infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

trait Trait<T> {}

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() {}
6 changes: 3 additions & 3 deletions tests/ui/const-generics/mgca/braced-const-infer.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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>(T);

fn main() {
let _: S<core::direct_const_arg!(_)> = 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
}
15 changes: 15 additions & 0 deletions tests/ui/const-generics/mgca/direct_const_arg-infer-as-type.stderr
Original file line number Diff line number Diff line change
@@ -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<core::direct_const_arg!(_)> = 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`.
5 changes: 3 additions & 2 deletions tests/ui/const-generics/mgca/macro-const-arg-infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}

Expand All @@ -15,6 +16,6 @@ const y: A<
x
}
},
> = 1; //~ ERROR: mismatched types
> = 1;

fn main() {}
25 changes: 10 additions & 15 deletions tests/ui/const-generics/mgca/macro-const-arg-infer.stderr
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
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<T>;
| ^ unused type parameter
|
= 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
Expand All @@ -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`.
Loading