-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[Patterns] Flow analysis #50419
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
Comments
I'm assuming I'll be doing a lot of this work, so I'm assigning to myself. So far I've written up an implementation plan but no actual code. If anyone would like to collaborate on this, please let me know. |
It turns out the only information stored in `_BranchContext` that was actually used was the part of `_conditionInfo` that tells what the flow model should be if the branch is taken. So we just store that information directly. This should make it easier to implement flow analysis for the new "if-case" construct, which doesn't have a particular expression that's determining whether the branch is taken (and hence won't have an easily derivable `_conditionInfo`). Change-Id: I73ffad36cda4f863335f571542244d58f4bddceb Bug: #50419 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268741 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
I marked this P1 because some priority is part of the analyzer issue triage process and it's related to a language feature. |
This change makes the API for the `ifCase` method the same as that of `if_`, which should make it easier to write flow analysis unit tests for if-case statements. Bug: #50419 Change-Id: Iea7e0fabba9966eae52c0d28b52d2f8fcea25e46 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273820 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This change makes the API for the `ifCaseElement` method similar to that of `ifCase`, which should make it easier to write flow analysis unit tests for if-case elements. Bug: #50419 Change-Id: I64c160f3b6df38b0d337f9b8f9c6c9189e9a13ed Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274161 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This CL adds support for flow analysis with variable patterns and guards, and integrates it with if-case elements, if-case statements, pattern variable declarations, switch expressions, and switch statements. It includes support for guards. No other types of patterns are handled yet. Bug: #50419 Change-Id: Iacad82b472cba0e2e670981847258e4046017576 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274162 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
…ement cases. Bug: #50419 Change-Id: Ie9b0dd3319dd4e28f53082794aa18ed422b0894b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274605 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
When patterns support is disabled, flow analysis considers a switch statement to be exhaustive if it has a `default` clause or if the scrutinee type was an enum and all enum cases were covered (this matches the behaviour of previous releases of Dart). When patterns support is enabled, flow analysis considers a switch statement to be exhaustive if it has a `default` clause or if the scrutinee type is an "exhaustive type" (as defined in the patterns spec). A later stage of analysis will check that such switch statements truly are exhaustive, and issue a compile-time error if they aren't. Note that as part of this change I've modified the analyzer so that it only attempts to track whether all enum cases are covered if patterns support is disabled. I didn't make a corresponding change to the CFE because the CFE stores exhaustiveness information in the kernel output (`SwitchStatement.isExplicitlyExhaustive`) and I didn't want to break that. Bug: #50419 Change-Id: Ib2e51971a1b814c003401b3d54d41f7a9ef9f59a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274720 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
As I'm beginning to work on flow analysis for logical and/or patterns I'm realizing that the shared analysis methods for handling logical-and and logical-or patterns are going to need to have different parameters, so it makes sense to separate them. This makes the code clearer anyhow, since they weren't sharing any functionality. Bug: #50419 Change-Id: I17b0ad53f916f48ee02ccb1c9c23488261a6a1b6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274920 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This will allow me to push additional pattern contexts to represent subpatterns, while still accumulating the "unmatched" flows for the pattern as a whole. Bug: #50419 Change-Id: I8a7b1255abeda1cd07d82828057c81f45954d173 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274941 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This simplifies the shared TypeAnalyzer code by avoiding a lot of null checks. This required modifying a few analyzer code paths that didn't previously initialize FlowAnalysis so that they now do. Change-Id: Ie306d3ac94c4ca00d211e9cd038fb0b001996747 Bug: #50419 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274940 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
…ments. I previously thought that the only possible situation where a switch statement over a valid type could be exhaustive without containing any cases was if the scrutinee type was the empty record type (`()`). But that isn't true at all: - The empty record type is inhabited by empty record objects, so such a switch statement would not be exhaustive after all. - It is possible for the user to create a type that can be exhaustively switched over with zero cases: by creating an abstract sealed class without any subclasses. In the latter case, I think it makes the most sense to treat the code after the switch as unreachable, because that's the normal behaviour of a switch over an exhaustive type with no `break`s. It is sound to do so because the type is uninhabited, therefore the body of the switch statement itself will never be reached. Bug: #50419 Change-Id: Ibc0a21226f25ae155db994343874354d5b8e4f7d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274621 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
A desired feature for flow analysis of patterns is that the matched value type of one subpattern may depend on promotions from previous patterns. For example, we want this to work: int? x = ...; if (x case null || < 0) ...; This means that although the type of the scrutinee is `int?`, after the subpattern `null` has been processed, type promotion should promote the matched value type to `int`, so that the subpattern `< 0` doesn't report an error. This requires changing the API of the shared patterns analysis logic, so that the client is no longer responsible for passing around the matched value type. Instead, flow analysis keeps track of it and provides it to the client when requested. In follow-up CLs I'll add the necessary logic to flow analysis to actually promote the matched value type in situations like the example above. Change-Id: I6ce66962af32f9bd93bfe4082ba256de627d3cc6 Bug: #50419 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274942 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
…t clauses. This enables the front end to skip the old-style (enum-based) exhaustiveness checking algorithm when pattern support is enabled, because with pattern support enabled, switches on enums are required to be exhaustive (this will be checked by the new exhaustiveness checking algorithm). That in turn means that in the future, when we remove support for language versions that lack patterns support, we will be able to remove the old-style exhaustiveness checking algorithm. This change has a small effect on code generated by the WASM back-end (the only back-end that uses `isExplicitlyExhaustive`): for a switch statement that is exhaustive *and* has an unreachable `default` clause, after testing all the cases, the WASM back-end will generate a branch to the `default` case. Previously it would instead generate an `unreachable` instruction. There should be no behavioural difference because the instruction in question is unreachable in both cases. Also, there should be negligible code size difference because the body of the `default` case is being emitted either way. Bug: #50419 Change-Id: Id6bd7d9a540cb1b4d9c3624db8ff494438276bea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274924 Reviewed-by: Aske Simon Christensen <askesc@google.com> Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
Implement the necessary flow analysis bookkeeping so that in a pattern of the form `P1 && P2`, any type checks performed by `P1` will be reflected in the matched value type used by `P2`. To accomplish this, we allocate a promotion key to represent the "cached value" matched by every pattern and subpattern (so that `P1 && P2` promotes properly even when in a subpattern of another pattern). This promotion key is stored (in the form of a `ReferenceWithType<Type>`) in the `_PatternContext` class. Also, move `_scrutineeReference` and `_scrutineeType` into `_FlowAnalysisImpl`; this preserves the existing behaviour of promoting the scrutinee expression, but with less bookkeeping (since we don't need to pass it along from one context to the next). And add `_FlowAnalysisImpl._scrutineeSsaReference` so that if the scrutinee is modified during execution of the switch statement, it won't be erroneously promoted by patterns that follow. Finally, implement some preliminary logic for `||` patterns to avoid breaking existing tests. I will fill this out (and test it thoroughly) in a follow-up CL. Bug: #50419 Change-Id: I0d934e706ad5b19cda46a198afb2fb7a4309829b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275788 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
A switch statement like this one: switch (E) { case P1 when G1: S1; case P2 when G2: S2; case P3 when G3: } Is equivalent to an if/else chain like this: var tmp = E; if (tmp case P1 when G1) { S1; } else if (tmp case P2 when G2) { S2; } else if (tmp case P3 when G3) { S3; } Therefore, if the failure of a particular pattern/guard combination to match implies a type promotion, it makes sense for that promotion to be carried into later cases. For example: int? x = ...; switch (E) { case _ when x == null: break; default: x.isEven; // OK because `x` known to be non-null. } This enabled some more thorough testing of type promotion in switches, which then caught a bug introduced in a previous CL: when the switch scrutinee is a variable reference, and we are trying to determine whether it is safe for a pattern to promote the scrutinee variable, we were checking the wrong SSA node to determine whether the variable had been reassigned. For example: Object x; switch (x) { case _ when f(x = ...); break; case int _: // `x` is not promoted to `int` because it is no longer the // same as the cached scrutinee. break; } Bug: #50419 Change-Id: Ie8d6cf0fc662aa5ef0ac81eb2343952028dd2abb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278533 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Thanks to Konstantin for noticing this issue. Bug: #50419 Change-Id: I0380b846839c5afa1b20a52d55d980ddb6d09fec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278810 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This will help facilitate a follow-up CL in which I plan to modify flow analysis data structures to track the static (unpromoted) type of each variable, rather than querying that information from the client. That in turn will help address some subtle bugs in the flow analysis of patterns wherein an invalid promotion chain is getting created because the wrong variable is being queried. As part of this change, I've cleaned up the logic that calls `FlowAnalysis.declare` for the synthetic variables associated with or-patterns and switch cases that share a body; previously this logic was making redundant calls to `declare`; now it is only calling `declare` once per synthetic variable. Bug: #50419 Change-Id: I8e8e4aa71afe3ac7ecdc474f023ec513dc7286b1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278693 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
In order to handle variable patterns inside logical-or patterns, flow analysis will need to model the implicit temporary variables that represent the variables before they are joined to form the final variable value. This CL adds the necessary logic to model this: - `declaredVariablePattern` is now responsible for initializing the temporary variable (the client no longer needs to call `initialize` when analyzing a variable pattern). It returns an integer representing the implicit temporary variable. - A new API call, `assignMatchedPatternVariable` can be used by the client to transfer the variable from the implicit temporary variable to a user-accessible variable. For now, the shared analysis logic always calls this from `analyzeDeclaredVariablePattern`, after calling `declaredVariablePattern`. However, in the future, it will postpone the call until after these temporary variables are implicitly joined by logical-or patterns. Bug: #50419 Change-Id: I2b78a46c11d0d46c8e0a8691c2a2ce49dceb2a24 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279078 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
Bug: #50419 Change-Id: I7fd845b0e465b63a2a9fd5e17bf254b9073a7d1f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279459 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This method is used for declared variable patterns, list patterns, map patterns, record patterns, object patterns, and wildcard patterns to cause the value being matched to be promoted. As a temporary measure it's also used for cast patterns; this will be fixed in a later CL. Change-Id: Iccc9ce4a53e2a10753847f9ecade091f1b230111 Bug: #50419 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279653 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
There are three ways type promotion can occur in an or-pattern: (1) the scrutinee variable (if any) might be promoted, e.g.: f(Object x) { if (x case int _ && < 0 || int _ && > 10) { // `x` is promoted to `int` because both sides of the `||` // promote the scrutinee variable to `int`. } } (2) the implicit temporary variable that holds the matched value might be promoted, e.g.: f(Object Function() g) { if (g() case (int _ && < 0 || int _ && > 10) && (var x)) { // `x` has type `int` because both sides of the `||` promote // the matched value to `int`. } } For this sort of promotion to work, we need to (3) explicitly matched variables might be promoted at the time of the match, e.g.: f<T>(T t) { if (t is int) { if (t case var x && < 0 || var x && > 10) { // `x` has type `T` but is promoted to `T&int`, because both // declarations of `x` are in a context where the matched // value has type `T&int`. } } } The existing flow analysis logic handles cases (1) and (2) without any extra work, because those promotions are joined as a natural consequence of the flow control join at the end of matching the logical-or pattern. However, flow analysis has to do some extra work for case (3), because the two copies of variable `x` are associated with different variable declarations (and hence have different promotion keys). To ensure that the promotions are joined in this case, we need to copy the flow model for the two copies of `x` into a common promotion key prior to doing the flow control join. The bookkeeping necessary to figure out a common promotion key is similar to the bookkeeping necessary to track the association between the individual declared variable patterns and the joined pattern variable (and this is bookkeeping that flow analysis is already doing). So as part of this change I went ahead and removed the `getJoinedVariableComponents` method (which was previously used by flow analysis to query this association). This reduces the constraints on the analyzer and CFE implementations by not requiring them to do this bookkeeping themselves. In the process I've made two additional small changes: - I modified the logic for assigning types and finality to joined variables so that if there is a finality conflict but no type conflict, the common type is used; conversely, if there is a type conflict but no finality conflict, the common finality is used. This should help reduce follow-on errors. - I added logic to ensure that if a variable is only declared on one side or the other of a logical-or, flow analysis still considers that variable to be definitely assigned. This should help reduce follow-on errors. Change-Id: I62f17adb6a51a583707c216ed48d941d1c621eea Bug: #50419 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279756 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
…a body. There are two ways type promotion can occur when switch cases share a body: (1) the scrutinee variable (if any) might be promoted, e.g.: f(Object x) { switch (x) { case int _ && < 0: case int _ && > 10: // `x` is promoted to `int` because both cases promote the // scrutinee variable to `int`. } } (2) explicitly matched variables might be promoted at the time of the match, e.g.: f<T>(T t) { if (t is int) { switch (t) { case var x && < 0: case var x && > 10: // `x` has type `T` but is promoted to `T&int`, because // both declarations of `x` are in a context where the // matched value has type `T&int`. } } } The existing flow analysis logic handles case (1) without any extra work, because those promotions are joined as a natural consequence of the flow control join at the end of matching the cases. However, flow analysis has to do some extra work for case (2), because the two copies of variable `x` are associated with different variable declarations (and hence have different promotion keys). To ensure that the promotions are joined in this case, we need to copy the flow model for the two copies of `x` into a common promotion key prior to doing the flow control join. The bookkeeping necessary to figure out a common promotion key is similar to the bookkeeping for logical-or patterns. Bug: #50419 Change-Id: I9ee4ec5d797dae28099aafbaf34fbbeeee5cd626 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280201 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
Since matching a constant pattern implicitly performs an equality check, we do the same flow analysis for constant patterns that we would have done for an explicit equality test. There are only two user-visible behaviours: - If the constant pattern is a `null` literal, then in the code path where the pattern fails to match, the scrutinee is promoted to a non-nullable. - If the constant pattern and the scrutinee are both `null` literals, the pattern match is known to always succeed (so the code path where the pattern fails to match is marked as unreachable). The first of these two behaviours is genuine useful to the user, since it allows things like: switch (expr) { case null: ... ... default: // expr is known to be non-`null`. } The second behaviour is not so useful, but seemed worth doing to maximize code sharing and to keep the behaviour consistent between pattern matching and explicit null checks. Making this work required extracting some of the logic that was formerly in `_FlowAnalysisImpl.equalityOperation_end` into a method `_equalityCheck`, which understands how to analyze an equality check regardless of whether it's an explicit equality expression or an implicit part of a pattern. It returns an `_EqualityCheckResult`, which `equalityOperation_end` examines to determine exactly what needs to be done to for an equality test in an expression context; similarly, `_FlowAnalysisImpl.constantPattern_end` now calls `_equalityCheck` and then does the right thing for patterns. It was also necessary to extract the logic from `nullCheckOrAssertPattern_begin` for handling null checks in patterns; that logic is now in `_nullCheckPattern`, which is also called by `constantPattern_end`. In the process of testing this change, I discovered (and fixed) a minor bug: when analyzing a switch statement or switch expression, we were re-capturing the value of the scrutinee before visiting each pattern. This meant, for example, that we would analyze the following code incorrectly: int? i = ...; switch (i) { case _ when f(i = ...): ... case null: ... default: // `i` should *not* be promoted to non-null here, because it's // not guaranteed to be the same as the value matched by `case // null` above. } Bug: #50419 Change-Id: I4d30d6bc2673d9968e69f3384a37e1b2b9cc4a8f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280861 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
There are two new API methods: `equalityRelationalPattern_end` (for relational patterns using `==` or `!=`, where some degree of flow analysis is warranted) and `nonEqualityRelationalPattern_end` (for all other relational patterns, where all we care about is making sure that both the "matched" and "unmatched" branches are reachable). I've moved most of the logic for constant patterns into `equalityRelationalPattern_end`, since it's essentially the same logic (except that `equalityRelationalPattern_end` also has support for `!=`). So now, `constantPattern_end` simply calls `equalityRelationalPattern_end` in the case where pattern support is enabled. I also had to make a change to `RelationalOperatorResolution` to make it possible to distinguish `==` from `!=`. Bug: #50419 Change-Id: Idc5dbcfb02e3f8b57cfcccb3f46364fe34268ded Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280900 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
If a cast pattern fails to match, it throws an exception, so the "match failure" code path should be unreachable. To fix this, I added an optional argument `updateUnmatched` to `patternRequiredType` to allow the type analyzer to tell flow analysis whether a required type is enforced via a match failure or an exception. I also renamed `patternRequiredType` to `promoteForPattern`; this is in anticipation of an upcoming CL which will use this method to promote to a type which isn't necessarily the same as the required type. I also discovered a few testing gaps while double-checking that every call to `promoteForPattern` makes the proper choice about what to pass for `updateMatched`; I've added test cases to cover these gaps. Bug: #50419 Change-Id: Id6f63138d01b481e7c9442469ce45e2aaa507a5a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/281740 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
These fields are no longer being used. Bug: #50419 Change-Id: I6305785d32c5ca2ff55aee297a5977dbd6ea4189 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282300 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
Previously, we stored an EqualityInfo object representing the scrutinee at the time of entry to the top level of the pattern; then when handling, for example, a relational pattern using `==`, we used that EqualityInfo object to decide how to handle the equality check, *even if we were no longer at the top level of the pattern*. As a result, we would sometimes come to incorrect conclusions about relational patterns inside subpatterns. For example, we would fail to see that `if ((null,) case (== null,))` is a guaranteed match, because when processing the `== null` pattern, we would erroneously use the EqualityInfo for `(null,)` (which is *not* `null`). To solve this, we only store the scrutinee *reference* at the top level of the pattern (this is sufficient to allow us to decide whether or not to promote the scrutinee). When we encounter a pattern like `== null`, we compute the appropriate EqualityInfo directly based on the ExpressionInfo, type, and reference that are appropriate to the current pattern level. Bug: #50419 Change-Id: I4d1bc34fcb2d238e7b69e1b88df50b389410963c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282162 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
Bug: #50419 Change-Id: If38ad38cefbdca97144dd853c05aeca3ddb61cf2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282320 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
Most pattern variable assignments don't need to promote, because pattern variable assignments must be irrefutable, and thus the pattern match cannot fail. There's one exception, though: when the assigned value has type `dynamic`, an implicit downcast is performed. Bug: #50419 Change-Id: Ic8f572303d60c354e9e342f79af03e669fa248c3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282381 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
Previously, we kept track of the promotion information for a matched value using a `ReferenceWithType` stored in the `_PatternContext`. This information did not get updated in the event of a promotion, so that meant that if a pattern tried to promote the same value twice (e.g. `int _ && num _`), the second promotion attempt would not see the effects of the first attempt, so it might wind up demoting the matched value. The solution is to just track the promotion key in `_PatternContext`, and resynthesize the `ReferenceWithType` object (with the proper type) whenever we need it. Bug: #50419 Change-Id: I026a4d2f42875a003ce8840dfc88d65484bb33ae Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282800 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
For each subpattern of a record pattern, we define its "demonstrated type" to be the type that the matched value has been promoted to if the subpattern match succeeds. At the conclusion of visiting a record pattern, we promote the whole record pattern's matched value to a record type formed by combining together the demonstrated types of the subpatterns. So, for example, the pattern `(int _, String _)` promotes the matched value to `(int, String)`. This change contains a lot of specific tests, to make sure the demonstrated type of each kind of pattern behaves as expected; but the actual machinery is general, since it just takes advantage of the type promotion performed by the subpatterns. Bug: #50419 Change-Id: Ie4da81964b5ade657c23a598ee18982b793fb4ac Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282806 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
@stereotype441 are we still working toward completion of flow analysis? What is left to close this issue out? |
This field is no longer used; the SSA node for the scrutinee is now looked up using the scrutinee's promotion key. Bug: #50419 Change-Id: I67768fa1311cecf62508844d3074758fbf55b426 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287941 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
As discussed in dart-lang/language#2857 (comment), we only want a pattern match to promote the scrutinee in refutable contexts (if-case and switch). Bug: dart-lang/language#2857, #50419 Change-Id: I187ef632e5da95b931e5cda34db06491a5228c98 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/288000 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
@stereotype441 - is there still open work here? Or can we close? |
It's feature complete as far as I know. But I'm still planning on writing language tests (probably later this week or early next week) to help verify that there are no issues. |
Thanks, I'll drop the pri and bump to the stable milestone. |
These tests are based on the unit tests I wrote during development of the flow analysis support for patterns; as such, they are not especially uniform in their coverage, but they should be a good start. I intend to expand coverage in future CLs. Bug: #50419 Change-Id: I23bd96621a0269c1e642a7fa3b65c851357505c3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304320 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com>
Tracking issue for the implementation of flow analysis for patterns.
This includes implementing the flow analysis engine for patterns and adding calls to the engine from the shared logic in
pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
. I'm assuming that the analyzer and CFE will use that shared logic for all their patterns analysis, so there shouldn't be any need to add calls from the analyzer and CFE directly to flow analysis for pattern support.The text was updated successfully, but these errors were encountered: