Open lukaskollmer opened 2 months ago
Update:
Having looked into this a bit more (and spent some more time trying to work around this issue), it seems like this is in fact not caused by the use of set/dictionary literals, but rather is somehow directly related to the use of a single class type in the generic type parameter pack?
To provide some more context, the HashableTuple
defined above is used as part of a memoize
function:
func memoize<each Input: Hashable, Output>(_ fn: @escaping (repeat each Input) -> Output) -> (repeat each Input) -> Output {
var cache: [HashableTuple<repeat each Input>: Output] = .init()
return { (input: repeat each Input) -> Output in
let key = HashableTuple(elements: (repeat each input))
// rest omitted bc not relevant
}
}
even though declaring and initializing a dict as a global variable using .init()
works (as seen in the original post), it still fails when done within a function.
As with the initial issue, this seems to happen only if the type using a generic type parameter pack (HashableTuple
in this case) is instantiated using only a single class type parameter.
Simply always adding an implicit trailing non-class type parameter to the pack (and thereby ensuring it never consists of only a single class type) seems to work around this issue:
private struct EmptyStruct: Hashable {}
func memoize<each Input: Hashable, Output>(_ fn: @escaping (repeat each Input) -> Output) -> (repeat each Input) -> Output {
var cache: [HashableTuple<repeat each Input, EmptyStruct>: Output] = [:] // <--
return { (input: repeat each Input) -> Output in
let key = HashableTuple(elements: (repeat each input, EmptyStruct())) // <--
// rest omitted bc not relevant
}
}
Description
Attempting to create an instance of a
Set
or aDictionary
where the generic parameter (Element
in the case of theSet
, andKey
in the case of theDictionary
) is a Hashable type that uses variadic generics and is passed a single class type as its type parameter pack, crashes the compiler in a release build. (Sometimes also depending on if the Set or Dictionary is created using a literal.)See the example program below: it defines several variables (sets and dictionaries) with different parameters for the generic parameter, and using different ways of initialising the values (using a literal and using
.init()
).When compiled with a debug build, the entire program will compile without any issues. But in a release build, the compiler will crash if the program contains at least one instantiation of
Set
orDictionary
where the Hashable generic parameter isHashableTuple<C>
. For some reason, this only happens whenHashableTuple
's parameter pack consists of a single class type. If a struct type is specified instead, or multiple class types, or a mix of class and struct types, everything seems to work just fine.I also tried defining a custom type with a Hashable-constrained generic parameter that implements ExpressibleByArrayLiteral, but for some reason instantiating that instead of eg Set worked fine (ie, didn't crash the compiler).
Reproduction
Stack dump
Expected behavior
IMO this should compile just fine.
Environment
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4) Target: arm64-apple-macosx14.0
Additional information
i also tried this with the nightly compiler, which also crashed.