Open mattmassicotte opened 2 months ago
Ok it is possible I have made progress despite me having aboslutely no idea what I am doing.
I've narrowed down the problem to a constructor:
ArgumentMismatchFailure(const Solution &solution, Type argType,
Type paramType, ConstraintLocator *locator,
FixBehavior fixBehavior =
FixBehavior::Error)
: ContextualFailure(solution, argType, paramType, locator, fixBehavior),
Info(*getFunctionArgApplyInfo(getLocator())) {}
This ends up invoking:
std::optional<FunctionArgApplyInfo>
Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const
which is, as you might have guessed, returning null. That's being unconditionally dereferenced in the constructor above, causing the crash.
Ok! Solution::getFunctionArgApplyInfo
is getting all the way to the end, calling FunctionArgApplyInfo::get
. That function is the one returning std::nullopt
, because the following is true:
paramIdx >= fnType->getNumParams()
Thanks to the forums, I have more information by running this with -Xfrontend -debug-constraints
. A lot of output was produced, but I'm including the last bit becuase it seems the most relevant. If more is needed, I can get it!
Overload choices:
locator@0x1569ea850 [DeclRef@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:44] with EmpireTests.(file).TestRecord extension.select(in:a:).a@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:29:63 as a: String
locator@0x1569ea200 [DeclRef@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:10] with EmpireTests.(file).TestRecord extension.select(in:a:).context@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:29:34 as context: TransactionContext
locator@0x1569eaa10 [Call@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32 → apply function → constructor member] with Empire.(file).Query.init(_:last:)@/Users/matt/Developer/Empire/Sources/Empire/Query.swift:42:9 as Query<Pack{/* shape: $T2 */ repeat $T2}, $T3>.Type.init: ($T9, ComparisonOperator<$T8>) -> Query<Pack{/* shape: $T2 */ repeat $T2}, $T3>
locator@0x1569ea278 [UnresolvedDot@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:18 → member] with Empire.(file).TransactionContext.select(query:)@/Users/matt/Developer/Empire/Sources/Empire/Store.swift:74:14 as TransactionContext.select: (Query<Pack{$T14}, $T13>) throws -> sending [$T11]
Constraint restrictions:
Query<<<hole>>> to Query<<<hole>>> is [deep equality]
Array<TestRecord> to Array<TestRecord> is [deep equality]
Trailing closure matching:
locator@0x1569ea250 [UnresolvedDot@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:18 → apply argument]: forward
locator@0x1569ea978 [Call@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32 → apply argument]: forward
locator@0x156c49df8 [Call@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:18 → apply argument]: forward
Opened types:
locator@0x1569ea418 [Type@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32] opens 'Last' (τ_0_1) -> <<hole>> [from $T3], 'each Component' (each τ_0_0) -> Pack{} [from $T2]
locator@0x1569eaa10 [Call@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32 → apply function → constructor member] opens 'Last' (τ_0_1) -> <<hole>> [from $T8], 'each Component' (each τ_0_0) -> Pack{} [from $T7]
locator@0x1569ea278 [UnresolvedDot@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:18 → member] opens 'Last' (τ_0_2) -> <<hole>> [from $T13], 'Record' (τ_0_0) -> TestRecord [from $T11], 'each Component' (each τ_0_1) -> Pack{} [from $T12]
Defaulted constraints: locator@0x1569ea490 [Type@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32 → generic parameter 'Last']
Fixes:
[fix: allow argument to parameter type conversion mismatch] @ locator@0x156c493d8 [Call@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32 → apply argument → comparing call argument #0 to parameter #1]
[fix: default generic argument 'Last' to 'Any'] @ locator@0x1569ea418 [Type@@__swiftmacro_11EmpireTests10TestRecord08IndexKeyD0fMe_.swift:30:32]
Assertion failed: (!HasOriginalArgs && "Query original args instead"), function isTrailingClosureIndex, file ArgumentList.h, line 434.
Here are sample sources that reproduce the issue.
Input file:
public enum ComparisonOperator<Value: Comparable> {
}
public struct Query<each Component: Comparable, Last: Comparable> {
public let last: ComparisonOperator<Last>
public let components: (repeat each Component)
public init(_ value: repeat each Component, last: ComparisonOperator<Last>) {
self.components = (repeat each value)
self.last = last
}
}
public protocol IndexKeyRecord {
}
@attached(
extension,
conformances: IndexKeyRecord,
names:
named(select)
)
public macro IndexKeyRecord(
_ first: StaticString,
_ remaining: StaticString...
) = #externalMacro(module: "EmpireMacros", type: "IndexKeyRecordMacro")
@IndexKeyRecord("a")
struct TestRecord: Hashable {
let a: String
}
Macro definition:
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
public struct IndexKeyRecordMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
return [
try dataManipulationExtensionDecl(type: type),
]
}
}
extension IndexKeyRecordMacro {
private static func dataManipulationExtensionDecl(
type: some TypeSyntaxProtocol
) throws -> ExtensionDeclSyntax {
let queryArguments = "last: a"
let funcDecl = try FunctionDeclSyntax(
"""
public static func select() {
Query(\(raw: queryArguments))
}
"""
)
return ExtensionDeclSyntax(
extendedType: type,
memberBlock: MemberBlockSyntax(
members: MemberBlockItemListSyntax(
[MemberBlockItemSyntax(decl: funcDecl)]
)
)
)
}
}
Description
I swear I tried my best to reduce this. Every time I tried, the crash would go away. So, what I did instead was create a branch that will reproduce the issue. I know this is pretty far for ideal, but is the best I could do. I would be happy to include more information if there's anything I can do to help.
https://github.com/mattmassicotte/Empire/tree/macro-parse-crash
Running the tests for
EmpireTests
will reproduce the crash.The line that is ultimately responsible seems to be
Sources/EmpireMacros/IndexKeyRecordMacro.swift:186
Relevent line in the macro generation that kills it:
queryArguments = "a, last: b"
It is something about the formation of
Query(\(raw: queryArguments))
+ the content ofqueryArguments
that is the problem. I have been able to make the crash disappear by changing and/or removing the label. It is matching an initializer that looks like this:Reproduction
See the attached branch. I was unable to reduce this further.
Stack dump
Expected behavior
The macro should build valid code.
Environment
Apple Swift version 6.0-dev (LLVM 5b37bd4c1c578e9, Swift 54898ce105c7185) Target: arm64-apple-macosx14.0
Additional information
No response