Last active
January 26, 2016 03:50
-
-
Save jepers/72417e6eb84632b59239 to your computer and use it in GitHub Desktop.
Example of something that takes a long time to type check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This little program takes ~ 6 seconds to compile on my MacBook Pro Late 2013. | |
// It compiles and works as expected. But the type checker spends a lot of time | |
// on the function at the end. | |
// In my actual project, I have much more code like this, and it results in very | |
// long compile times. So I'd like to know if there is something I can do to | |
// speed that up. | |
protocol DefaultInitializable { init() } | |
extension Float : DefaultInitializable {} | |
protocol CountType { static var value: Int { get } } | |
struct Count0 : CountType { static var value: Int { return 0 } } | |
struct CountSuccesorOf<T: CountType> : CountType { static var value: Int { return T.value + 1 } } | |
extension CountType { | |
typealias Plus1 = CountSuccesorOf<Self> | |
typealias Plus2 = Plus1.Plus1 | |
typealias Plus3 = Plus1.Plus2 | |
typealias Plus4 = Plus1.Plus3 | |
} | |
typealias Count1 = Count0.Plus1 | |
typealias Count2 = Count0.Plus2 | |
typealias Count3 = Count0.Plus3 | |
typealias Count4 = Count0.Plus4 | |
protocol StaticArrayType : DefaultInitializable, CollectionType { | |
typealias Element: DefaultInitializable | |
typealias Count: CountType | |
//typealias Successor = StaticArraySuccessorOf<Self> // (As a side note: This line has to be in an extension, or debug-built binary will crash (while release-built binary works as expected). Filed radar 23602584 about this.) | |
} | |
extension StaticArrayType { | |
typealias Successor = StaticArraySuccessorOf<Self> // (As a side note about a side note: See comment above.) | |
typealias Successor2 = Successor.Successor | |
typealias Successor3 = Successor2.Successor | |
} | |
// A concrete static array type with one element of type E. | |
struct StaticArray<E: DefaultInitializable> : StaticArrayType { | |
typealias Element = E | |
typealias Count = Count1 | |
var storage = Element() | |
typealias WithCount1 = StaticArray | |
typealias WithCount2 = StaticArray.Successor | |
typealias WithCount3 = StaticArray.Successor2 | |
typealias WithCount4 = StaticArray.Successor3 | |
} | |
// A concrete static array type with one more element than its predecessor P. | |
struct StaticArraySuccessorOf<P: StaticArrayType> : StaticArrayType { | |
typealias Predecessor = P | |
typealias Element = Predecessor.Element | |
typealias Count = Predecessor.Count.Plus1 | |
var storage = (Element(), Predecessor()) | |
} | |
// Default implementation of conformance to CollectionType: | |
extension StaticArrayType where Index == Int, Generator.Element == Element { | |
var startIndex: Int { return 0 } | |
var endIndex: Int { return Count.value } | |
func generate() -> IndexingGenerator<Self> { return IndexingGenerator(self) } | |
subscript(index: Int) -> Generator.Element { | |
get { precondition(index >= 0 && index < count) | |
var selfCopy = self; return withUnsafePointer(&selfCopy, { UnsafePointer<Generator.Element>($0)[index] }) } | |
set { precondition(index >= 0 && index < count) | |
withUnsafeMutablePointer(&self) { UnsafeMutablePointer<Generator.Element>($0)[index] = newValue } | |
} | |
} | |
} | |
// Conformance to CustomStringConvertible: | |
extension StaticArray : CustomStringConvertible {} | |
extension StaticArraySuccessorOf : CustomStringConvertible {} | |
extension StaticArrayType { | |
var description: String { | |
var a: [String] = [] | |
for i in self.indices { a.append("\(self[i])") } | |
return "(" + a.joinWithSeparator(", ") + ")" | |
} | |
} | |
// This is the function that (together with the above type definitions) demonstrates | |
// the type of thing on which the compiler spends nearly all of its time type checking. | |
// (As can be seen when compiling with -Xfrontend -debug-time-function-bodies) | |
func functionThatTakesTimeToTypeCheck() { | |
typealias Float4 = StaticArray<Float>.WithCount4 | |
typealias Float4x4 = StaticArray<Float4>.WithCount4 | |
var a = Float4x4() | |
for row in a.indices { | |
for col in a[row].indices { | |
a[row][col] = Float(row) + Float(col) / 10.0 | |
} | |
} | |
print(a) | |
print(strideof(Float4x4)) | |
} | |
functionThatTakesTimeToTypeCheck() | |
//---------------------------------------------------------------------------- | |
// Example of compiling it: | |
//---------------------------------------------------------------------------- | |
// $ time swiftc -O -Xfrontend -debug-time-function-bodies test.swift | |
// 0.1ms test.swift:10:51 get {} | |
// 0.0ms test.swift:10:8 init() | |
// 0.6ms test.swift:11:74 get {} | |
// 0.0ms test.swift:11:8 init() | |
// 0.0ms test.swift:34:8 init() | |
// 0.0ms test.swift:44:8 init() | |
// 0.0ms test.swift:52:25 get {} | |
// 0.0ms test.swift:53:23 get {} | |
// 0.2ms test.swift:54:10 func generate() -> IndexingGenerator<Self> | |
// 2.3ms test.swift:56:9 get {} | |
// 1.5ms test.swift:58:9 set {} | |
// 9.2ms test.swift:67:29 get {} | |
// 5229.8ms test.swift:76:6 func functionThatIsSlowCompileSlashTypeCheck() | |
// 0.0ms <invalid loc> init() | |
// | |
// real 0m6.282s | |
// user 0m6.028s | |
// sys 0m0.253s | |
//---------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Removing the inheritance from CollectionType from the StaticArrayType protocol makes this example program compile fast (blink of an eye instead of 6 s), here's the modified program:
protocol DefaultInitializable { init() }
extension Float : DefaultInitializable {}
protocol CountType { static var value: Int { get } }
struct Count0 : CountType { static var value: Int { return 0 } }
struct CountSuccesorOf<T: CountType> : CountType { static var value: Int { return T.value + 1 } }
extension CountType {
typealias Plus1 = CountSuccesorOf
typealias Plus2 = Plus1.Plus1
typealias Plus3 = Plus1.Plus2
typealias Plus4 = Plus1.Plus3
}
typealias Count1 = Count0.Plus1
typealias Count2 = Count0.Plus2
typealias Count3 = Count0.Plus3
typealias Count4 = Count0.Plus4
protocol StaticArrayType : DefaultInitializable, CustomStringConvertible {
typealias Element: DefaultInitializable
typealias Count: CountType
//typealias Successor = StaticArraySuccessorOf // (As a side note: This line has to be in an extension, or debug-built binary will crash (while release-built binary works as expected). Filed radar 23602584 about this.)
}
extension StaticArrayType {
typealias Successor = StaticArraySuccessorOf // (As a side note about a side note: See comment above.)
typealias Successor2 = Successor.Successor
typealias Successor3 = Successor2.Successor
}
// A concrete static array type with one element of type E.
struct StaticArray<E: DefaultInitializable> : StaticArrayType {
typealias Element = E
typealias Count = Count1
var storage = Element()
typealias WithCount1 = StaticArray
typealias WithCount2 = StaticArray.Successor
typealias WithCount3 = StaticArray.Successor2
typealias WithCount4 = StaticArray.Successor3
}
// A concrete static array type with one more element than its predecessor P.
struct StaticArraySuccessorOf<P: StaticArrayType> : StaticArrayType {
typealias Predecessor = P
typealias Element = Predecessor.Element
typealias Count = Predecessor.Count.Plus1
var storage = (Element(), Predecessor())
}
extension StaticArrayType {
var count: Int { return Count.value }
var indices: Range { return 0 ..< count }
subscript(index: Int) -> Element {
get { precondition(index >= 0 && index < count)
var selfCopy = self; return withUnsafePointer(&selfCopy, { UnsafePointer($0)[index] }) }
set { precondition(index >= 0 && index < count)
withUnsafeMutablePointer(&self) { UnsafeMutablePointer($0)[index] = newValue }
}
}
var description: String {
var a: [String] = []
for i in self.indices { a.append("(self[i])") }
return "(" + a.joinWithSeparator(", ") + ")"
}
}
func functionThatTakesTimeToTypeCheck() {
typealias Float4 = StaticArray.WithCount4
typealias Float4x4 = StaticArray.WithCount4
var a = Float4x4()
for row in a.indices {
for col in a[row].indices {
a[row][col] = Float(row) + Float(col) / 10.0
}
}
print(a)
print(strideof(Float4x4))
}
functionThatTakesTimeToTypeCheck()