Commit Graph

585 Commits

Author SHA1 Message Date
Johnni Winther 17f4344336 [cfe,analyzer] Handle extension types in exhaustiveness checking
This adds support for extension types in exhaustiveness checking by
performing extension type erasure on the type before computing the
corresponding static type/space.

Change-Id: Ie75c903aec52a7c34410695787a9bea6008d637d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340442
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
2023-12-11 11:10:07 +00:00
Paul Berry 004f564f40 Allow "field promotion" to apply to abstract getters.
A quirk of analyzer and CFE implementations is that they resolve
property gets such as `foo.bar` to specific field or getter
declarations that may be not be directly defined on the target type;
for example if `foo` has type `B`, and `B` extends `A`, and `A`
contains a field called `bar`, then `foo.bar` is considered to refer
to `A.bar`, for example:

    class A {
      int? bar;
    }
    class B extends A {}
    f(B foo) {
      print(foo.bar); // Resolved to `A.bar`.
    }

This is in contrast with the language specification, which makes a
clean distinction between class _declarations_ and the _interfaces_
implied by those declarations. While a class declaration can contain
(among other things) both getters and fields, which might be concrete
or abstract, an interface doesn't distinguish between getters and
fields, and is inherently abstract.

The advantage of the analyzer/CFE approach is that it allows more
intuitive error messages and "go to definition" behavior, which
benefits users. But it has some ill-defined corner cases involving
complex class hierarchies, because not every property access can be
resolved to a unique declaration (sometimes a getter is multiply
inherited from multiple interfaces, for example). The language spec
approach has the advantage of being well-defined and consistent even
in situations involving complex class hierarchies.

When I initially implemented field promotion, I took advantage of this
quirk of the analyzer and CFE implementations, so that I could make
property gets that refer to field declarations promotable, while
keeping property gets that refer to abstract getter declarations
non-promotable. This caused unpredictable behaviors in the ill-defined
corner cases. It also meant that in certain rare cases, a property
access might not be promoted even when it would be sound to do so
(e.g. a property access might refer to a private abstract getter
declaration, but the only concrete _implementation_ of that abstract
getter was a final field).

This CL changes the rule for promotability so that any get of a
private property is considered promotable, provided that the
containing library doesn't contain any concrete getters, non-final
fields, or external fields with the same name. It no longer matters
whether the private property refers to a field or a getter. This rule
is simpler than the old rule, restores the spec's clean distinction
between class declarations and interfaces, and allows more promotions
without sacrificing soundness.

For additional details please see the breaking change announcement at
https://github.com/dart-lang/sdk/issues/54056, as well as the original
change proposal at https://github.com/dart-lang/language/issues/3328.

Fixes https://github.com/dart-lang/sdk/issues/54056.
Fixes https://github.com/dart-lang/language/issues/3328.

Change-Id: I38ffcb9ecce8bccb93b1b2586a1222a0fb1005a7
Bug: https://github.com/dart-lang/sdk/issues/54056
Bug: https://github.com/dart-lang/language/issues/3328
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/337609
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2023-12-07 23:40:27 +00:00
David Morgan eff8c0d946 [macros] Finish and fix ExtensionTypeDeclaration.
Add corresponding `DeclarationKind`, rename `onType` to
`representationType`.

R=jakemac@google.com, scheglov@google.com

Change-Id: I0ce697de6c0b03d4a69a0f55379a0c9d9850233b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340400
Reviewed-by: Jake Macdonald <jakemac@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Auto-Submit: Morgan :) <davidmorgan@google.com>
2023-12-07 15:37:39 +00:00
David Morgan 296a7f642e [macros] Remove Introspectable* types.
Per https://github.com/dart-lang/language/issues/3442 inrospection will
be allowed to succeed if possible, failing if there are cycles.

Change-Id: I341cc4ae87d1399df82cebb1d5c9df7e5070e777
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339620
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Morgan :) <davidmorgan@google.com>
2023-12-07 09:44:59 +00:00
Konstantin Shcheglov 5650e743d5 Macro. Fix executor_test after the previous CL.
https://dart-review.googlesource.com/c/sdk/+/339722

Change-Id: I0d26aa33cbe5ee3454e49700fc3fc51fecd5ebd1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340061
Reviewed-by: Jake Macdonald <jakemac@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
2023-12-05 21:19:09 +00:00
Jake Macdonald 613fa1f5aa fix executor_test.dart for hasAbstract changes
Bug: https://github.com/dart-lang/sdk/issues/54130
Change-Id: If3554796de99ed0e8b8ea37ae159e89bcc5cbcf6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/337860
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
2023-11-22 18:52:20 +00:00
Jake Macdonald e6ebb9340f remove unmeaningful constructor parameters from ConstructorDeclarationImpl
Change-Id: I1bb5712349198d3a1658c405a164aa38d447c752
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/337660
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Morgan :) <davidmorgan@google.com>
2023-11-22 17:37:22 +00:00
Jake Macdonald a1b8fa4613 move hasAbstract from FunctionDeclaration to FieldDeclaration
Bug: https://github.com/dart-lang/language/issues/3454
Change-Id: Ic157dcd1e2c82c8cc08cd225065fd2810a8b02f2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335240
Reviewed-by: Morgan :) <davidmorgan@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
2023-11-21 23:18:10 +00:00
David Morgan 8d62c1962c Add extension type macro and declaration interfaces and implementation.
Add test coverage: `SimpleMacro`, `executor_test`, `serialization_test`.

R=jakemac@google.com

Bug: https://github.com/dart-lang/language/issues/3224
Change-Id: I17a814b18231db60a33b41099c93c0978cebae1b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/337543
Reviewed-by: Jake Macdonald <jakemac@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Morgan :) <davidmorgan@google.com>
2023-11-21 16:55:34 +00:00
Konstantin Shcheglov 5dbb5960ef Extension type. Issue 53918. Fix type literal constant type.
Bug: https://github.com/dart-lang/sdk/issues/53918
Change-Id: I941332f30bdc681dd10c8471e1710f2e9dde4c68
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336501
Reviewed-by: Kallen Tu <kallentu@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
2023-11-15 21:10:48 +00:00
David Morgan 307a46f991 Add arguments to ConstructorMetadataAnnotation.
Support serializing them. Add helper methods to serialize lists of `Code` and `Map<String, Code`.

R=jakemac@google.com

Bug: https://github.com/dart-lang/language/issues/3443
Change-Id: If03b4ad5bf761b089f800834fc103b26143a0ddc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335446
Commit-Queue: Jake Macdonald <jakemac@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Auto-Submit: Morgan :) <davidmorgan@google.com>
2023-11-13 17:12:00 +00:00
Johnni Winther 12c4e22a4d [cfe] Handle various cases ExtensionType
Handles ExtensionType in inference of MapLiteral, inference of
ObjectPattern, and exhaustiveness.

TEST=tests/extension_type/*

Change-Id: I3284da2c69d875e192cf3f004ee1156e1aedd98b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333160
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
2023-11-02 10:42:48 +00:00
Johnni Winther 72f1591f29 [cfe] Use getTypeAsInstanceOf instead of getInterfaceTypeAsInstanceOfClass
The changes calls to getInterfaceTypeAsInstanceOfClass (et al.) to
getTypeAsInstanceOf to ensure that we take extension types into account.

Change-Id: I7d732cdae8494002b44561cb02c49d58dd0ba67b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332920
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
2023-10-31 22:30:50 +00:00
Paul Berry e7c88f127d Flow analysis: fix capitalization convention.
Both letters of `OK` should be capitalized, in accordance with
https://dart.dev/effective-dart/style#do-capitalize-acronyms-and-abbreviations-longer-than-two-letters-like-words.

Change-Id: I920436d373d1a597244e5592e568a19d0f22fa86
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332065
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-10-27 17:52:39 +00:00
Paul Berry d42390d7c1 Clean up enable/disable logic for flow analysis and type inference tests.
Previously, the logic for enabling and disabling language features in
flow analysis and type inference tests relied on setters in the
`Harness` class that (a) were mostly unmatched with getters, and (b)
were almost exclusively used in just a single one direction
(e.g. `Harness.legacy` defaulted to `true`, so it was only ever set to
`false`).

Cleaned up so that there are explicit `enable` and `disable` methods
in the `Harness` class to cover all the use cases.

Change-Id: I5ccc8585f803fec634cad1472395ea0d135c87c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332064
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
2023-10-27 17:51:44 +00:00
Paul Berry c23ac067eb Improve the behavior of "why not promoted" when field promotion disabled.
If the user attempts to promote a property, and their language version
does not permit field promotion, the "why not promoted" logic now
checks whether the language version is the sole reason for the failure
in property promotion. In other words, it checks whether the property
would have been promotable *if* field promotion had been enabled. If
it would, then the context message displayed to the user explains that
the property did not promote because field promotion is not supported
by the current language version.

However, if there is some secondary reason why the property failed to
promote (in other words, if the property would not have been
promotable even if field promotion had been enabled), then the context
message now favors the secondary reason.

Rationale: imagine a user is maintaining a package that doesn't yet
support SDK version 3.2, and that package contains some property
that's non-promotable both because the language version is prior to
3.2 *and* for some other reason (e.g., because the property isn't a
private field). It would be quite frustrating if the user saw a
context message suggesting that the property would be promotable in
SDK 3.2, and then went to a lot of effort to bump their minimum SDK
version, only to discover *after* the bump that the property is still
not promotable.

In the process of making this change, I discovered that the CFE
doesn't support field promotion in patch files. This is because patch
files aren't listed in `SourceLoader.sourceLibraryBuilders`, so the
logic in the `FieldPromotability` is never invoked for those
files. Since patch files are an artifact of SDK development, and will
never be used by end users, it doesn't seem worth going to extra
effort to add this support. However, I've taken care to make sure that
the "why not promoted" logic recovers gracefully in patch files (by
simply not generating a context message).

Change-Id: I6c0d1c0f4b8a7690f6f775408cb5e857b2dd7b03
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330241
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
2023-10-25 19:41:26 +00:00
Paul Berry bb524468ef Wire up "why not promoted" messages for failed field promotion due to conflict.
Previously, when field promotion failed due to a conflict with another
declaration in the same library, the client (analyzer or front_end)
was responsible for returning a value of
`PropertyNonPromotabilityReason.isInterferedWith` from
`Operations.whyIsPropertyNotPromotable`. Flow analysis would propagate
this value into a `PropertyNotPromoted` object whose
`documentationLink` getter returned `null`. The client was then
responsible for tracking down all the conflicting fields and getters
and creating the appropriate context messages for them (but this
functionality wasn't implemented yet).

With this change, the `PropertyNotPromoted` is now abstract, with two
subclasses to represent the two cases the client has to handle:

- `PropertyNotPromotedForInherentReason` to cover the case where a
  property cannot be promoted due to the fact that it is inherently
  not promotable (i.e. it's not final, it's public, it's external,
  it's not a field, or it's in a library where field promotion isn't
  enabled). In this case the client simply has to generate the
  appropriate context message and attach it to the site where the
  property is declared, and it can rely on having access to a non-null
  `documentationLink` to include in the context message.

- `PropertyNotPromotedDueToConflict` to cover the case where the
  property cannot be promoted due to a conflict with some other
  property in the same library. In this case the client has to
  generate multiple context messages, one for each conflicting
  declaration, and it has to associate each one with the appropriate
  documentation link from the `NonPromotionDocumentationLink` enum.

The `NonPromotionReasonVisitor` base class has been updated to reflect
this split, so that the logic for handling these two cases is in
separate methods in the client.

The front_end logic for handling non-promotion due to conflict is now
fully implemented. The analyzer logic will be addressed in a follow-up
CL, since it's more complex (it requires plumbing additional data
through the summary file format).

Finally, the nomenclature in the `FieldNameNonPromotabilityInfo` is
adjusted to match the new context messages.

Change-Id: Ieed70d1a3572abbc726ae34584d85c7a8aee0732
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327712
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-09-28 03:37:01 +00:00
Paul Berry 8529e31a0f Flow analysis: track detailed non-promotability reasons for getters.
- When the shared logic in `field_promotability.dart` decides that a
  given field should be non-promotable based on attributes of the
  field itself (i.e. because it's public, non-final, or external), it
  returns information to the caller about the reason for
  non-promotability.

- This information is recorded by the analyzer and CFE, and delivered
  back to flow analysis in response to a new callback method,
  `whyIsPropertyNotPromotable`. Flow analysis records this information
  in the `PropertyNotPromoted`, which is delivered to clients when a
  compile-time error occurs due to a property access not being
  promotable. This ensures that the appropriate
  `http://dart.dev/go/non-promo-...` link will be associated with the
  context message. In a future CL, the context messages themselves
  will be updated to match the link.

- The shared logic in `field_promotability.dart` also collects, for
  each field name that isn't promotable, all the reasons why that
  particular field name is non-promotable, in a new data structure,
  `FieldNameNonPromotabilityInfo`. In a future CL, this data structure
  will be used to explain to the caller situations in which a field is
  non-promotable due to interference from other fields or getters with
  the same name.

Change-Id: I89ad102a4bec071bf59374971a8d83b061d4ec1d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327901
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-09-27 20:04:01 +00:00
Paul Berry 2887fe0b2c Flow analysis: rework of promotionInfo data structure.
This change updates `FlowModel.promotionInfo`, the primary data
structure used by flow analysis to track program state, so that
instead of being a `Map<int, PromotionModel<Type>>`, it is represented
by a new data structure called a `FlowLink`, an immutable data
structure describing program state in a way that's particularly
optimized for flow analysis's usage patterns.

Like a map, a `FlowLink` data structure represents a collection of
key/value pairs (where the keys are integers), however instead of
storing the keys and values in a hashtable, each `FlowLink` object
contains a single key/value pair and a pointer to a previous
`FlowLink` object. The value associated with a given key can be looked
up by starting with the current `FlowLink` and walking backwards
through the linked list of `previous` pointers until a matching key is
found. (An empty map is represented by `null`). This makes it an
`O(1)` operation to update the promotion state associated with a
single promotion key (an operation that flow analysis performs
frequently), since all that is required is a single allocation.

If the `previous` pointers are regarded as parent pointers, all the
`FlowLink` objects produced by a given run of flow analysis form a
tree that mirrors the dominator tree of the code being analyzed.

To optimize reads of `FlowLink` data structures, there is a
`FlowLinkReader` class that keeps track of a lookup table reflecting
the implicit map represented by a given `FlowLink` object; this table
can be updated to reflect a different `FlowLink` object in `O(n)`
time, where `n` is the number of edges between the two `FlowLink`
objects in the tree. Since flow analysis is based on a depth-first
traversal of the syntax tree of the code being analyzed, it has a high
degree of tree locality in the `FlowLink` objects it needs to be able
to read, so these `O(n)` updates do not consume much CPU.

The `FlowLinkReader` class is also able to compute a difference
between the program states represented by two `FlowLink` objects, in
`O(n)` time, where `n` is the number of edges between the two
`FlowLink` objects in the tree. This is used by flow analysis to
compute the program state after a control flow join, so that it does
not need to spend any time examining promotion keys that are unchanged
since the corresponding control flow split.

For more information about the `FlowLink` data structure and how it
works, see the comments in `flow_link.dart`.

This change improves the performance of CFE compilation fairly
substantially:

    instructions:u: -0.8167% +/- 0.0007% (-158214865.67 +/- 130252.25)
    branches:u: -0.4694% +/- 0.0009% (-18575169.00 +/- 37220.97)
    branch-misses:u: -1.0009% +/- 0.7189% (-575742.67 +/- 413521.70)
Change-Id: Ia87458ee599977e6efdc9f0e7aa283a41f84f616
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326900
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Morgan :) <davidmorgan@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-09-25 15:41:20 +00:00
Paul Berry f5208f5d59 Flow analysis: prepare for rework of promotionInfo data structure.
`FlowModel.promotionInfo` is currently a map from integer promotion
keys to PromotionModel data structures. This is inefficient because
FlowModel is an immutable data structure, so whenever the promotion
state of a variable changes, the map must be duplicated. In a
follow-up CL I will be changing `FlowModel.promotionInfo` to a much
more efficient data structure. However, that data structure will
require some extra plumbing. For ease in code review, I'm doing the
extra plumbing first, as its own CL.

This CL makes the following changes:

- Removes unnecessary null checks from the `FlowModel.withInfo`
  constructor. These null checks are no longer needed because all the
  clients of flow analysis are now fully null safe. This change is not
  strictly necessary; it's just a long-overdue clean-up.

- Adds a `helper` argument (of type `FlowAnalysisHelper`) to
  `FlowModel.conservativeJoin`, `FlowModel.declare`, and
  `FlowModel.infoFor`, `FlowModel.inheritTested`, and
  `FlowModel._updatePromotionInfo`. This is needed because these
  methods will need access to `FlowAnalysisHelper` in order to read
  and update the new data structure.

- Removes the `typeOperations` argument of `FlowModel.inheritTested`,
  since it can be easily obtained from the new `helper` argument.

- Changes `FlowModel._updatePromotionInfo` to a public method
  annotated with `@visibleForTesting`. This will be needed by flow
  analysis unit tests to create the new data structure.

Note that this change causes a small regression in the performance of
CFE compilation, due to the extra `helper` arguments:

    instructions:u: 0.0693% +/- 0.0008% (13413234.33 +/- 155671.09)
    branches:u: 0.0886% +/- 0.0012% (3502620.67 +/- 45724.97)

The follow-up CL that switches to a more efficient data structure will
result in a performance improvement roughly an order of magnitude
larger.

Change-Id: I21c13fb817f05281b558f0473119473a26ea0fb8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326860
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2023-09-20 12:29:50 +00:00
Paul Berry ef74475404 Create an enum to represent links used in "why not promoted" context messages.
This makes it easier to see at a glance which messages need to be
supported by the website.

I've included the new links that I intend to support as part of the
new "field promotion" feature.

Bug: https://github.com/dart-lang/sdk/issues/53102
Change-Id: I67ad47c5a00db9807a6c726677a06427cdbe02c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325803
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
2023-09-18 18:44:32 +00:00
Jake Macdonald 0ffd54738a add declarationKind for extensions and libraries, support augmenting extensions and add test
Change-Id: I510976cac641800e664e92e7db786962d539ec9c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/325021
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
2023-09-11 15:56:23 +00:00
Paul Berry d28631f1e2 Fix field promotion of external fields.
External final fields are equivalent to getters whose implementation
is provided outside of Dart code. As such they're not guaranteed to be
stable, so they shouldn't be promotable.

It turns out that the CFE was already correctly classifying them as
non-promotable (because it de-sugars them into getters prior to
computing promotability). This CL fixes the analyzer.

Fixes https://github.com/dart-lang/sdk/issues/53426.

Bug: https://github.com/dart-lang/sdk/issues/53426
Change-Id: Icdd897cdbdf0da0a69ea704a245c0b428070b95e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324340
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
2023-09-06 12:23:17 +00:00
Jake Macdonald abc7a21679 add Builder.report method and Diagnostic class to support macros sending diagnostics
Will follow up with tests once we agree on the API. At the same time I will handle translating any normal runtime errors into error diagnostics.

Bug: https://github.com/dart-lang/language/issues/3234
Change-Id: I2fc22af088f0e50b1877022aa793337850257804
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317221
Commit-Queue: Jake Macdonald <jakemac@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
2023-08-30 17:43:42 +00:00
Paul Berry 602e38eab4 Flow analysis: fix integration of field promotion with object patterns.
When entering visiting a subpattern of an object pattern, the flow
analysis engine now updates `_FlowAnalysisImpl._scrutineeReference` to
a `_PropertyReference` referring to the property being matched; this
ensures that if the subpattern match implies a type promotion, and the
property in question is promotable, the type promotion will be applied
to the property.

Also, if the property has already been promoted at the time of entry
to the subpattern, the promoted property type is used as the matched
value type.

Includes unit tests and language tests for the new functionality.

Fixes #53100.

Change-Id: I6d28e9a7d188bf1136e8517d6aa06af3b4c31c69
Bug: https://github.com/dart-lang/sdk/issues/53100
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323001
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-29 16:05:49 +00:00
Paul Berry aef81ef08e Flow analysis: fix scrutinee promotion for fields.
Prior to this change, the SSA node stored in `PromotionModel.ssaNode`
was only correct for promotion models that represented variable
references. If a promotion model represented a promotable field, its
`ssaNode` pointed to a bogus SSA node. This had two undesirable
effects:

- It meant that `FlowModel.rebaseForward` needed to contain a hack to
  prevent it from looking at the bogus SSA node for a promotable
  field, and falsely concluding that the field's value had been
  reassigned (which is impossible for promotable fields)--see
  https://dart-review.googlesource.com/c/sdk/+/321752.

- It meant that if a promotable field was used as a scrutinee in a
  refutable pattern match, the promotion logic would look at the bogus
  SSA node for the field, and falsely conclude that its value had been
  reassigned, preventing field promotion from working during pattern
  matching.

This change ensures that the correct SSA node is always stored in
`PromotionModel.ssaNode`, and removes the hack in
`FlowModel.rebaseForward`. This required some re-ordering some of the
logic for control flow joins, to ensure that when a join creates a
fresh promotion model for a property, it has already created the
corresponding `_PropertySsaNode` (previously, it created the
`_PropertySsaNode` afterwards, but that is too late since the
`PromotionModel` class is immutable).

Unit tests and language tests are introduced to validate the newly
fixed behavior for promotable fields used as a scrutinee in a
refutable pattern match.

Also, the uses of `FlowModel.infoFor` in queries such as
`getMatchedValueType`, `isAssigned`, `isUnassigned`, and
`promotedType` were changed to simple map lookups, to prevent bogus
SSA nodes from being created and then immediately discarded. This
resulted in a fairly significant boost to CFE compilation speed:

  page-faults:u: -1.2664% +/- 0.1535% (-2531.33 +/- 306.73)
  instructions:u: -0.6210% +/- 0.0009% (-119891846.00 +/- 180585.35)
  branches:u: -0.6765% +/- 0.0014% (-26637478.67 +/- 54272.64)
  branch-misses:u: -0.9562% +/- 0.8909% (-548444.00 +/- 510991.65)

Change-Id: I30f82e8a4ba11236735258077d61d36717fa32c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322443
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-28 15:01:56 +00:00
Paul Berry b29e4a8554 Flow analysis: unit test that join variables are usable and promotable.
These tests fill a coverage gap in the flow analysis unit
tests. Previously we tested that "join" variables were created by
logical-or patterns and switch cases that share a body, but we didn't
have any tests to verify that those variables could be used.

We now verify that those variables can be read from and promoted.

Change-Id: Ic8948cd307edff429aea9007183d65cc3a770ef3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322360
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2023-08-24 16:42:20 +00:00
Paul Berry 30e8ed8410 Flow analysis: fix field promotion based on condition variables.
When the result of an `is` test or null check is stored in a boolean
variable, and later recalled for use in flow control, the flow models
that were computed at the time the variable was stored need to be
updated to reflect any further change to flow state that happened
between the test and the usage. This is done by
`FlowModel.rebaseForward` method. `rebaseForward` takes two flow
models as input: `this`, which represents the flow state that was
computed at the time the condition variable was stored, and `base`,
which represents the flow state at the time the condition variable is
recalled.

Flow analysis adds promotion keys for variables to the flow state at
the time their declarations are encountered, and in certain
circumstances removes them after they go out of scope. But for
properties, it only adds promotion keys when the promotion occurs. So
prior to the addition of field promotion, if `this` contained a
promotion key that wasn't present in `base`, that could only mean that
the promotion key was associated with a variable that had gone out of
scope; accordingly, it was safe for `rebaseForward` to simply ignore
that key. (It did so implicitly, by only ever examining the promotion
keys in `this`). But with the addition of field promotion, it is now
possible that the promotion key represents a property that was
promoted in `this`, and hence the promotion needs to be kept. This CL
adds the necessary logic to keep the promotion.

In addition, there is a subtle difference in the relationship between
the `PromotionModel` and `SsaNode` data structures for local variables
versus properties. For local variables, the promotion key is
determined solely from the variable name; then, this promotion key is
looked up in the current `FlowModel` to obtain a `PromotionModel`, and
the `PromotionModel` contains a prointer to the `SsaNode`. For
properties, the property name is looked up in the
`promotableProperties` map of the parent `SsaNode`; this points to a
`_PropertySsaNode`, which contains the promotion key, and when this
promotion key is looked up in the current `FlowModel` to obtain a
`PromotionModel`, that `PromotionModel` contains a pointer to a bogus
`SsaNode`.

For local variables, the `SsaNode` pointed to by the `PromotionModel`
is important, because if it's different between `this` and `base`,
then the variable in question received a new value between the time
the condition variable was stored and the time the condition variable
was recalled; therefore the promotion should be disregarded. However,
for properties, the `SsaNode` pointed to by the `PromotionModel` is
bogus, so if it's different between `this` and `base`, that shouldn't
block promotion. This CL adds the necessary logic to avoid the
`SsaNode` check for properties.

This situation is very confusing so I've added more detail to the
comment above `PromotionModel.SsaNode` explaining it. In a future CL I
will try to clean up the confusing situation by eliminating the bogus
`SsaNode`s pointed to by `PromotionModel`s for properties.

Fixes https://github.com/dart-lang/sdk/issues/53273.

Bug: https://github.com/dart-lang/sdk/issues/53273
Change-Id: I1d528e25de1eb2ed63d0ee1a00faa5ad5b5061ca
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321752
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-24 14:02:29 +00:00
Paul Berry 2ecc88e7ef Flow analysis: Replace merge with join followed by unsplit.
The `merge` operation is equivalent to a `join` operation followed by
an `unsplit` operation, so there is no real benefit to having both
`merge` and `join` as separate methods. Removing `merge` will make it
easier to refactor the behavior of `join` in follow-up CLs.

Change-Id: I4a42cdd1cb2e795dcfeae86703fe5d3356c131ce
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322140
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
2023-08-23 20:28:00 +00:00
Paul Berry 5c018e5c65 Flow analysis: Simplify Reachability class.
Remove the `Reachability.restrict` method--it hasn't been used since
2021, and was only kept around by mistake.

Remove the `Reachability.join` method--it was only used in the
circumstance where two flow control paths were being joined that had
equivalent reachability, in which case, it did nothing but return a
new reachability that was equivalent to one of its inputs. Call sites
have been updated to assert that the two control flow paths are indeed
equivalent, and then simply use the first control flow path's
reachability.

Change-Id: Ie24789ccd18723425b7db405d2122954dfae7b5b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321841
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2023-08-22 14:19:10 +00:00
Paul Berry b9adb3d398 Flow analysis: adjust nomenclature to reflect field promotion.
The class `VariableModel` is renamed to `PromotionModel` to reflect
that it tracks promotion information for both local variables and
fields. Variables and fields that map from a promotion key to an
instance of `PromotionModel` are renamed from `variableInfo` to
`promotionInfo`.

Also a few comments are re-worded to make them clearer.

There is no functional change--this is a rename-only CL.

Change-Id: Ie0e7147d290171407f31fe65af85ce96dd51694a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321362
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-18 02:48:47 +00:00
Paul Berry 7703609cc1 Flow analysis: fix interaction of field promotion and try/finally.
Try/finally statements have an unusual property that needs to be
handled in a special way by flow analysis: within the `finally` block,
the `try` block might not have run to completion, but after the
try/finally statement, the `try` block is known to have run to
completion. Therefore, even though the code that follows the
try/finally statement is immediately preceded by the end of the
`finally` block, the flow states of those two control flow points
might not be the same.

Flow analysis accounts for this situation by analyzing the `finally`
block as though it started executing right after the beginning of the
`try` block, but with all variables that are written within the `try`
block demoted. Then, after it finishes analyzing the `finally` block,
it builds a fresh flow model by starting with the flow state after the
end of the `try` block, and then applying any promotions that were
performed within the `finally` block. This is accomplished by the
`FlowModel.attachFinally` method.

The following changes had to be made to make this work with field
promotion:

- If a given promotion key appears in the "after try" model but not
  the "after finally" model, it might represent a field that was
  promoted during the `try` block, so the promotion needs to be
  preserved. Previously, this situation could only occur if the
  promotion key represented a variable declared in the `try` block
  (and therefore the variable would not be accessible after the
  try/finally statement), so the promotion could be safely dropped.

- If a given promotion key appears in the "after try" model and the
  "after finally" model, but not the "before finally" model, it might
  represent a field that was promoted within both the `try` and
  `finally` blocks, so the promotions need to be combined. Previously,
  this situation could not occur, so the promotion could be safely
  dropped.

- If a given promotion key is associated with the same SSA node in the
  "before finally" and "after finally" models, but a different SSA
  node in the "after try" model, that means that the corresponding
  variable was assigned in the `try` block but not in the `finally`
  block. If any properties of the variable were promoted within the
  `finally` block, those promotions were applied to the SSA nodes used
  by the `finally` block, and don't appear in the SSA nodes used in
  the "after try" model. So those promotions need to be
  transferred. This is accomplished by the new
  `SsaNode._applyPropertyPromotions` method.

- If a given promotion key appears in the "after finally" model but
  not the "after try" model, it might represent a field that was
  promoted during the `finally` block, so the promotion needs to be
  preserved. Previously, this situation could only occur if the
  promotion key represented a variable declared in the `finally` block
  (and therefore the variable would not be accessible after the
  try/finally statement), so the promotion could be safely dropped.

Fixes https://github.com/dart-lang/sdk/issues/53225.

Bug: https://github.com/dart-lang/sdk/issues/53225
Change-Id: Ie4b635dbf838447d6964c326e1ecebfff99bed8e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/320961
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-17 19:16:48 +00:00
Paul Berry d31689ae2f Flow analysis: unify field promotions when joining SSA nodes.
Flow analysis implements field promotion using an extension of SSA
(static single assignment) analysis.

In traditional SSA, an analysis phase assigns a collection of SSA
nodes to each local variable in the program, such that each SSA node
represents a region of control flow in which there are no assignments
to the variable, and no control flow joins that might affect the
variable's value. Each local variable read expression is therefore
associated with an SSA node, establishing the invariant that two reads
that share the same SSA node are known to produce identical results.

In flow analysis, SSA nodes are also assigned to property get
expressions, with a similar invariant: two property gets that share
the same SSA node are known to produce identical results. To ensure
soundness, flow analysis generally only considers a property get
expression to be promoted if the get has the same SSA node as a
previous type test.

There's an exception, though: if a property get is associated with an
SSA node that arose from a control flow join, it may be appropriate to
consider it promoted, if the SSA nodes that were joined are both
considered to be promoted. For example, consider the code below:

    class C {
      final int? _i;
      C(this._i);
    }
    f(bool b, C c1, C c2) {
      C c3;
      if (b) {
        c3 = c1;
        if (c3._i == null) return;
      } else {
        c3 = c2;
        if (c3._i == null) return;
      } // (1)
      print(c3._i + 1); // (2)
    }

At (2), it makes sense to consider `c3._i` to be promoted, because
`c3._i` was type checked in both control flow paths leading up to the
join point at (1). However, since those two control flow paths contain
different assignments to `c3`, at the time that the join point (1) is
analyzed, flow analysis assigns a fresh SSA node to `c3._i`, distinct
from the two SSA nodes that were type checked.

To ensure that the promotion is preserved, a new method is introduced,
`SsaNode._join`, which creates the fresh SSA node and updates the
newly created flow model to preserve the promotion. The bulk of the
heavy lifting is done by `SsaNode._joinProperties`, which recursively
walks the `_promotableProperties` maps of the two SSA nodes being
joined, creating fresh promotions for all the properties that should
have their promotions preserved.

This required plumbing some new parameters through
`VariableModel.join` (which calls `SsaNode._join`), so that
`SsaNode._joinProperties` can find the promotion information along the
two incoming control flow paths, and can create fresh promotions for
the outgoing control flow path.

Fixes https://github.com/dart-lang/sdk/issues/53146.

Change-Id: I6e53b3363ab5d769bef1b96f0ccd380fa2ca39df
Bug: https://github.com/dart-lang/sdk/issues/53146
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/320580
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
2023-08-14 21:27:59 +00:00
Paul Berry 907e705307 Flow analysis: use a more precise split point for refutable patterns.
Previously, the flow control logic for patterns didn't use the
`FlowModel.split` or `FlowModel.unsplit` methods at all. This meant
that if a control flow join point occurred in pattern logic, flow
analysis would consider the split point to be whatever split point was
established by the enclosing expression or statement. In the case of
an if-case statement, it would consider the split point to be at the
beginning of the scrutinee expression.

Split points are used by flow analysis for the sole purpose of
ensuring that joins propagate type promotions the same way in dead
code as they do in live code (so that users introducing temporary
`throw` expressions or `return` statements into their code do not have
to deal with nuisance compile errors in the (now dead) code that
follows. The consequence of flow analysis considering the split point
to be at the beginning of the scrutinee expression is that if the
scrutinee expression is proven to always throw, then joins that arise
from the pattern or guard may not behave consistently with how they
would have behaved otherwise. For example:

    int getInt(Object o) => ...;
    void consumeInt(int i) { ... }
    test(int? i) {
      if (
          // (1)
          getInt('foo')
          case
              // (2)
              int()
          // (3)
          when i == null) {
      } else {
        // (4)
        consumeInt(i);
      }
    }

In the above code, there is a join point at (4), joining control flows
from (a) the situation where the pattern `int()` failed to match, and
(b) the situation where `i == null` evaluated to `false` (and hence
`i` is promoted to non-nullable `int`). Since the return type of
`getInt` is `int`, it's impossible for the pattern `int()` to fail, so
at the join point, control flow path (a) is considered
unreacable. Therefore the promotion from control flow path (b) is
kept, and so the call to `consumeInt` is valid.

In order to decide whether to preserve promotions from one of the
control flow paths leading up to a join, flow analysis only considers
reachability relative to the corresponding split point. Prior to this
change, the split point in question occurred at (1), so if the
expression `getInt('foo')` had been replaced with `getInt(throw
UnimplementedError())`, flow analysis would have considered both
control flow paths (a) and (b) to be unreachable relative to the split
point, so it would not have preserved the promotion from (b), and
there would have been a compile time error in the (now dead) call to
`consumeInt`.

This change moves the split point from (1) to (2), so that changing
`getInt('foo')` to `getInt(throw UnimplementedError())` no longer
causes any change in type promotion behavior.

The implementation of this change is to add calls to `FlowModel.split`
and `FlowModel.unsplit` around all top-level patterns. At first glance
this might appear to affect the behavior of all patterns, but actually
the only user-visible effect is on patterns in if-case statements,
because:

- In switch statements and switch expressions, there is already a
  split point before each case.

- In irrefutable patterns, there is no user-visible effect, because
  irrefutable patterns cannot fail to match, and therefore don't do
  any control flow joins.

This change allows the split points for patterns to be determined by a
simple syntactic rule, which will facilitate some refactoring of split
points that I am currently working on.

Change-Id: I55573ba5c28b2f2e6bba8731f9e3b02613b6beb2
Bug: https://github.com/dart-lang/sdk/issues/53167
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319381
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-11 17:09:49 +00:00
Paul Berry 9a3420f1d4 Flow analysis: fix field promotion within cascades of non-promotable targets.
Previously, flow analysis used a hack to make it easy to generate "why
not promoted" messages when the user tried to promote a non-promotable
field: it treated all field accesses as stable for the purpose of
assigning SSA nodes, but avoided promoting non-promotable fields by
setting the `_Reference.isPromotable` flag to `false`. So, for
instance, in the following code, both subexpressions `c.i` got
assigned the same SSA node, even though there's no guarantee that
`C.x` will return the same value each time it's invoked.

    class C {
      int? get i => ...;
    }
    f(C c) {
      if (c.i != null) {
        var i = c.i; // Inferred type `int?`
      }
    }

This mostly worked, since the SSA node assigned by flow analysis is
only used for promotion, and promotion is disabled for non-promotable
fields. However, it broke when the field in question was used as the
target of a cascade, because fields within cascades always had their
`_Reference.isPromotable` flag set to `true` regardless of whether the
corresponding cascade target is promotable. For example:

    class C {
      D? get d => ...;
    }
    class D {
      final E? _e;
      ...
    }
    class E {
      m() { ... }
    }
    f(C c) {
      (c.d)
        .._e!.m() // OK; promotes _e
        .._e.m(); // OK; _e is promoted now
      (c.d)
        .._e.m(); // OOPS, _e is still promoted; it shouldn't be
    }

See
`tests/language/inference_update_2/cascaded_field_promotion_unstable_target_test.dart`
for a more detailed example.

This CL removes the hack; now, when a non-promotable property is
accessed more than once, flow analysis assignes a different SSA node
for each access. As a result, the `_Reference.isPromotable` is not
needed, because non-promotable fields simply never have the chance to
be promoted (since every field access gets a separate SSA node, so
type checking one field access has no effect on others).

To preserve the ability to generate "why not promoted" messages, the
`_PropertySsaNode` class now contains a `previousSsaNode` pointer,
which links together the separate SSA nodes allocated for
non-promotable properties, so that they form a linked list. The "why
not promoted" logic traverses this list to figure out which promotions
*would* have occurred if the property had been promotable.

In order to make it efficient to create this linked list, the
`SsaNode` class also had to acquire a `_nonPromotableProperties` map,
which records the SSA node that was allocated the last time each
property was accessed.

Fixes https://github.com/dart-lang/sdk/issues/52728.

Change-Id: I16a7b27f77c309bdccce86195a53398e32e8f75d
Bug: https://github.com/dart-lang/sdk/issues/52728
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318745
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-08-08 17:26:09 +00:00
Chloe Stefantsova bd951bb5ad [cfe] Treat promitions from T? to non-nullable as two-step
This CL introduces handling of promotions of the form `x is T` where
`x` has static type `X?`, `X` is a type variable, and `T` is
non-nullable. They are treated as an equivalent of `x == null || x is
T`, effectively resulting in the static type of `x` being `X & T` in
the promoted code.

Closes https://github.com/dart-lang/sdk/issues/52973

Change-Id: Ibfa6e32e14202651db09cfb4fbbdec864552b96a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316381
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
2023-08-02 09:51:31 +00:00
Jake Macdonald 597444b54e add hasBody getter to FunctionDeclaration
Bug: https://github.com/dart-lang/language/issues/3078
Change-Id: I3b14d050062d0c2e90e6e0f5614dcc25e87a23fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316060
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
2023-08-01 16:00:29 +00:00
Jake Macdonald 91f389ed6a Drop use of package:_dart_internal in _fe_analyzer_shared
This is largely a copy of https://github.com/leafpetersen/cast, with some extra magic.

Change-Id: Iff92ac9a57b1cfbaa67fe15647aabb8858442b60
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/316880
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
2023-07-28 22:36:44 +00:00
Paul Berry 5a79f8a9f3 Unify "mini-ast" constructs for rest pattern elements.
Previously, in the "mini-ast" pseudo-language for shared flow analysis
and type analysis unit testing, there were two separate functions to
create a rest pattern (`...`):

- `listPatternRestElement` for creating a rest pattern for use in a
  list pattern

- `mapPatternRestElement` for creating a rest pattern for use in a map
  pattern

The latter is not allowed in Dart, but it's supported to allow for
better error recovery.

But having two functions wasn't necessary--the two functions did
exactly the same thing.

This CL simplifies things so that there is just a single function,
`restPattern`. It also renames the underlying representation class
from `RestPatternElement` to `RestPattern`, to match the nomenclature
in the patterns spec document.

Change-Id: Iecfe8c86f49161e0657cdab44f000f47c0e3c212
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315520
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
2023-07-25 16:36:28 +00:00
Paul Berry 39e1357288 Add shared analysis testing infrastructure for map literals.
This change adds the functions `mapLiteral` and `mapEntry` to the
"mini-ast" representation used for unit testing shared flow analysis
and type analysis logic. These can be used to model map literals with
explicit type arguments. Set/map literals without explicit type
arguments are not supported yet.

These functions replace the old `inContextMapEntry` method, which was
an alternative way of testing the type analysis behavior of map
literal entries (and was not yet being used). The new approach is
better in that it allows the test cases to follow the structure of
actual Dart code (map entries inside map literals) rather than just
testing map entries in isolation.

Change-Id: I4bfd31b8fb2865f3d0892da0a47ee0bdacaf9250
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315225
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-07-25 13:49:06 +00:00
Jake Macdonald e12698594c Move more macro apis to has* instead of is* nomenclature.
These are intended to be syntactic and not semantic in meaning, so I think has* is a better name.

Change-Id: Ia2a8a276c1057bde913eb755cc1a7a559d953774
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315960
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
2023-07-24 20:51:38 +00:00
Jake Macdonald 5220b9e5f7 Add Extension declaration introspection and extension macros
Bug: https://github.com/dart-lang/language/issues/3223
Change-Id: I43e0ea17ea1bf8dbb41ad899675ac25d26ca568f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315300
Commit-Queue: Jake Macdonald <jakemac@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
2023-07-24 15:24:10 +00:00
Paul Berry 03a91b5d2a Simplify handling of variable expressions in shared analysis tests.
When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.expr` to turn a `Var` into
an `Expression`; this now happens automatically. The way this works
under the hood is that the `Var` and `Expression` classes implement
the `ProtoExpression` interface; constructs that expect expressions
are declared with input parameters of type `ProtoExpression`, and they
automatically convert to `Expression`s when necessary.

Change-Id: I85c493145c3fc41a5296c1807cd63fe1401672db
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315247
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-07-24 15:03:19 +00:00
Jake Macdonald 9803ffef27 Add support for macros adding mixins and interfaces to existing types in
the types phase.

Also seales the Code types hierarchy to block users from attempting to
create their own subclasses.

Bug: https://github.com/dart-lang/language/issues/3211
Change-Id: I51ebdfdad6e1fba3c19ef91f25e238730e98e740
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314821
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
2023-07-21 15:18:33 +00:00
Paul Berry 82a196387d Allow .pattern only on const expressions.
Previously, when using the "mini-ast" pseudo-language to write unit
tests for the flow analysis and type analysis logic in the
`_fe_analyzer_shared` package, it was possible to call `.pattern` on
any arbitrary expression, creating a constant pattern containing the
expression. This didn't make sense--only constant expressions can be
used as the basis for constant patterns.

With this change, `.pattern` is only available on the various forms of
constant expressions supported by the "mini-ast" pseudo-language
(currently: integer literals, the `null` literal, and placeholder
expressions created using the `expr` function).

Change-Id: I0d87c66bdb8e636615b20bbb6207c38d78d0d2dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315245
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
2023-07-21 14:52:26 +00:00
Paul Berry 64ecabdf16 Add function second to flow analysis tests.
In several flow analysis tests we need to model an expression with two
subexpressions, where the type of the overall expression is the same
as the type of the second subexpression.

Previously we did this using `ProtoStatement.thenExpr`, which created
a magic compound expression consisting of an expression (or statement)
followed by a second expression. This was too general, since it
allowed modelling code that would not be possible in Dart.

This CL replaces uses of `ProtoStatement.thenExpr` with a function
`second`, which models a Dart function defined this way:

    T second(dynamic x, T y) => y;

This has two advantages:

- The tests are now modelling code that could actually exist in the
  real world, rather than modelling pseudo-expressions that are not
  actually possible to write in Dart.

- It prepares for a follow-up CL in which I'll be unifying the
  representation of patterns and expressions in the flow analysis
  tests; eliminating `ProtoStatement.thenExpr` will prevent a conflict
  between it and `PossiblyGuardedPattern.thenExpr`.

With this change, two tests had to be deleted, because the conditions
they were testing could no longer be expressed:

- `for_conditionBegin() handles not-yet-seen variables`

- `whileStatement_conditionBegin() handles not-yet-seen variables`

This is ok, because these tests were designed to verify correct
behavior in the circumstance where the client forgets to declare a
variable. This circumstance no longer arises, because the
`_FlowAnalysisImpl` constructor detects undeclared variables and
generates synthetic declarations for them.

Change-Id: I19275ba0b7fa143ce7051bf14d0d4c6f57a4ab8e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315244
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
2023-07-21 14:43:08 +00:00
Paul Berry bcaab7e985 Make more "mini-ast" constructs into expressions.
The following functions, which are used to create constructs in the
"mini-ast" pseudo-language to write unit tests for shared flow
analysis and type analysis logic, now have a return type of
`Expression` rather than `Statement`:

- checkAssigned
- checkUnassigned
- getSsaNodes
- implicitThis_whyNotPromoted an expression

This allows them to be used either where an expression is exprected or
where a statement is expected, which should give us the ability to
write some tests that are not possible (or very difficult) to write
today.

Change-Id: Ie50e82ad05dc88182b59c99c11ffaac41515ebb9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315460
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
2023-07-21 13:24:37 +00:00
Paul Berry 7dc587d344 Simplify handling of switch heads in shared analysis tests.
When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.switchCase` to turn a
`Pattern` (or a `GuardedPattern`) into a `SwitchHead`; this now
happens automatically. The way this works under the hood is that the
`PossiblyGuardedPattern`, and `SwitchHead` classes implement the
`ProtoSwitchHead` interface; constructs that expect switch heads are
declared with input parameters of type `ProtoSwitchHead`, and they
automatically convert to switch heads when necessary.

Change-Id: Ic16264fc52ffff08bf0e0cc72db064a6da63eda5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315180
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-07-20 15:20:57 +00:00
Paul Berry ecf71eb63b Simplify handling of collection elements in shared analysis tests.
When using the "mini-ast" pseudo-language to write unit tests for the
flow analysis and type analysis logic in the `_fe_analyzer_shared`
package, it is no longer necessary to use `.asCollectionElement` to
turn an expression into a collection element; this now happens
automatically. The way this works under the hood is that both the
`CollectionElement` and `Expression` classes mix in the
`ProtoCollectionElement` mixin; constructs that expect collection
elements are declared with input parameters of type
`ProtoCollectionElement`, and they automatically convert expressions
to collection elements when necessary.

Also, instead of using `.inContextElementType` to establish the
appropriate context when testing a collection element, the tests not
simply create a `listLiteral` of the appropriate type, containing the
appropriate collection elements. This makes the unit tests much more
similar to the way actual Dart code is written in the wild, and makes
the test infrastructure more closely mirror the way types are analyzed
by the analyzer and CFE.

Change-Id: Ib628ff12caa84254df069308ae3a25061377db29
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314141
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2023-07-20 13:14:24 +00:00
Jake Macdonald 1b99100e2e Add API for resolving any identifier in the final macro phase.
- Rename declarationOf to typeDeclarationOf.
- Add declarationOf api for general declarations.
- Tighten the type of typeDeclarationOf in the final phase to avoid unnecessary
  casts in user code.
- Refactor message handling a bit to unify the error handling.

Bug: https://github.com/dart-lang/language/issues/3216
Change-Id: Ia61da19374abec77853d37e110a08f7dfe0d3b10
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314280
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
2023-07-19 13:56:08 +00:00