Narrowing to opaque types #1375
Replies: 1 comment 3 replies
-
This code compiles in Swift and prints protocol P {}
protocol Q: P {}
struct A: Q {}
struct C: P {}
func foo<T: P>(_ x: T) {
if let y = x as? any Q
{
bar(y)
} else {
print("else")
}
}
func bar<T: Q>(_ x: T) {
print("bar")
}
foo(A())
foo(C()) There's an "implicit opening" feature that I always had reservations about (see my many posts here). If you look at the Detailed Design section you can see the rules for when and how you can use this are quite complicated for users. I haven't analyzed your proposal yet beyond this initial example but if it creates a more consistent world for users while supporting the important use-cases for implicitly-opened existentials, I would be strongly in favor. One problem is that I think nobody has actually laid out the use cases for implicit opening. I seem to remember there was a workaround for the lack of implicit opening, too, before it was added. I'll see if I can find that… |
Beta Was this translation helpful? Give feedback.
-
There's one thing we can't do in Swift that's a little annoying. Imagine I have this setup:
It makes sense that an existential type doesn't conform to its bounds but that forces us to opt in type erasure when we want to narrow a type to a refinement. AFAIK, the only way to deal with this situation is to narrow to concrete types, i.e.:
That's not only boilerplate but also high-maintenance in cases where it's likely that new conformances to
Q
might be defined.In the real world, I hit this problem quite often in
hc
because we have many protocols describing categories of declarations, likeGenericDecl
,TypeExtendingDecl
, orExposableDecl
. You can look in the type checker for all thecase ConformanceDecl.self
that are next tocase ExtensionDecl.self
to see examples, but even more generally we can't easily narrow aT: DeclID
to a genericU: ScopeID
without erasure. That is, we need to transform ourT: DeclID
to aAnyScopeID
, which involves a change of representation (AnyScopeID
must store the kind of the node in its payload;U: ScopeID
does not).I think we could get around this issue in Hylo by supporting narrowing casts to opaque types:
Such casts would be zero cost because they don't involve any change of representation, unlike erasure. For code generation we wouldn't be able to use monomorphization but the existentialized form of the function should work fine because anyway it would take an arbitrary pointer along with a witness table, which is exactly the representation I expect for an opaque type.
Beta Was this translation helpful? Give feedback.
All reactions