> On Dec 5, 2017, at 4:05 PM, Douglas Gregor via swift-dev > <swift-dev@swift.org> wrote: > > > >> On Dec 5, 2017, at 3:56 PM, David Hart <da...@hartbit.com >> <mailto:da...@hartbit.com>> wrote: >> >> But that wouldn’t allow surfacing a func type(named: String) Standard >> Library function that worked on any type, wouldn’t it (like the Dictionary >> with non-Hashable key)? > > As I noted to John, we still need to handle the general case for the > right-hand side of a same-type constraint, which can be an arbitrary type. > That requires all of the functionality of type(named:). > > That said, from my perspective, adding type(named:) is entirely “gravy”. We > get it for free from this implementation plan, but IMO it could be added to > some later version of Swift and that would be fine.
I agree that surfacing it in the stdlib is gravy, but implementing the underlying mechanism is important, IMO. Field type vector accessors are a large contributor to binary code size (I wouldn’t be surprised if it was 5-10% for some projects) and implementing a more efficient encoding for ABI stability would be nice. Slava > > - Doug > >> >> On 6 Dec 2017, at 00:42, John McCall via swift-dev <swift-dev@swift.org >> <mailto:swift-dev@swift.org>> wrote: >> >>>> On Dec 5, 2017, at 5:28 PM, Douglas Gregor via swift-dev >>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote: >>>> Hi all, >>>> >>>> The main missing piece for conditional conformances >>>> (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md >>>> >>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md>) >>>> is support for dynamic casting. Right now, dynamic casting that queries a >>>> conditional conformance will always fail. Here’s an example: >>>> >>>> protocol P { >>>> func foo() >>>> } >>>> >>>> struct X : P { >>>> func foo() { print("X.P") } >>>> } >>>> >>>> struct Y<T> { >>>> var wrapped: T >>>> } >>>> >>>> extension Y: P where T: P { >>>> func foo() { wrapped.foo() } >>>> } >>>> >>>> func tryAsP(_ value: Any) { >>>> if let p = value as? P { >>>> p.foo() >>>> } >>>> } >>>> >>>> let yx = Y(wrapped: X()) >>>> tryAsP(yx) >>>> >>>> This won’t print anything, but should print “X.P”. We’d like to fix that :) >>>> >>>> Joe Groff, Slava, and I discussed an approach to implement dynamic casting >>>> for conditional conformances, which I’d like to outline here. >>>> >>>> Background >>>> The Swift runtime expresses the conformance of a specific type (say >>>> Array<Int>) to a particular protocol (say, Equatable) using a witness >>>> table. Witness tables contain the actual associated types as well as >>>> function pointers for each of the requirements of a protocol. Slava and >>>> John’s talk on Implementing Swift Generics >>>> (https://llvm.org/devmtg/2017-10/#talk15 >>>> <https://llvm.org/devmtg/2017-10/#talk15>) gives a bunch of background >>>> here. >>>> >>>> When a conformance is conditional, the witness table also stores the >>>> conditional requirements. So, the witness table for Array<Int>: Equatable >>>> has to store the witness table Int: Equatable. In the example above, the >>>> witness table for Y<X>: P needs to store a pointer to the witness table X: >>>> P. The compiler knows how to pass along the witness tables needed for a >>>> conditional conformance, but for runtime casting to work, we need to (1) >>>> evaluate all of the conditional requirements to determine whether they >>>> apply (e.g., does T: P for a specific T?) and then (2) pass those witness >>>> tables along when building the witness table. The cast should fail if any >>>> of the conditional requirements goes unsatisfied, and produce a valid >>>> witness table otherwise. >>>> >>>> Protocol Conformance Records >>>> Whenever code declares conformance of a particular type to a given >>>> protocol, the compiler emits a “protocol conformance record” (documented >>>> at >>>> https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-conformance-records >>>> >>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-conformance-records>). >>>> These protocol conformance records state the type declaring conformance >>>> (e.g., Y) and the protocol (e.g., P), and then provide a witness table >>>> accessor to form the witness table given type metadata for a specific type >>>> instance (e.g., Y<X>). In the case of a conditional conformance, this >>>> accessor also needs to be passed the witness tables for any conditional >>>> requirements, e.g., the witness table for X: P. >>>> >>>> Conditional Requirements in Protocol Conformance Records >>>> Somehow we need to dynamically evaluate the conditional requirements. For >>>> example, we need to know that for the X<T>: P conformance to be valid, we >>>> need T: P to hold for the given T. So, we’ll extend the protocol >>>> conformance record with an encoding of those requirements. Fortunately, we >>>> already have a way to encode arbitrary generic requirements: the mangling >>>> of a generic-signature (see >>>> https://github.com/apple/swift/blob/master/docs/ABI/Mangling.rst#generics >>>> <https://github.com/apple/swift/blob/master/docs/ABI/Mangling.rst#generics>) >>>> already encodes arbitrary generic requirements, so we can put a string >>>> comprised of the mangled conditional requirements into the protocol >>>> conformance record. >>>> >>>> When evaluating a conditional conformance, we demangle the conditional >>>> requirements to get something like: “T must conform to P”. We then need to >>>> substitute the type arguments (e.g., X) for the corresponding type >>>> parameters (T) to form type metadata for the requirements. In this case, >>>> we’d get the type metadata pointer for Y and the protocol descriptor for >>>> P, and then call swift_conformsToProtocol() to determine whether the >>>> requirement holds. If it does, swift_conformsToProtocol() produces the Y: >>>> P witness table we need to pass along to the witness table accessor. >>>> >>>> Note that the conditional requirements can be arbitrarily complicated. For >>>> example, given: >>>> >>>> extension Dictionary: P where Value == (Key) -> Bool { … } >>>> >>>> Even though the result of evaluating this same-type requirement doesn’t >>>> need to be passed along to the witness table accessor, we still need to >>>> evaluate the requirement to determine whether the conditional conformance >>>> to P applies. To do so, we will need to substitute type arguments for both >>>> Value and Key, and need to form the type metadata representing the >>>> (substituted) function type (Key) -> Bool to determine if it is equivalent >>>> to the (substituted) type of Value (which is then determined by type >>>> metadata pointer equality because the runtime uniques type metadata). >>>> >>>> Looking up Type Metadata For a Mangled Name >>>> To perform that mapping from a mangled type in a conditional requirement >>>> to type metadata, we effectively need an operation to take a mangled type >>>> name and turn it into a type metadata pointer. This is something we could >>>> surface in the Swift standard library/runtime as, e.g., >>>> >>>> func type(named: String) -> Any.Type? >>>> >>>> to take a mangled type name and try to get the type metadata for it. From >>>> there, one can query protocol conformances that (say) allow one to >>>> construct instances of the arbitrarily-named type. Think of it as >>>> NSClassFromString for any type in the Swift language, including >>>> specializations of generic types. >>>> >>>> To get here, we’ll also need to extend the nominal type descriptor >>>> (https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#nominal-type-descriptor >>>> >>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#nominal-type-descriptor>) >>>> to contain the generic signature of a nominal type. That let’s us safely >>>> create specializations of generic types. For example, if one tries to form >>>> Dictionary<A, B> where A does not conform to Hashable, type(named:) should >>>> return “nil” rather than an invalid type. The same logic that will be used >>>> to form type metadata when checking conditional requirements will apply >>>> here. Indeed, it’s probably worth proposing type(named:) as a separate >>>> language feature on the path to conditional conformances. >>>> >>>> Looking Forward: Generalized Existentials >>>> Generalized existentials >>>> (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials >>>> >>>> <https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials>) >>>> allows us to express more kinds of “existential” type in the language, >>>> e.g., “A Collection of some type of Element that we know is Equatable”, >>>> e.g., >>>> >>>> var a: Any<Collection where .Element: Equatable> >>>> a = [1, 2, 3, 4, 5] >>>> a = Set([“a”, “b”, “c”]) >>>> >>>> To get there, we can change (or extend) the protocol metadata >>>> (https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-metadata >>>> >>>> <https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst#protocol-metadata>) >>>> to contain a complete generic signature, which can be evaluated >>>> dynamically using the same mechanisms described above. For example: >>>> >>>> func f(any: Any) { >>>> if let c = any as? Any<Collection where .Element: Equatable> { … } >>>> } >>>> >>>> We should make the metadata change to allow this form of generalized >>>> existentials before locking down the ABI, even if we don’t settle on the >>>> feature in the surface language. >>>> >>>> Thoughts? >>> >>> Couldn't we just encode a metadata path for the associated type and then do >>> the conformance lookup? >>> >>> John. >>> _______________________________________________ >>> swift-dev mailing list >>> swift-dev@swift.org <mailto:swift-dev@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-dev >>> <https://lists.swift.org/mailman/listinfo/swift-dev> > > _______________________________________________ > swift-dev mailing list > swift-dev@swift.org > https://lists.swift.org/mailman/listinfo/swift-dev
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev