-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[WIP] Opaque result types prototype #21137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
80fed14
to
d756010
Compare
32c9c86
to
58329d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solver changes look reasonable to me, @jckarter!
@@ -1115,6 +1115,11 @@ ConstraintSystem::solveImpl(Expr *&expr, | |||
// constraint. | |||
if (convertType) { | |||
auto constraintKind = ConstraintKind::Conversion; | |||
|
|||
if (getContextualTypePurpose() == CTP_ReturnStmt | |||
&& Options.contains(ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder - do we really need a new flag or we could detect this situation based on convertType
itself, because it always would be OpaqueTypeArchetypeType
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we normally want to treat the opaque type and underlying type as distinct outside of return statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, what I meant was:
if (getContextualTypePurpose() == CTP_ReturnStmt &&
covertType->isa<OpaqueTypeArchetypeType>())
constraintKind = ConstraintKind::OpaqueUnderlyingType;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs for ContextualTypePurpose suggested that it was only intended as a discriminator for diagnostics, so I wasn't sure whether it was OK to key other constraint system behavior solely on it. I can do what you suggested if you think it's better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was intended like that originally but it would be totally okay to use it for this case as well to avoid adding new flags.
} | ||
} | ||
|
||
addConstraint(ConstraintKind::Equal, type1, underlyingTyVar, locator); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my better understanding, could you please elaborate if this constraint has to be equality, or it could be conversion instead? It seems like in the non-opaque case solver creates a conversion constraint from contextual result to what we infer for return
, but in this case I think equality makes more sense because base is going to be a type variable with a set of requirements, is that correct? If so, I wonder if we should just bind these types instead of to pull requirements to the left type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the result of opening the opaque archetype should be a type variable with constraints the value of the return statement would need to satisfy. Are there cases where a Conversion
constraint between type variables might still allow a more general set of types to be bound? Bind
seems too specific since we still want to allow lvalues in the return statement to be loaded too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there cases where a Conversion constraint between type variables might still allow a more general set of types to be bound?
I can only think of implicit conversions being a difference between equals and conversion in that regard.
Bind seems too specific since we still want to allow lvalues in the return statement to be loaded too.
Actually if you look at the matchTypes
- both equal and bind share the same path and most likely going to bind types or merge equivalence classes of the type variables if either is a type variable.
5324671
to
aca8292
Compare
38e0034
to
65d32b3
Compare
174ae36
to
2d90612
Compare
@swift-ci Please Build Toolchain macOS Platform |
2d90612
to
e1c4979
Compare
@swift-ci Please build toolchain macOS platform |
1 similar comment
@swift-ci Please build toolchain macOS platform |
macOS Toolchain Install command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my review is not very substantiative. But at least I read through most of the code.
You have a binary file 'bar' that got added by mistake |
ae4e289
to
260398d
Compare
@swift-ci Please build toolchain macOS platform |
1 similar comment
@swift-ci Please build toolchain macOS platform |
macOS Toolchain Install command |
@swift-ci Please build toolchain |
To represent the abstracted interface of an opaque type, we need a generic signature that refines the outer context generic signature with an additional generic parameter representing the underlying type and its exposed constraints. Opaque types also need to be keyed by their originating decl, so that we can treat values of the same opaque type as the same. When we check a FuncDecl with an opaque type specified as its return type, create an OpaqueTypeDecl and associate it with the originating decl. (A representation for *types* derived from the opaque decl will come next.)
b4b725b
to
8e2b83f
Compare
It's currently meaningless, and it'll require thought to pass the correct value when it becomes meaningful.
…lt types. This prevents opaque result types from propagating nontrivially into other declarations' types, which may be confusing and create implementation complexities.
8e2b83f
to
b63ccda
Compare
@swift-ci Please build toolchain macOS platform |
macOS Toolchain Install command |
The real implementation |
WIP towards a prototype of an MVP subset of https://forums.swift.org/t/opaque-result-types/15645 . For an initial implementation, this won't include the resilience, second-order
where
constraint, or multiple conditional conformance features proposed in the thread.Limitations include:
__opaque Protocol
or__opaque ProtocolA & ProtocolB [& ProtocolC...]
as placeholder spelling.func
declarations, not properties or closures.where
clause constraints on the opaque type are not yet supported, nor are conditional conformances on the opaque type. However, the protocols in the__opaque
type can be arbitrary protocols, with any number of associated type or Self type requirements.__opaque
types can in turn be inferred as associated types of protocol conformances.Some known issues: