-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New Syntax for Capture Variables and Explicit Capture Polymorphism v3 #23063
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
base: main
Are you sure you want to change the base?
Conversation
9e1754b
to
ff07e02
Compare
@odersky making these behave analogously to higher-kinded type parameters makes me wonder if
|
If the lower bound of a capture variable is temprarily |
It's not impossible to add the lower bound (& upper bound) during parsing. But if the mental model is "this is another kind", then the proposed scheme will be irregular for someone who is familiar with the syntax- and subtyping-rules for higher-kinded types in Scala. |
I don't think we should make a capture variable a real "kind"... |
* Refrain from using a flag and in favor of an attachment. * Rule out context bounds entirely for capture vars.
@noti0na1 |
We cannot post-process the typedef in typedTypeDef in the typer, because adaptation of the rhs prematurely sets the symbol info to the old bounds pre-expansion, which will be caught by checkBounds in posttyper. It is easier to mark the rhs as well and do the expansion in typedTypeBoundsTree.
@odersky We cannot post-process in typedTypeDef in the typer, because adaptation of the unprocessed rhs prematurely sets the |
if mods.isOneOf(Covariant | Contravariant) then | ||
syntaxError(em"capture parameters cannot have `+/-` variance annotations") // TODO we might want to allow those |
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 don't see any reason to disallow it.
I don't like there are so many special handling for capture sets when parsing a type dound/def. Can we simplily parse a capture set as a "Type"? ParserWhen we parse
If a type def has a hat, we add some attachment and use for latter. We don't care the rhs when parsing. TyperWhen completing a symbol for a type def:
type C1^ // => capture type C1 >: CapSet <: CapSet^
type C2^ <: {a} // => capture type C2 >: CapSet <: CapSet^{a}
type C3 <: {a} // => regular type C3 >: Nothing <: CapSet^{a}
type C4 >: {} <: {a} // => capture type C4 >: CapSet <: CapSet^{a}
type C5 = {a} // => capture type C5 >: CapSet^{a} <: CapSet^{a}
type C6^ >: {} <: {a} // => capture type, but redundant hat
type C7^ = {a} // => capture type, but redundant hat
type C8 >: C1 <: C2 // => capture type C8 >: C1<: C2
def f[C^] = ???
f[{a}]
type S = {a}
f[{S}] // ok
f[S] // ok, just looks like a substitution |
Right now, it's tailored to exactly the usage contexts where we expect to be able to write literal capture sets. Making this a new case for general types would also permit expressions like |
I'd say a Since we don't have any value for |
type C3 <: {a} // => regular type C3 >: Nothing <: CapSet^{a} Well, hence my comment on making it truly like a new kind. If we upper-bound f[{a}]
type S = {a}
f[{S}] // ok
f[S] // ok, just looks like a substitution I'm pretty sure these all work right now. No? |
Well, if we really want to relax the rule for My example just want to show allowing a set should be equal to allowing a capture variable in bound. |
After discussing with @odersky, we are not going to deviate from the current scheme and will permit the sets only in those specific circumstances. While the general approach and code structure will remain as is, I appreciate feedback on specific details and possible simplifications—just not the broader simplification that was proposed, which we feel is too general for this case. |
OK, I will add another point to my proposal: if we want to support capture set intersection in the future, for example |
Closes #22490
Builds on #22725
Supersedes #22902
This syntax for capture variables and members caters to the view that "they are another kind", and most conventions we know from higher-kinded type parameters carry over.
A postfix
^
(analogous to[_]
) indicates that a type parameter/member ranges over capture setsThese variables can be bounded by capture-set literals:
Just as with higher-kinded type parameters, the kind is "contagious", and we can often avoid the hat if the bounds are concrete capture sets or other capture variables:
Capture variables will be erased if capture checking is turned off. In non-capture-checked code, they are essentially type variables within the interval
>: caps.CapSet <: caps.CapSet
. With capture checking turned on and without explicit bounds, the interval corresponds to>: caps.CapSet^{} <: caps.CapSet^{caps.cap}
.Tasks