inferred types not treated the same as explicit type by deferred loading

According to the spec it is an error to use a deferred type in an expression or type: you can’t use them in variable or function declarations, is/as/catch clauses, and cannot use them in generic type arguments of any form.

This is checked and reported as an error for explicit types in dartanalyzer and CFE, but it is today ignored for inferred types. Unfortunately there is code out there where this occurs. For example, some applications show cases like these:

import 'b.dart' deferred as d;
main() {
   ...
   // inferred return-type in closures:
   d.B f1() => new d.B(); // detected as an error today
   var f2 = () => new d.B(); // no error, but f1 has inferred type: () -> d.B

   // inferred type-arguments
   d.list = <d.B>[]; // detected as an error today, can't use the type parameter
   d.list = []; // no error, but type parameter was injected here
   d.list = d.eList.map((x) => x.bValue).toList(); // no error, type parameter inferred on closure and map<T>.
}

When dart2js splits a program with these types, it ignores the error cases and allows those deferred types to be deferred. This is unsound in the presence of reified types.

To address performance problems in our current implementation of deferred loading, we are revisiting the algorithm and our changes are likely going to affect this behavior.

4 options so far:

  1. Make this a proper error: change the CFE/analyzer, announce a breaking change, and ignore the issue in dart2js.
  2. Make deferred loading more flexible: the errors above exist because dart2js represents types and classes as one thing. If we split the runtime type representation in dart2js, we could remove this limitation of deferred loading.
  3. Make this a warning and do a sound code split by assigning more types to the main output unit.
  4. Hide the error and try to mimic the current unsound behavior (either by ignoring certain cases or by using the “any” type we have for js-interop)

(2) is our long term goal, but it will take time (at least a few months), (1) seems unfortunate if we are aiming to do (2). (4) could work because today’s behavior is working for our users, however we are not sure if it’s feasible to do after we change the algorithm implementation (in particular, some patterns we want to ignore are hard to distinguish from problematic patterns like #33046).

Author: Fantashit

2 thoughts on “inferred types not treated the same as explicit type by deferred loading

  1. Hi @sigmundch, checking in again.

    We’ve been talking about @jakemac53 for our own null-safety migration, and one thing that came up is we might be able to always emit null-safe annotated code, relying on the mixed-mode runtime to “do the right thing” (if a user is not migrated, they will largely ignore our annotations, and if they are, they will be enforced to some extent).

    This probably reduces the amount of work we need to do possibly by 1/3 or more, because we would only need to focus on emitting null-safe code, and not forking 35K+ lines of our compiler, or adding lots of if statements. It doesn’t need to be done now, but it could be a huge benefit towards our overall strategy.

    … however, that whole strategy is blocked because we currently export {user_code}.dart` in our generated code, and we can’t remove that feature because of this very issue.

  2. @matanlurey thanks for checking in.

    @joshualitt is actively working on this. woohoo!

    Large part of the algorithm is in progress (see cl/154580). There is a bit more polish work needed and some validation to ensure that we are properly slicing the code, so we plan to start with this under a flag for a short period before we enable it internally.

    I didn’t fully grasp how reexports are at play with this problem, though. I’m happy to chat offline if you think it could help explore other ideas that may let you avoid being blocked on this issue.

Comments are closed.