swift_conformsToProtocol

My embedded Swift code doesn't work with as? for class bound protocols even though those seem to work and the ABI documentation mentions witness tables existing

Is this a bug or intentional?

The support for class bound protocols does not (yet?) include the ability to dynamically check for protocol conformances.

2 Likes

Embedded Swift relies on pre-generated specializations of witness tables to implement class existentials. Suppose you have:

protocol P: AnyObject {}
class G<T>: P, Base {}
class Base {}

Now if after specialization, your SIL happens to only ever store G<Int> and G<String> into an any P, we generate two witness tables for G<Int>: P and G<String>: P.

If you then do something like this:

func f() -> Base {
  return G<Bool>()
}

f() as? any P

A non-Embedded Swift programmer would expect the above to work, because there we just have one unspecialized witness table G<T>: P for all T.

With Embedded Swift though, there is nothing in that program that statically makes us generate a witness table for G<Bool>: P. So even if you had a hypothetical runtime registration mechanism for witness tables and a way to do lookups into it, this cast would fail, which might be surprising.

I guess to fix the immediate problem, we should diagnose dynamic casts as unsupported. It sounds like an oversight in the implementation that this generates a call to a non-existent runtime function even for an embedded target.

6 Likes

I thought this is already the case (that we already diagnose). We certainly do at least on some downcasts, see e.g. https://swift.godbolt.org/z/jbnf1o39b.

@Lua could I ask for a Github issue with a snippet of the code that triggers the problem?

3 Likes

I believe the diagnostics work fine for most protocols but they stopped once I added the AnyObject requirement.

This compiles:

protocol P: AnyObject {}
class A {}
func foo(a: A) -> Bool { a is P }

I assumed that the error going away made sense since classes already store metadata, and that the implemented protocols would just be referenced there

Nice, thanks for the bugreport!

As Slava said, the fix is going to be to produce a clear error message, rather than to make this code actually work. Is that your expectation, too?

1 Like

Yeah I understand that :+1:

I don’t really need this for my code, I just made my base class implement the protocol with some vaguely useful defaults