Shared type analysis: API adjustments for analyzer and CFE

I've begun prototyping what it might look like to integrate the
current shared type analysis functionality with the analyzer and CFE,
and I've discovered some API improvements that are needed:

- The shared logic now handles the possibility that switch cases that
  share a body have been merged prior to type analysis (because the
  CFE merges them during parsing), in addition to the pre-existing
  functionality which assumed that switch case merging had to be done
  in the shared logic.

- The shared logic now returns several pieces of information as the
  result of a call to `analyzeSwitchStatement`: whether the switch
  statement had a `default` clause, whether it was exhaustive, whether
  the last case body terminates, and the type of the scrutinee.  These
  are all needed by the CFE.

- The shared logic now allows `TypeAnalyzer.errors` to be `null`,
  indicating that no errors should be reported.  This reflects how
  errors are suppressed during top level inference in the CFE.

- If a switch case lacks a `when` clause, this is reported by calling
  `handleNoWhen` rather than passing a boolean to `handleCaseHead`.

- The shared logic now reports the appropriate error when a case
  constant doesn't properly match the scrutinee's static type.

- Information about case labels is now delivered to flow analysis via
  `switchStatement_endAlternatives` rather than
  `switchStatement_beginCase`.  This made it possible to rewrite the
  shared `analyzeSwitchStatement` method in a way that requires less
  bookkeeping, because it no longer has to peek ahead to look for
  labels associated with a given case body.

- `TypeAnalyzer.analyzeExpression` is now responsible for
  understanding that "no context" and a context of `dynamic` should
  both be coalesced to `?`.  The analyzer does this (although it's not
  100% why), and it's definitely "business logic" that eventually
  belongs in the shared type analyzer.

- `TypeAnalyzer.analyzeSwitchExpression` and
  `TypeAnalyzer.analyzeSwitchStatement` no longer receive a list of
  ExpressionCaseInfo / StatementCaseInfo objects describing the cases;
  instead they query for them using a callback.  This reduces the
  lifetime of the ExpressionCaseInfo / StatementCaseInfo objects.  In
  the future, when we have record support, we could replace these
  objects with records, which would then be passed on the stack,
  avoiding any allocations.

- A new hook, `handleSwitchScrutinee`, is called right after visiting
  the "scrutinee" expression of a switch expression or switch
  statement.  This hook is needed by the analyzer to compute
  exhaustiveness.  In a future CL, I hope to move exhaustiveness
  analysis into the shared code as well, which should make this hook
  unnecessary.

- `TypeAnalyzer.analyzeSwitchStatement` now reports an error if a
  switch case completes normally and pattern support is not enabled.

- The test class `_MiniAstTypeAnalyzer` no longer overrides
  `analyzeExpression` to provide a default context type; instead,
  every call to `analyzeExpression` that didn't previously provide a
  context now provides a context of `?`.  Note that not all of these
  are correct, but they are close enough for the unit tests we have
  today.  I plan to fix them in future CLs as I replace this logic
  with shared logic.

- The hook `handleVariablePattern` is now always provided with a
  static type.  Previously, it was only provided with a static type if
  this was the first time the variable was bound in the pattern.

Change-Id: I70e3c5468312a9329fcf4ad2e13749a32d2418e7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/257487
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
14 files changed
tree: af577af7a029542a1e2969c8a11fd63218600101
  1. .dart_tool/
  2. .github/
  3. benchmarks/
  4. build/
  5. docs/
  6. pkg/
  7. runtime/
  8. samples/
  9. sdk/
  10. tests/
  11. third_party/
  12. tools/
  13. utils/
  14. .clang-format
  15. .gitattributes
  16. .gitconfig
  17. .gitignore
  18. .gn
  19. .mailmap
  20. .style.yapf
  21. .vpython
  22. AUTHORS
  23. BUILD.gn
  24. CHANGELOG.md
  25. codereview.settings
  26. CONTRIBUTING.md
  27. DEPS
  28. LICENSE
  29. OWNERS
  30. PATENT_GRANT
  31. PRESUBMIT.py
  32. README.dart-sdk
  33. README.md
  34. sdk_args.gni
  35. SECURITY.md
  36. WATCHLISTS
README.md

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.