Skip to content

dart-lang/sdk

main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

If a user promotes a field and then subsequently changes the variable
used to access it, the promotion must be discarded. For example, in
this code:

    class C {
      int? _i;
    }
    test(C c1, C c2) {
      C c = c1;           // (1)
      if (c._i != null) { // (2)
        print(c._i + 1);  // (3)
        c = c2;           // (4)
        print(c._i + 1);  // (5)
      }
    }

The test at (2) promotes `c._i` to non-null, so (3) is ok. But since
`c` is reassigned at (4), (5) should be a compile-time error.

Previously, flow analysis used one promotion key to track `c` and one
promotion key to track `c._i`. The `PromotionKeyStore` associated each
promotion key with a map containing the promotion keys of all of its
properties. So, for example, if the promotion key for `c` was 10 and
the promotion key for `c._i` was 11, the `PromotionKeyStore` would
associate promotion key 10 with the map `{'_i': 11}`, so that each
time `c._i` was accessed, promotion key 11 would be found. In order to
detect the compile-time error at (5), it had to keep track of the fact
that keys 10 and 11 were related, so that the assignment to `c` at (4)
could invalidate the promotion of `c._i`. It accomplished this by
linking together all the related promotion keys in a circularly linked
list, which it would walk at the time of any variable assignment.

This worked, but it required a lot of complex bookkeeping. Also, it
posed problems for integrating field promotion with cascades, for
example, in the following code:

    class B {
      void f([_]) { ... }
    }
    class C {
      B? _b;
    }
    test(C c1, C c2) {
      C c = c1;           // (6)
      if (c._b != null) { // (7)
        c.._b.f(          // (8)
	    [
              c = c2,     // (9)
	      c._b.f(),   // (10)
	    ])
         .._b.f();        // (11)
      }
    }

The cascaded access `.._b.f` at (8) should be ok, since `c._b` has
been promoted. But since there is an assignment to `c` at (9), the
promotion should not carry over to (10), and an error should be
reported. However, no error should be reported at (11) because the
cascaded access to `.._b.f` at that location is using the old value of
`c` that was captured at the beginning of the cascade, prior to the
assignment. There's no way to achieve this by invalidation alone,
since the code locations at which the promotion is valid ((8) and
(11), but not (10)) aren't even contiguous.

The solution to the problem is to store property promotion keys in
`SsaNode`s used by flow analysis, rather than in the
`PromotionKeyStore`. Since a fresh `SsaNode` is allocated each time a
variable is assigned, this automatically invalidates any previous
property promotions without the need for any extra bookkeeping. So, in
the first example, at (1), an `SsaNode` is allocated and associated
with the promotion key for `c`. At (2), a promotion key is created for
`c._i` and stored in `c`'s `SsaNode`, and the flow model is updated to
indicate that that key has been promoted to non-null. At (3), that
promotion key is reacalled from the `c`'s `SsaNode`, so the promotion
is still in effect. At (4), a fresh `SsaNode` is associated with
`c`. Since that `SsaNode` doesn't contain any promotion keys yet, at
(5), the access to `c._i` causes a fresh promotion key to be
allocated, with no associated promotions. So the invalidation happens
automatically due to the fact that a new `SsaNode` was created.

Flow analysis doesn't yet support cascades, but here's how the second
example is intended to work: as before, at (6), an `SsaNode` is
allocated and associated with the promotion key for `c`. At (7), a
promotion key is created for `c._b` and stored in `c`'s `SsaNode`, and
the flow model is updated to indicate that `c._b` has been promoted to
non-null. At (8), the `SsaNode` for `c` is captured and saved for
later use. At (9), a fresh `SsaNode` is created and associated with
`c`. That fresh `SsaNode` is consulted at (10), so `c._b` is not
promoted at this point. However, at (11), the previously stored
`SsaNode` is used, so the promotion of `._b` still works.

Change-Id: I64519fbcb2368a37aa18adf35cee0ffd290db9b9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/307140
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
39de3f2

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
pkg
 
 
 
 
 
 
sdk
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gn
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Dart

A client-optimized language for fast apps on any platform

Dart is:

  • Optimized for UI: Develop with a programming language specialized around the needs of user interface creation.

  • Productive: Make changes iteratively: use hot reload to see the result instantly in your running app.

  • Fast on all platforms: Compile to ARM & x64 machine code for mobile, desktop, and backend. Or compile to JavaScript for the web.

Dart's flexible compiler technology lets you run Dart code in different ways, depending on your target platform and goals:

  • Dart Native: For programs targeting devices (mobile, desktop, server, and more), Dart Native includes both a Dart VM with JIT (just-in-time) compilation and an AOT (ahead-of-time) compiler for producing machine code.

  • Dart Web: For programs targeting the web, Dart Web includes both a development time compiler (dartdevc) and a production time compiler (dart2js).

Dart platforms illustration

License & patents

Dart is free and open source.

See LICENSE and PATENT_GRANT.

Using Dart

Visit dart.dev to learn more about the language, tools, and to find codelabs.

Browse pub.dev for more packages and libraries contributed by the community and the Dart team.

Our API reference documentation is published at api.dart.dev, based on the stable release. (We also publish docs from our beta and dev channels, as well as from the primary development branch).

Building Dart

If you want to build Dart yourself, here is a guide to getting the source, preparing your machine to build the SDK, and building.

There are more documents on our wiki.

Contributing to Dart

The easiest way to contribute to Dart is to file issues.

You can also contribute patches, as described in Contributing.