[Pitch] Expression macro as caller-side default argument

Hi everyone,

I have a pitch for lifting the restriction afore set in SE-0382 "Expression macros" to allow non-built-in expression macros as caller-side default argument expressions, where they are expanded with each call site's source location and declaration context:

// in MyLibrary.swift =======
@freestanding(expression)
macro MyFileID<T: ExpressibleByStringLiteral>() -> T = ...

public func callSiteFile(_ file: String = #MyFileID) { file }

// in main.swift ============
print(callSiteFile())  // print main.swift, the current file

You can read the full proposal at the link below. Let me know what you think!

12 Likes

This seems like a very natural way to bring #line & Co out of compiler magic land. Restricting arguments to literals seems like a good compromise to avoid some potentially very confusing situations.

Very sensible proposal, both the motivation and the solution just make sense.

4 Likes

Huge +1.

I've encountered this limitation when working on a #context macro. This macro aims to combine #file, #function, #line, #column, and similar identifiers into a single structure, offering a more convenient way for propagating source location information. This would let us realize @davedelong's original idea. The challenge lies in the requirement for default arguments to be literals, which complicates the process. However, it's feasible to encapsulate this information into a single string literal to meet this requirement.

2 Likes

Yeah, I have also tried to implement #context using macros and it's hitting the callsite-versus-codesite issue. I think this pitch would definitely help work around that.

"Implementation-side Question

How does this work across module boundaries, where the original syntax nodes for a default argument expression aren’t usually available? Are the tokens saved and reparsed at expansion time? Or are these macros required to not have arguments, so a synthetic node isn’t really missing anything?

4 Likes

current implementation saves textual representation and re-parse at expansion time with new source location

Or are these macros required to not have arguments, so a synthetic node isn’t really missing anything?

the proposal addressed this in Type-checking default argument macro expressions:

its arguments, if any, must be literals

I believe this will also ensure that it's not missing anything at call site

3 Likes