Given that my definition of “semantically static” has been revised a few times here, I thought I should try to nail it down rigorously and formally. It's really hard, though, and that is a good indicator that the whole concept might (cough) be nonsense and I might be wasting everybody's time. So, to those of you who hadn't already figured it out, consider yourself warned. For anyone not yet deterred, I'm still going to take one last stab at defining what I meant.
Part of what makes it hard does indeed come from infinite types. Doug demonstrated that the set of concrete types in the program cannot be known at compile time, even if all sources are visible. Here's an even simpler demo:
struct X<T> {
static func f(_ n: Int) {
if n != 0 { X<Self>.f(n - 1) } // nesting level of X's depends on n
}
}
X<Void>.f(Int(CommandLine.arguments[1])!)
Given the possibility of mutual recursion, the set of possible concrete types can be arbitrarily complex and not even easily characterized, much less enumerated.¹
Fortunately, accepting this fact led me to an approach that I think captures what I've been trying to say, and it's better formulated as a property of conformances than of programs, where by “conformance” I mean specifically the set of implementations used to satisfy any given protocol's requirements. I hope @Douglas_Gregor will confirm this to be part of the intended design:
In Swift, at the moment a concrete type is bound to a generic parameter, we can determine all of the type's conformances to any protocols.
I also hope that this is intended:
The determination of conformances can be done entirely based on declarations visible in the scope where the binding occurs.
Thanks for your indulgence, everybody! Now to dig into earlier posts from Doug and Joe…
¹ I can easily see how the possibility of arbitrary types at run time could cause ambiguities that can only be diagnosed at run time (which Doug mentioned), and wonder if that was considered before we made infinite types “a thing.”