-
Notifications
You must be signed in to change notification settings - Fork 211
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
Can we promote through record fields? #2503
Comments
This seems reasonable to me. We already have the technology to track types of interest and promotions for private class fields (soon to be enabled as part of #2020); extending this to record fields seems like a no-brainer.
Personally wouldn't have any problem with this. It doesn't create any soundness problems, and it's really consistent with my mental model of records (which is that they're just extremely lightweight agglomerations of values that otherwise would have been stored in separate variables).
I don't have time to prototype it right now, but my intuition is that this would actually be a fairly straightforward extension of what flow analysis is already capable of doing. I'll add it to my list to explore in the coming weeks. |
I think allowing It's a little weird to allow that, and not, say |
Porting over another motivating example from #3160 that came up in some real-world code: void function(int? arg1, int? arg2) {
switch ((arg1, arg2)) {
case (null, null): print("both null");
case (var first, null): print(first.abs());
case (null, var second): print(second.abs());
}
} Specifically, promoting through record fields makes it much nicer to construct a tuple to match against. |
You can force promotion if null is checked in the pattern. void function(int? arg1, int? arg2) {
switch ((arg1, arg2)) {
case (null, null): print("both null");
case (var first?, null): print(first.abs());
case (null, var second?): print(second.abs());
}
} |
Consider the following example:
The rule would be that we can specify an arbitrary record structure (here
\X, Y. (X?, Y)
) and perform pointwise operations on it (transforming\X, Y. (X?, Y)
to\X, Y. (X, Y)
), and declaring that the latter is a 'type of interest' because it is a structurally lifted version of the standard rule that makesT
a type of interest during initialization of a local variable with declared typeT?
. This allows us to promote from(int?, bool)
to(int, bool)
, from(int?, (bool?, List<String>?))
to(int, (bool, List<String>?))
, etc.A similar phenomenon arises with intersection types, where we are immediately promoting a type which is a type variable
X
to an intersection typeX & T
, because it was initialized by an expression of typeX & T
.Are we going to apply similar promotions based on "lifted" types of interest?
We could proceed as usual (in some lifted sense) and erase the type of the record literal from
(X & int, bool)
to(X, bool)
. However, it is actually sound to maintain that the record has the type(X & int, bool)
, because the run-time type of the record is computed from the run-time types of the field values, and the actual object denoted byx
at this point is known to have a typeS
such thatS <: int
andS <: X
.But it's a potentially deep violation of the current rules that we even consider a type like
(X & int, bool)
, because an intersection type does not otherwise occur as a subterm of any other type.In any case, lifting initializer based promotions to record types seems to be a non-trivial exercise.
@natebosch, @lrhn, @munificent, @leafpetersen, @jakemac53, @kallentu, @stereotype441, WDYT?
The text was updated successfully, but these errors were encountered: