Skip to content

Reject non-constructor self types in const-arg tuple-call lowering - #157513

Open
Dnreikronos wants to merge 4 commits into
rust-lang:mainfrom
Dnreikronos:fix-tracing-const-arg-157152
Open

Reject non-constructor self types in const-arg tuple-call lowering#157513
Dnreikronos wants to merge 4 commits into
rust-lang:mainfrom
Dnreikronos:fix-tracing-const-arg-157152

Conversation

@Dnreikronos

@Dnreikronos Dnreikronos commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Turning on min_generic_const_args makes tracing stop compiling. Its logging macros expand a field name to something like FieldName<{ FieldName::len(stringify!(field)) }>, and under mgca a braced call in const-arg position gets lowered as a tuple constructor. So lowering tries to resolve the bare self type FieldName (written without its const N), which kicks off an E0107 "missing generics" cascade pointing deep into macro code. But FieldName::len(..) is just an associated fn, not a constructor, so lowering it like a TupleCall was wrong in the first place. See #157152.

Only an enum can host a tuple-variant ctor, so for any other self type that can't (struct, union, primitive, foreign type) the call has to be an assoc fn and needs wrapping in const { ... }. We catch those from the self type's resolution before lowering it and emit the existing "complex const arguments must be placed inside of a const block" error, which is the message you'd want anyway. Enums, aliases, Self and type params get left alone since they might resolve to an enum. tbh the bare generic enum case (Option::Some(0)) still E0107s, and imo that's better as a follow-up since catching it needs the variant type before lowering. Tests cover struct/union/primitive/foreign plus the wrapped forms that compile, and I checked it against the real tracing 0.1.44 crate too.

fwiw just the code changes and tests were implemented with AI help and I verified/reproduced/tested everything locally before sending to remote.

@rustbot

rustbot commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

HIR ty lowering was modified

cc @fmease

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 5, 2026
@rustbot

rustbot commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

BoxyUwU is currently at their maximum review capacity.
They may take a while to respond.

@Dnreikronos

Copy link
Copy Markdown
Contributor Author

r? @fmease

cc @BoxyUwU

@rustbot rustbot assigned fmease and unassigned BoxyUwU Jun 6, 2026
@Dnreikronos

Copy link
Copy Markdown
Contributor Author

Hi, @fmease!
Need something from my side here to continue the work?

@BoxyUwU

BoxyUwU commented Jul 22, 2026

Copy link
Copy Markdown
Member

r? BoxyUwU

@rustbot rustbot assigned BoxyUwU and unassigned fmease Jul 22, 2026
//@ compile-flags: -Znext-solver

#![feature(min_generic_const_args)]
#![feature(generic_const_args)]

@BoxyUwU BoxyUwU Jul 22, 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.

this PR will need a rebase since we've changed a lot of the rules around what is considered an anon const or not. i think to reproduce this now you'll need macroless_generic_const_args enabled.

View changes since the review

hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
_ => Res::Err,
};
if matches!(

@BoxyUwU BoxyUwU Jul 22, 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.

can you move this logic into a separate fn, something like try_recover_misrepresented_function_call so that the good-path logic isn't complicated by diagnostics stuff.

View changes since the review

@BoxyUwU

BoxyUwU commented Jul 22, 2026

Copy link
Copy Markdown
Member

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 22, 2026
@rustbot

rustbot commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

A braced const argument that is a call, like `Ty<{ Ty::f() }>`, is lowered
as a tuple constructor. When the callee's self type cannot host a
tuple-variant constructor (a struct, union, primitive, or foreign type),
the call is an associated function, not a constructor, and must be wrapped
in a `const { ... }` block.

Detect that from the self type's resolution before lowering it, and emit
the existing "complex const arguments must be placed inside of a `const`
block" diagnostic. A generic struct written without its arguments, as
`tracing`'s logging macros generate, would otherwise produce a spurious
E0107 "missing generics" cascade; a primitive or foreign type would
surface an opaque "invalid base path" error.

Enums, aliases, `Self`, and type parameters are left to constructor
lowering, since each may resolve to an enum.

Add UI tests for struct, union, primitive, and foreign self types, plus
the `const { ... }`-wrapped form that compiles.
@Dnreikronos
Dnreikronos force-pushed the fix-tracing-const-arg-157152 branch from 706a7b5 to cceaea0 Compare July 23, 2026 00:03
@rustbot

rustbot commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Dnreikronos

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 23, 2026
Comment on lines +2508 to +2511
fn error_complex_const_arg(&self, span: Span) -> ErrorGuaranteed {
self.dcx()
.span_err(span, "complex const arguments must be placed inside of a `const` block")
}

@bit-aloo bit-aloo Jul 23, 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.

Can we inline this?

View changes since the review

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.

I think it's nice having it outlined so the errors don't diverge :3 though we could be using a structured diagnostic here instead of embedding strings into the source

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I went with the structured diagnostic you suggested. Both sites emit ComplexConstArg, so the message still has one source of truth even though the emissions are inline. btw imo this is a pretty clean compromise with Shourya's suggestion. ltm if you meant keeping the helper around the structured diag too.

Comment on lines +2531 to +2535
matches!(
self_ty_res,
Res::Def(DefKind::Struct | DefKind::Union | DefKind::ForeignTy, _) | Res::PrimTy(_)
)
.then(|| self.error_complex_const_arg(span))

@bit-aloo bit-aloo Jul 24, 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.

With this we do not handle enum associated function calls. In the current lowering path, a call like E::len() is allowed to fall through because E::V(..) could be a valid tuple-variant constructor. If E is generic and written without its generic arguments, lowering the self type then emits a misleading error. Maybe we can handle this case here?

For example:

enum E<const N: usize> {
     V,
}

impl E<0> {
     const fn len() -> usize { 1 }
}

fn bad2(_: FieldName<{ E::len() }>) {}

View changes since the review

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.

I think it's tricky to handle enums because they do actually need to go into the codepath where we resolve len to tell whether its a tuple constructor or a function 🤔

struct/union/foreignty/primty are all nice because they will never resolve to a tuple constructor so this codepath is always an error

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.

we could in theory manually check the generics of the enum against the args here, but I don't want us to maintain a second codepath for trying to lower the ty in a way that doesnt emit errors if it fails

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fyi I left enum handling out after reading your follow-up. I tried the precheck locally, but it started duplicating resolver decisions just to avoid emitting the first error. imo that is not worth maintaining for this regression. idk of a clean non-emitting path we can reuse here, so I'd rather leave enums on the existing flow and handle them separately later. ltm if there is an API I missed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants