├── .cloud_build └── specification │ └── cloudbuild.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── 1-PROBLEM_STATEMENT.md │ ├── 2-FEATURE.md │ └── 3-BUG.md ├── dependabot.yml └── workflows │ ├── dart.yml │ ├── no-response.yml │ └── spec.yml ├── .gitignore ├── LICENSE ├── PATENTS ├── README.md ├── accepted ├── 2.0 │ └── sound-type-system.md ├── 2.1 │ ├── int-literal-as-double-value │ │ └── feature-specification.md │ └── super-mixins │ │ ├── feature-specification.md │ │ ├── implementation-plan.md │ │ └── mixin-inference.md ├── 2.12 │ ├── abstract-external-fields │ │ ├── feature-specification.md │ │ └── implementation-plan.md │ └── nnbd │ │ ├── feature-specification.md │ │ ├── number-operation-typing.md │ │ └── roadmap.md ├── 2.13 │ └── nonfunction-type-aliases │ │ ├── feature-specification.md │ │ └── implementation-plan.md ├── 2.14 │ ├── small-features-21Q1 │ │ ├── feature-specification.md │ │ └── implementation-plan.md │ └── triple-shift-operator │ │ ├── feature-specification.md │ │ └── implementation-plan.md ├── 2.15 │ └── constructor-tearoffs │ │ ├── faq.md │ │ ├── feature-specification.md │ │ └── test-plan.md ├── 2.17 │ ├── 1847-finalization-registry │ │ └── proposal.md │ ├── enhanced-enums │ │ └── feature-specification.md │ ├── named-arguments-anywhere │ │ └── feature-specification.md │ └── super-parameters │ │ └── feature-specification.md ├── 2.18 │ └── horizontal-inference │ │ └── feature-specification.md ├── 2.19 │ └── unnamed-libraries │ │ └── feature-specification.md ├── 2.2 │ └── set-literals │ │ ├── feature-specification.md │ │ └── implementation-plan.md ├── 2.3 │ ├── control-flow-collections │ │ ├── feature-specification.md │ │ └── implementation-plan.md │ ├── spread-collections │ │ ├── benchmarks │ │ │ ├── .gitignore │ │ │ ├── Makefile │ │ │ ├── bin │ │ │ │ ├── lrhn_benchmark.dart │ │ │ │ ├── profile.dart │ │ │ │ ├── profile_list_spread.dart │ │ │ │ └── profile_map.dart │ │ │ └── pubspec.yaml │ │ ├── examples │ │ │ ├── postfix-ellipses │ │ │ │ ├── build_methods.dart │ │ │ │ └── other.dart │ │ │ └── prefix-ellipses │ │ │ │ ├── build_methods.dart │ │ │ │ └── other.dart │ │ ├── feature-specification.md │ │ ├── implementation-plan.md │ │ └── performance.md │ └── unified-collections │ │ └── feature-specification.md ├── 2.5 │ ├── constant-update-2018 │ │ ├── feature-specification.md │ │ └── implementation-plan.md │ └── contravariant-superinterface-2018 │ │ ├── feature-specification.md │ │ └── implementation-plan.md ├── 2.7 │ └── static-extension-methods │ │ ├── feature-specification.md │ │ ├── implementation-plan.md │ │ └── old │ │ ├── feature-specification-draft14.md │ │ ├── lrn-static-extension-survey.md │ │ └── lrn-strawman.md ├── 2.8 │ └── language-versioning │ │ ├── feature-specification.md │ │ ├── implementation-plan.md │ │ └── package-config-file-v2.md ├── 3.0 │ ├── class-modifiers │ │ └── feature-specification.md │ ├── patterns │ │ ├── exhaustiveness.md │ │ └── feature-specification.md │ └── records │ │ └── feature-specification.md ├── README.md └── future-releases │ ├── 0323-null-aware-elements │ └── feature-specification.md │ ├── 0546-patterns │ ├── exhaustiveness.md │ ├── exhaustiveness_prototype │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── benchmark │ │ │ ├── large_fields_call_counts.dart │ │ │ └── large_fields_timed.dart │ │ ├── lib │ │ │ ├── equal.dart │ │ │ ├── exhaustive.dart │ │ │ ├── intersect.dart │ │ │ ├── intersect_empty.dart │ │ │ ├── profile.dart │ │ │ ├── space.dart │ │ │ ├── static_type.dart │ │ │ └── subtract.dart │ │ ├── pubspec.yaml │ │ └── test │ │ │ ├── expand_type_test.dart │ │ │ ├── intersect_empty_test.dart │ │ │ ├── intersect_test.dart │ │ │ ├── intersect_types_test.dart │ │ │ ├── is_exhaustive_field_test.dart │ │ │ ├── is_exhaustive_nested_test.dart │ │ │ ├── is_exhaustive_type_test.dart │ │ │ ├── report_errors_test.dart │ │ │ ├── static_type_test.dart │ │ │ ├── subtract_test.dart │ │ │ └── utils.dart │ ├── feature-specification.md │ ├── goals-and-constraints.md │ └── why-two-kinds-of-patterns.md │ ├── 3009-inference-using-bounds │ └── design-document.md │ ├── async-star-behavior │ ├── feature-specification.md │ └── implementation-plan.md │ ├── class-modifiers │ └── feature-specification.md │ ├── digit-separators │ └── feature-specification.md │ ├── extension-types │ └── feature-specification.md │ ├── records │ └── records-feature-specification.md │ ├── sealed-types │ └── feature-specification.md │ ├── unquoted-imports │ └── feature-specification.md │ └── wildcard-variables │ └── feature-specification.md ├── analysis_options.yaml ├── archive ├── 0036 - Set Literals │ └── 0037 - Math-Braced Set Literals - lrhn.md ├── 0649 - Import shorthand │ └── proposal.md ├── README.md ├── feature-specifications │ ├── assert-in-initializer-list.md │ ├── covariant-from-class.md │ ├── covariant-overrides.md │ ├── dynamic-members.md │ ├── extreme-upper-lower-bounds.md │ ├── generalized-void.md │ ├── generic-function-instantiation.md │ ├── generic-function-type-alias.md │ ├── generic-method-syntax.md │ ├── implicit-creation.md │ ├── instantiate-to-bound.md │ ├── int-to-double.md │ ├── int64.md │ ├── interface-conflicts.md │ ├── invalid_returns.md │ ├── mixin-declaration.md │ ├── mixin-inference.md │ ├── nosuchmethod-forwarding.md │ ├── optional-new-const.md │ ├── subtyping.md │ └── super-bounded-types.md └── newsletter │ ├── 20171103 │ ├── big.json │ ├── json.dart │ ├── json2.dart │ └── json3.dart │ ├── 20170728.md │ ├── 20170804.md │ ├── 20170811.md │ ├── 20170818.md │ ├── 20170825.md │ ├── 20170901.md │ ├── 20170908.md │ ├── 20170915.md │ ├── 20170922.md │ ├── 20170929.md │ ├── 20171006.md │ ├── 20171013.md │ ├── 20171020.md │ ├── 20171027.md │ ├── 20171103.md │ ├── 20171110.md │ ├── 20171124.md │ ├── README.md │ └── lib │ ├── as_broadcast.svg │ ├── broadcast.svg │ ├── broadcast_transformer.svg │ ├── lib.md │ ├── multicast.svg │ └── single_subscription.svg ├── doc └── life_of_a_language_feature.md ├── inactive ├── enhanced-type-promotion │ └── feature-specification.md ├── packaged-libraries │ └── feature-specification.md ├── reserve-await-and-yield.md ├── terminating-tokens.md └── type-modifiers │ └── feature-specification.md ├── resources ├── README.md ├── String Class Issues.md ├── backgroundhow-other-languages-manage-breakage.md ├── bazel │ └── module-structure.md ├── class-capabilities │ └── class-capabilities.md ├── instance-initialization-analysis.md ├── null-shorting │ └── nullshort.sml ├── old-non-nullable-types.md ├── optional-semicolons-prototype.md ├── type-system │ ├── flow-analysis.md │ ├── inference.md │ ├── normalization.md │ ├── strict-casts.md │ ├── strict-inference.md │ ├── strict-raw-types.md │ ├── subtyping.md │ └── upper-lower-bounds.md ├── variance │ ├── showWidening.sml │ ├── typeModel.sml │ └── widen.sml └── warnings.md ├── specification ├── .gitignore ├── Makefile ├── dart.sty ├── dartLangSpec.tex ├── firebase.json ├── pubspec.yaml └── scripts │ ├── addlatexhash.dart │ ├── build_pdf │ └── simplify_specification.dart ├── templates └── implementation_meta_issue.txt ├── tools ├── corpus │ ├── .gitignore │ ├── README.md │ └── scripts │ │ ├── bin │ │ ├── clone_flutter_apps.dart │ │ ├── clone_widgets.dart │ │ ├── copy_corpus.dart │ │ └── download_packages.dart │ │ ├── lib │ │ └── utils.dart │ │ └── pubspec.yaml └── plaintext_grammar.dart └── working ├── 0015-infer-required └── feature-specification.md ├── 0093 - Gradual Language Change Migration └── 0094 - Per Library Language Version Selection │ └── strawman.md ├── 0107 - implicit-constructors ├── feature-brainstorm.md └── feature-specification.md ├── 0125-static-immutability └── feature-specification.md ├── 0158 - Enhanced Enum ├── feature_specification.md └── proposal.md ├── 0323-null-aware-elements └── feature-specification.md ├── 0546-patterns ├── exhaustiveness.md ├── goals-and-constraints.md ├── patterns-feature-specification.md └── why-two-kinds-of-patterns.md ├── 0649 - Import shorthand └── proposal.md ├── 0698 - Enhanced Default Constructors └── proposal.md ├── 0723-static-extensions ├── feature-specification-variant1.md └── feature-specification.md ├── 0731 - horizontal inference └── feature-specification.md ├── 0884 └── interface_default_methods_proposal.md ├── 1113 - null-asserting compound assignment └── proposal.md ├── 1426-extension-types ├── feature-specification-inline-classes.md ├── feature-specification-views.md └── feature-specification.md ├── 1610 - override └── proposal.md ├── 1661 - unawaited futures └── proposal.md ├── 1855 - super parameters ├── package_evaluation.md └── proposal.md ├── 2364 - primary constructors ├── feature-specification.md └── scripts │ ├── class.json │ ├── class_namedpar.json │ ├── class_optpar.json │ ├── class_requiredpar.json │ ├── const_class.json │ ├── const_class_namedpar.json │ ├── const_class_optpar.json │ ├── const_class_requiredpar.json │ ├── generic_class.json │ ├── generic_class_namedpar.json │ ├── generic_class_optpar.json │ ├── generic_class_requiredpar.json │ ├── inline_class.json │ ├── inline_const_class.json │ ├── inline_generic_class.json │ ├── inline_named_class.json │ ├── inline_named_const_class.json │ ├── inline_subtyped_class.json │ ├── inline_subtyped_const_class.json │ ├── inline_subtyped_generic_class.json │ ├── inline_subtyped_generic_const_class.json │ ├── named_class.json │ ├── named_class_namedpar.json │ ├── named_class_optpar.json │ ├── named_class_requiredpar.json │ ├── named_const_class.json │ ├── named_const_class_namedpar.json │ ├── named_const_class_optpar.json │ ├── named_const_class_requiredpar.json │ ├── named_subtyped_class.json │ ├── named_subtyped_class_namedpar.json │ ├── named_subtyped_class_optpar.json │ ├── named_subtyped_class_requiredpar.json │ ├── named_subtyped_const_class.json │ ├── named_subtyped_const_class_namedpar.json │ ├── named_subtyped_const_class_optpar.json │ ├── named_subtyped_const_class_requiredpar.json │ ├── named_subtyped_generic_class.json │ ├── named_subtyped_generic_class_namedpar.json │ ├── named_subtyped_generic_class_optpar.json │ ├── named_subtyped_generic_class_requiredpar.json │ ├── named_subtyped_generic_const_class.json │ ├── named_subtyped_generic_const_class_namedpar.json │ ├── named_subtyped_generic_const_class_optpar.json │ ├── named_subtyped_generic_const_class_requiredpar.json │ ├── show_primary_constructors.dart │ ├── subtyped_class.json │ ├── subtyped_class_namedpar.json │ ├── subtyped_class_optpar.json │ ├── subtyped_class_requiredpar.json │ ├── subtyped_const_class.json │ ├── subtyped_const_class_namedpar.json │ ├── subtyped_const_class_optpar.json │ ├── subtyped_const_class_requiredpar.json │ ├── subtyped_generic_class.json │ ├── subtyped_generic_class_namedpar.json │ ├── subtyped_generic_class_optpar.json │ ├── subtyped_generic_class_requiredpar.json │ ├── subtyped_generic_const_class.json │ ├── subtyped_generic_const_class_namedpar.json │ ├── subtyped_generic_const_class_optpar.json │ └── subtyped_generic_const_class_requiredpar.json ├── 2936 - Unresolved constants └── proposal.md ├── 333 - shared memory multithreading └── proposal.md ├── 3616 - enum value shorthand ├── proposal-lrhn.md └── proposal-simple-lrhn.md ├── README.md ├── augmentation-libraries ├── feature-specification.md └── parts_with_imports.md ├── base-interface-final └── feature-specification.md ├── declaring-constructors └── feature-specification.md ├── digit-separators └── feature-specification.md ├── enhanced-constructors └── feature-specification.md ├── extension_structs └── overview.md ├── field-promotion └── proposals-overview.md ├── macros ├── aspect-macros.md ├── feature-specification.md ├── host-notes.md └── motivation.md ├── modules ├── feature-specification.md ├── motivation.md └── private-imports.md ├── reflected-imports └── feature-specification.md ├── sealed-types └── feature-specification.md ├── specification └── compositional semantics.md ├── static wrapper types └── feature-specification.md ├── tagged-strings ├── alternative-generalized-feature-specification.md └── feature-specification.md ├── union-types └── nominative-union-types.md ├── unquoted-imports └── feature-specification.md ├── value-classes └── feature-specification.md └── wildcards └── feature-specification.md /.cloud_build/specification/cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: 'ubuntu' 3 | args: ['specification/scripts/build_pdf'] 4 | env: 5 | - 'BRANCH_NAME=$BRANCH_NAME' 6 | - '_PR_NUMBER=$_PR_NUMBER' 7 | - name: 'gcr.io/cloud-builders/gsutil' 8 | args: [ '-m', 'cp', '-r', 'specification/artifacts/*', 'gs://dart-specification'] 9 | options: 10 | automapSubstitutions: true 11 | logging: CLOUD_LOGGING_ONLY 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-PROBLEM_STATEMENT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: I have a problem which is impossible or inconvenient to solve in Dart 3 | labels: request 4 | about: A description of a problem without necessarily pointing to a particular 5 | solution. This may be the motivation for a new language feature. 6 | 7 | --- 8 | 9 | Describe the problem you are trying to solve, why is it hard to solve today? 10 | Avoid describing the problem in terms of your preferred solution - you may want 11 | to file a separate feature request issue related to this problem. If you'd like 12 | a feature which exists in another language, describe the use cases. 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-FEATURE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: I have an idea for a new language feature 3 | labels: feature 4 | about: A new syntax or language feature. 5 | 6 | --- 7 | 8 | Describe the new syntax or language feature you'd like to see incorporated into 9 | Dart. Ideally you can relate this to a `request` issue filed separately. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-BUG.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: I found a bug in the spec or documentation 3 | labels: bug 4 | about: There is an error in the spec or one of the feature implementation 5 | documents. 6 | 7 | --- 8 | 9 | Include a permanent link to the error if possible. 10 | 11 | https://help.github.com/en/articles/getting-permanent-links-to-files 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration file. 2 | # See https://docs.github.com/en/code-security/dependabot/dependabot-version-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: github-actions 7 | directory: / 8 | schedule: 9 | interval: monthly 10 | labels: 11 | - autosubmit 12 | groups: 13 | github-actions: 14 | patterns: 15 | - "*" 16 | -------------------------------------------------------------------------------- /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | push: 7 | branches: [main] 8 | 9 | env: 10 | PUB_ENVIRONMENT: bot.github 11 | 12 | jobs: 13 | analyze: 14 | continue-on-error: true 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 18 | - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c 19 | with: 20 | sdk: main 21 | - name: dart pub get (specification) 22 | run: dart pub get 23 | working-directory: specification 24 | - name: dart pub get (tools/corpus) 25 | run: dart pub get 26 | working-directory: tools/corpus/scripts 27 | - name: dart pub get (accepted/2.3/spread-collections/benchmarks) 28 | run: dart pub get 29 | working-directory: accepted/2.3/spread-collections/benchmarks 30 | - name: dart pub get (accepted/future-releases/0546-patterns/exhaustiveness_prototype) 31 | run: dart pub get 32 | working-directory: accepted/future-releases/0546-patterns/exhaustiveness_prototype 33 | - name: dart analyze --fatal-infos . 34 | run: dart analyze --fatal-infos . 35 | test: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 39 | - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c 40 | with: 41 | sdk: main 42 | - name: dart pub get (accepted/future-releases/0546-patterns/exhaustiveness_prototype) 43 | run: dart pub get 44 | working-directory: accepted/future-releases/0546-patterns/exhaustiveness_prototype 45 | - name: dart test (accepted/future-releases/0546-patterns/exhaustiveness_prototype) 46 | run: dart test 47 | working-directory: accepted/future-releases/0546-patterns/exhaustiveness_prototype 48 | -------------------------------------------------------------------------------- /.github/workflows/no-response.yml: -------------------------------------------------------------------------------- 1 | # A workflow to close issues where the author hasn't responded to a request for 2 | # more information; see https://github.com/actions/stale. 3 | 4 | name: No Response 5 | 6 | # Run as a daily cron. 7 | on: 8 | schedule: 9 | # Every day at 8am 10 | - cron: '0 8 * * *' 11 | 12 | # All permissions not specified are set to 'none'. 13 | permissions: 14 | issues: write 15 | pull-requests: write 16 | 17 | jobs: 18 | no-response: 19 | runs-on: ubuntu-latest 20 | if: ${{ github.repository_owner == 'dart-lang' }} 21 | steps: 22 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 23 | with: 24 | days-before-stale: -1 25 | days-before-close: 14 26 | stale-issue-label: "needs-info" 27 | close-issue-message: > 28 | Without additional information we're not able to resolve this issue. 29 | Feel free to add more info or respond to any questions above and we 30 | can reopen the case. Thanks for your contribution! 31 | stale-pr-label: "needs-info" 32 | close-pr-message: > 33 | Without additional information we're not able to resolve this PR. 34 | Feel free to add more info or respond to any questions above. 35 | Thanks for your contribution! 36 | -------------------------------------------------------------------------------- /.github/workflows/spec.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | # Run on PRs and pushes to the default branch. 5 | push: 6 | branches: [ main ] 7 | paths: 8 | - 'specification/**' 9 | - '.github/workflows/spec.yml' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'specification/**' 14 | - '.github/workflows/spec.yml' 15 | 16 | jobs: 17 | specification: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 22 | 23 | - name: Install latex tools 24 | run: | 25 | sudo apt-get update -qq 26 | sudo apt-get install \ 27 | texlive-latex-base \ 28 | texlive-latex-extra \ 29 | texlive-fonts-recommended \ 30 | lmodern 31 | 32 | - name: Build specification 33 | run: | 34 | cd specification 35 | make 36 | mkdir firebase 37 | cp dartLangSpec.pdf firebase/DartLangSpecDraft.pdf 38 | 39 | - name: Upload specification 40 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 41 | uses: FirebaseExtended/action-hosting-deploy@0cbcac4740c2bfb00d632f0b863b57713124eb5a 42 | with: 43 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 44 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_DART_SPECIFICATION }}' 45 | projectId: dart-specification 46 | entryPoint: specification/ 47 | channelId: ${{ github.event_name == 'push' && 'live' || '' }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build artifacts and dependencies. 2 | /.children 3 | /.project 4 | /Makefile 5 | /base 6 | /benchmarks 7 | /buildtools 8 | /ipch 9 | /out 10 | /xcodebuild 11 | /.flaky.log 12 | /.debug.log 13 | *.Makefile 14 | *.opensdf 15 | *.sdf 16 | *.sln 17 | *.suo 18 | *.target.mk 19 | *.host.mk 20 | *.vcproj 21 | *.vcxproj 22 | *.vcxproj.filters 23 | /*.vcxproj.user 24 | *.stamp 25 | .dart_tool 26 | .packages 27 | pubspec_overrides.yaml 28 | 29 | # Gyp generated files 30 | *.xcodeproj 31 | *.intermediate 32 | 33 | # Eclipse config files - also in all subdirectories. 34 | .children 35 | .project 36 | .settings 37 | 38 | # IntelliJ project files 39 | *.iml 40 | .idea 41 | CMakeLists.txt 42 | .clang_complete 43 | 44 | # VSCode project files 45 | .vscode 46 | .history 47 | 48 | # Built by chromebot and downloaded from Google Storage 49 | client/tests/drt 50 | 51 | # Compiled python binaries 52 | *.pyc 53 | 54 | # pydev project file. 55 | .pydevproject 56 | 57 | # From the Mac OS X Finder 58 | .DS_Store 59 | 60 | # Pub generated "packages" directories and files 61 | packages 62 | pubspec.lock 63 | 64 | # Local pub storage 65 | .pub 66 | 67 | # Vim temporary swap files. 68 | *.swp 69 | 70 | # Kate temporary files. 71 | *~ 72 | *.kate-swp 73 | 74 | # Merge files. 75 | *.orig 76 | *.rej 77 | 78 | # Generated files. 79 | tools/dartium/out 80 | tools/out 81 | tools/xcodebuild 82 | editor/util/testing/mac/CodeLab.suite/Results 83 | editor/util/testing/mac/DartEditor.suite/Results 84 | editor/util/testing/mac/Samples.suite/Results 85 | .test-outcome.log 86 | /outline.dill 87 | /generated/ 88 | /crash_logs/ 89 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The following license applies to all parts of this repository. 2 | See https://github.com/dart-lang/sdk/blob/main/LICENSE for the license 3 | of the Dart language implementation. 4 | 5 | Copyright 2018, the Dart project authors. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | * Neither the name of Google LLC nor the names of its 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Dart Project. 5 | 6 | Google hereby grants to you a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this 8 | section) patent license to make, have made, use, offer to sell, sell, 9 | import, transfer, and otherwise run, modify and propagate the contents 10 | of this implementation of Dart, where such license applies only to 11 | those patent claims, both currently owned by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by 13 | this implementation of Dart. This grant does not include claims that 14 | would be infringed only as a consequence of further modification of 15 | this implementation. If you or your agent or exclusive licensee 16 | institute or order or agree to the institution of patent litigation 17 | against any entity (including a cross-claim or counterclaim in a 18 | lawsuit) alleging that this implementation of Dart or any code 19 | incorporated within this implementation of Dart constitutes direct or 20 | contributory patent infringement, or inducement of patent 21 | infringement, then any patent rights granted to you under this License 22 | for this implementation of Dart shall terminate as of the date such 23 | litigation is filed. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dart language evolution 2 | 3 | [![Build Status](https://github.com/dart-lang/language/workflows/CI/badge.svg)](https://github.com/dart-lang/language/actions?query=workflow%3ACI+branch%3Amain) 4 | 5 | This repository is a place for the [Dart][website] language team to work on 6 | [language changes and features][language funnel], and to solicit and accept 7 | [feedback and requests](https://github.com/dart-lang/language/issues). 8 | 9 | # Dart language team 10 | 11 | As of January 2024, the Dart language team consists of: 12 | 13 | * Leaf Petersen ([@leafpetersen](https://github.com/leafpetersen)), language engineer 14 | * Lasse R.H. Nielsen ([@lrhn](https://github.com/lrhn)), language engineer 15 | * Bob Nystrom 16 | ([@munificent](https://github.com/munificent)), language engineer 17 | * Erik Ernst ([@eernstg](https://github.com/eernstg)), language engineer, [specification][specification] maintainer 18 | * Nate Bosch ([@natebosch](https://github.com/natebosch)), language engineer 19 | * Jake MacDonald ([@jakemac53](https://github.com/jakemac53)), language engineer 20 | * Paul Berry ([@stereotype441](https://github.com/stereotype441)), language engineer 21 | * Michael Thomsen ([@mit-mit](https://github.com/mit-mit)), product manager 22 | * Kallen Tu ([@kallentu](https://github.com/kallentu)), language engineer 23 | * David Morgan ([@davidmorgan](https://github.com/davidmorgan)), language engineer 24 | 25 | # Organization 26 | 27 | We follow [this process](https://github.com/dart-lang/language/blob/master/doc/life_of_a_language_feature.md) 28 | for planning and rolling out language changes. 29 | 30 | Features currently being worked on are listed in the [language funnel][]. 31 | 32 | ## Contributing 33 | 34 | Anyone can participate in the discussion about language changes 35 | by participating on the dart language mailing list, 36 | by replying to issues in this repository, 37 | and by uploading documents, tests or other resources. 38 | 39 | When commenting on issues in this repository, keep in mind: 40 | 41 | - :+1: reactions are more useful than comments to show support. 42 | - Motivating examples help us understand why you want new features more than 43 | pointers to other languages which have them. We love hearing feedback about 44 | your experiences with other languages, but we also want to know why they are 45 | right for Dart in particular. 46 | 47 | ## License & patents 48 | 49 | See [LICENSE][license] and [PATENTS][patents]. 50 | 51 | [website]: https://www.dartlang.org 52 | [license]: https://github.com/dart-lang/language/blob/master/LICENSE 53 | [patents]: https://github.com/dart-lang/language/blob/master/PATENTS 54 | [specification]: https://dart.dev/guides/language/spec 55 | [language funnel]: https://github.com/orgs/dart-lang/projects/90 56 | -------------------------------------------------------------------------------- /accepted/2.0/sound-type-system.md: -------------------------------------------------------------------------------- 1 | Dart 2.0 focused on one large, single change: Reworking the Dart 1.x type system 2 | to a complete & sound type system. For details, please see: 3 | https://www.dartlang.org/guides/language/sound-dart -------------------------------------------------------------------------------- /accepted/2.1/super-mixins/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation plan for super mixins 2 | 3 | Relevant documents: 4 | - [Tracking issue](https://github.com/dart-lang/language/issues/12) 5 | - [Discussion issue](https://github.com/dart-lang/language/issues/7) 6 | - [Full proposal](https://github.com/dart-lang/language/blob/master/accepted/2.1/super-mixins/feature-specification.md) 7 | - [Mixin inference](https://github.com/dart-lang/language/blob/master/accepted/2.1/super-mixins/mixin-inference.md) 8 | 9 | ## Implementation and Release plan 10 | 11 | ### Release flags 12 | 13 | Old school super-mixins are currently behind a flag in the analyzer, and 14 | available by default on the VM. They are not supported in dart2js and DDC, but 15 | some uses may accidentally work. We will not have a separate release flag for 16 | this feature. Platforms that currently have an `enableSuperMixins` flag will 17 | initially launch this feature behind this flag as described below. The VM will 18 | pick up support for this without a flag. 19 | 20 | ### Phase 0 (Syntax) 21 | 22 | #### CFE 23 | 24 | CFE adds support for the new syntax without (necessarily) implementing errors 25 | and warnings. This unblocks the analyzer work. 26 | 27 | ### Phase 1 (Frontend support) 28 | 29 | #### CFE 30 | 31 | Initial support is provided by translating mixin declarations 32 | into classes as follows: 33 | ```dart 34 | mixin M on S0, S1, ..., Sk implements I0, ..., Im { ...} 35 | ``` 36 | 37 | May be translated to: 38 | 39 | ```dart 40 | class M extends S0 with S1, ..., Sk implements I0, ..., Im { ...} 41 | ``` 42 | 43 | This allows existing code that is currently written as the latter to be 44 | rewritten using the new syntax without loss of functionality. 45 | 46 | Note that mixin inference must continue to be supported on the translated 47 | declarations in order for this to be useful for migration purposes. 48 | 49 | #### Analyzer/CFE 50 | 51 | Errors per the specification are implemented in the analyzer or the CFE (both 52 | for declarations and for uses), and support for surfacing these errors is added 53 | to the analyzer. 54 | 55 | #### Analyzer/Linter 56 | 57 | Implement a lint that fires when an old-school super mixin is used. 58 | 59 | #### Intellij/Grok/Dartfmt 60 | 61 | Support for the new mixin declaration syntax is added to the relevant tooling. 62 | 63 | ### Phase 2 (Functional backend support) 64 | 65 | #### Language team 66 | 67 | Turn on old-school mixin lint in flutter, and move flutter over to the new 68 | declaration syntax. 69 | 70 | ### Dart2js, DDC 71 | 72 | Implement support for the new syntax, and for the semantics to the extent that 73 | they are supported today (specifically, non-super-mixins using the mixin 74 | declaration syntax should work). This should be possible by translation to 75 | classes if necessary. 76 | 77 | ### Phase 3 (Flutter migration) 78 | 79 | ### Analyzer/CFE 80 | Move support for the new mixin declaration syntax out from behind the 81 | `enableSuperMixins` flag. Support for the old style syntax remains behind the 82 | flag. 83 | 84 | ### Language team 85 | 86 | After suitable migration period, remove `enableSuperMixins` flag from flutter 87 | analysis_options.yaml. 88 | 89 | ### Phase 4 (Full support) 90 | 91 | ### Dart2js, DDC 92 | 93 | Implement support for the feature. 94 | 95 | ### Dartdoc, Dartpad, Documentation sites 96 | 97 | Support verified, documentation in place. 98 | 99 | ### Phase 5 (Release and launch) 100 | 101 | ### Analyzer/CFE 102 | 103 | Remove support for old style super-mixins. 104 | 105 | ### Language team 106 | Clean up any remaining uses of old style super mixins, communicate and launch. 107 | 108 | ## Timeline 109 | 110 | Completion goals for the phases: 111 | 112 | - Phase 0: 2018.08.24 113 | - Phase 1: 2018.09.07 114 | - Phase 2: 2018.09.17 115 | - Phase 3: 2018.10.15 116 | - Phase 4: ??? 117 | - Phase 5: ??? 118 | -------------------------------------------------------------------------------- /accepted/2.13/nonfunction-type-aliases/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for the Q1 2019 Generalized Type Alias Feature 2 | 3 | Relevant documents: 4 | - [Tracking issue](https://github.com/dart-lang/language/issues/115) 5 | - [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/2.13/nonfunction-type-aliases/feature-specification.md) 6 | 7 | ## Implementation and Release plan 8 | 9 | This feature is non-breaking, because it is concerned with the introduction of 10 | support for new syntactic forms. 11 | Still, we will introduce it using an 12 | [experiments flag](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md) 13 | in order to enable a controlled deployment. 14 | 15 | 16 | ### Phase 0 (Preliminaries) 17 | 18 | #### Release Flag 19 | 20 | The flag 21 | `--enable-experiment=nonfunction-type-aliases` 22 | must be passed for the changes to be enabled. 23 | In this phase, support for that flag is added to all tools. 24 | 25 | #### Tests 26 | 27 | The language team adds a set of tests for the new feature, in terms of 28 | declarations and usages in the following situations: 29 | 30 | - A type alias with and without type arguments is used 31 | - as a type annotation for a variable of various kinds. 32 | - as a type argument of a class or another type alias. 33 | - as part of a function type. 34 | - in a function declaration as return type or parameter type. 35 | - as an expression. 36 | - as the type in an `on` clause. 37 | - in a type test (`is`). 38 | - in a type cast (`as`). 39 | - A type alias whose body is a class with or without type arguments, is used in 40 | - the `extends` clause of a class. 41 | - the `with` clause of a class. 42 | - the `implements` clause of a class or mixin. 43 | - the `on` clause of a mixin. 44 | - instance creation expressions, constant and non-constant. 45 | - an invocation of a static method, getter, setter, and a tear-off of a 46 | static method; note that the provision of type arguments 47 | (`F.m()`) is an error here. 48 | 49 | The co19 team start creating tests early, such that those tests can be 50 | used during implementation as well. 51 | 52 | ### Phase 1 (Analyzer and CFE Implementation) 53 | 54 | All tools implement syntactic support for type aliases of the form 55 | 56 | ```dart 57 | typedef F = type; 58 | ``` 59 | 60 | where `type` can be any type, rather than just a function type. 61 | 62 | All tools implement support for using such type aliases, in all situations 63 | mentioned under phase 0. 64 | 65 | ### Phase 2 (IDE tooling and Documentation) 66 | 67 | IDEs and other tools which consume/display Dart code should be updated to handle 68 | the new syntax. 69 | 70 | IDE support for any desired quick fixes, refactors, go-to-definition, etc should 71 | be implemented and validated as necessary. 72 | 73 | Dartdoc support validated. 74 | 75 | Dart format support validated. 76 | 77 | Documentation landed. 78 | 79 | ### Phase 3 (Core libraries and frameworks) 80 | 81 | Validate that frameworks (Angular) work correctly with generalized typedefs. 82 | 83 | Consider whether we wish to add any typedefs to the core libraries and/or 84 | Flutter at release. 85 | 86 | 87 | ### Phase 4 (Release) 88 | 89 | This feature is currently targetted to be released at the start of Q2. 90 | 91 | Prior to release, all tests relying on the experiment flag should be passing (or 92 | known to be incorrect tests). 93 | 94 | After the flag is flipped, all tests using the flag should have the flag 95 | removed. 96 | 97 | -------------------------------------------------------------------------------- /accepted/2.14/triple-shift-operator/feature-specification.md: -------------------------------------------------------------------------------- 1 | # The `>>>` Operator 2 | 3 | **Author**: [lrn@google.com](mailto:lrn@google.com) 4 | 5 | **Version**: 1.0 (2018-11-30) 6 | 7 | ## Feature Specification 8 | 9 | See [Issue #120](http://github.com/dart-lang/language/issues/120). 10 | 11 | The `>>>` operator is reintroduced as a user-implementable operator. 12 | It works exactly as all other user-implementable operators. 13 | It has the same precedence as the `>>` and `<<` operators. 14 | 15 | That also means that `>>>=` assignment must work 16 | and `#>>>` and `const Symbol(">>>")` must be valid symbols. 17 | The `>>>` operator should work in all the same places that `>>` currently does. 18 | 19 | The `int` class implements `>>>` as a logical right-shift operation, 20 | defined as: 21 | ```dart 22 | /// Shifts the bits of this integer down by [count] bits, fills with zeros. 23 | /// 24 | /// Performs a *logical shift* down of the bits representing this number, 25 | /// which shifts *out* the low [count] bits, shifts the remaining (if any) 26 | /// bits *down* to the least significant bit positions, 27 | /// and shifts *in* zeros as the most significant bits. 28 | /// This differs from [operator >>] which shifts in copies of the most 29 | /// significant bit as the new most significant bits. 30 | /// 31 | /// The [count] must be non-negative. If [count] is greater than or equal to 32 | /// the number of bits in the representation of the integer, the result is 33 | /// always zero (all bits shifted out). 34 | /// If [count] is greater than zero, the result is always positive. 35 | /// 36 | /// For a *non-negative* integers `n` and `k`, 37 | /// `n >>> k` is equivalent to truncating division of `n` by 2k, 38 | /// or `n ~/ (1 << k)`. 39 | int operator >>>(int count); 40 | ``` 41 | 42 | The JavaScript implementation of `int`'s `>>>` operator must be decided 43 | and implemented by the JavaScript platforms. It likely works like `>>` 44 | except that it doesn't "sign-extend" the most significant bit. 45 | 46 | ## Background 47 | 48 | When Dart chose arbitrary size integers as its `int` type, it also removed 49 | the `>>>` operator, not just from `int`, but from the language. 50 | 51 | Now that Dart has chosen to use signed 64-bit integers as its `int` type, 52 | there is again need for a logical right shift operator on `int`, 53 | and so we reintroduce the `>>>` operator in the language. 54 | 55 | This was decided before Dart 2 was released, and `>>>` was put into the 56 | current language specification document, but it was not implemented by 57 | the language tools for Dart 2.0 due to other priorities. 58 | -------------------------------------------------------------------------------- /accepted/2.14/triple-shift-operator/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for the `>>>` operator. 2 | 3 | Relevant documents: 4 | - [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/2.14/triple-shift-operator/feature-specification.md) 5 | ## Implementation and Release plan 6 | 7 | ### Phase 0 (Preliminaries) 8 | 9 | #### Specification 10 | 11 | The language specification already specifies `>>>` as a user-implementable 12 | operator. 13 | 14 | The `int` operator will act as documented in the feature specification 15 | when added. 16 | 17 | #### Tests 18 | 19 | The language team adds a set of tests for the new feature, 20 | both the general implementable operator, 21 | and the specific `int.operator>>>` implementation 22 | 23 | The co19 team start creating tests early, such that those tests can be 24 | used during implementation as well. 25 | 26 | The language specification is already updated with this feature. 27 | 28 | ### Phase 1 (Implementation) 29 | 30 | All tools implement syntactic support for the `>>>` operator. 31 | The syntax is guarded by the experiments flag `triple-shift`, 32 | so to enable the syntax, the tools need to be passed a flag 33 | like `--enable-experiments=triple-shift`. 34 | 35 | This also includes all derived syntax required by the specification, 36 | including the `>>>=` assignment oprator and the `#>>>` symbol. 37 | The `Symbol` constructor must also accept `>>>` as an argument. 38 | 39 | ### Phase 2 (Use) 40 | 41 | The library team implements `int.operator>>>`. 42 | This likely needs to be implemented as a branch 43 | which enables the experiments flag by default. 44 | As such, it can only be tested on that branch. 45 | Backends are free to optimize this operation further at any point. 46 | 47 | It is possible to delay the `int` operator until a later release, 48 | but it would be a better user experience to get it out as soon as possible. 49 | 50 | (It is not yet clear what semantics JS compilers will choose for `int.>>>`, 51 | this will also have to be decided). 52 | 53 | ### Phase 3 (Release) 54 | 55 | The feature is released as part of the next stable Dart release. 56 | 57 | ## Timeline 58 | 59 | Completion goals for the phases: 60 | - Phase 0: (TODO) 61 | - Phase 1: (TODO) 62 | - Phase 2: (TODO) 63 | - Phase 3: (TODO) 64 | -------------------------------------------------------------------------------- /accepted/2.19/unnamed-libraries/feature-specification.md: -------------------------------------------------------------------------------- 1 | # Unnamed Libraries 2 | 3 | Author: srawlins@google.com 4 | 5 | Version 1.0 6 | 7 | Specification for issue [#1073](https://github.com/dart-lang/language/issues/1073) 8 | 9 | ## Motivation 10 | 11 | Users would like to both document a library and associate metadata with a 12 | library without needing to decide on a library name. 13 | 14 | Declaring a library with a library declaration has become increasingly rare, 15 | with the availability of a 'part of' syntax with a URI string, and with the 16 | decline of the mirror system. Tools such as dartdoc and the test package 17 | attempt to support "library-level" documentation comments and annotations by 18 | looking at such elements associated with the first directive in a library, or 19 | the first declaration. Allowing users to write `library;` without a name gives 20 | a specific and meaningful syntax for library-level documentation and metadata. 21 | With this syntax, users do not need to conceive of a unique library naming 22 | scheme, nor do they need to write out names which are never used. 23 | 24 | ## Specification 25 | 26 | With this feature, library directives are allowed to be written without a name: 27 | 28 | ```dart 29 | // Existing named library syntax: 30 | library qualified.named.separated.by.dots; 31 | 32 | // New unnamed library syntax: 33 | library; 34 | ``` 35 | 36 | Prior to this feature, a library can be _explicitly named_ with a library 37 | directive, or _implicitly named_ when written without a library directive. An 38 | implicitly named library has the empty string as its name. With this feature, a 39 | library with a library directive without a name is an implicitly named library. 40 | 41 | ### Grammar 42 | 43 | The language grammar is changed to allow library directives without name. 44 | 45 | The section containin 46 | 47 | > ```latex 48 | > ::= \LIBRARY{} `;' 49 | > ``` 50 | 51 | becomes: 52 | 53 | > ```latex 54 | > ::= \LIBRARY{} ? `;' 55 | > ``` 56 | 57 | ### Parts 58 | 59 | A library part specifies the library to which it belongs using the part-of 60 | directive, which accepts two ways of referring to a library. A part-of 61 | directive can specify a library by URI, which is the more common way, and does 62 | not require the library to be explicitly named. In an older style, a part-of 63 | directive can instead specify a library by its name. A part-of directive cannot 64 | refer by name to an implicitly named library. Therefore, with this feature, a 65 | part-of directive using a library name cannot refer to a library with a library 66 | directive without a name. 67 | 68 | ### `dart:mirrors` 69 | 70 | The mirror system has at least one mechanism that uses a library's name, 71 | `MirrorSystem.findLibrary`. This function cannot find an implicitly named 72 | library. Therefore it cannot find a library with a library directive without a 73 | name. 74 | 75 | ## Summary 76 | 77 | We allow library directives without name. 78 | 79 | ## Versions 80 | 81 | 1.0, 2022-09-14: Initial version 82 | -------------------------------------------------------------------------------- /accepted/2.2/set-literals/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for Set literals 2 | 3 | Relevant documents: 4 | - [Tracking issue](TODO) 5 | - [Full proposal](https://github.com/dart-lang/language/blob/master/accepted/2.2/set-literals/feature-specification.md) 6 | 7 | ## Implementation and Release plan 8 | 9 | ### Release flags 10 | 11 | The implementation of this change will happen behind 12 | an 13 | [*experiments flag*](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md). 14 | Tools need to be passed the flag `--enable-experiment=set-literals` for the 15 | changes to be enabled. 16 | 17 | ### Task0 (Prerequisite) 18 | 19 | All tools add support for experimental flags, if not yet supported. This is 20 | tracked as Phase 0 of [this issue](https://github.com/dart-lang/language/issues/60). 21 | 22 | ### Task1 : Task0 (Parsing support) 23 | 24 | The CFE implements parsing support for the new literal syntax. 25 | 26 | ### Task2 : Task1 (CFE implementation) 27 | 28 | The CFE implements support for set literals (errors and warnings, constant 29 | evaluation, and any required changes to support the backends). 30 | 31 | ### Task3 : Task1 (Analyzer implementation) 32 | 33 | The analyzer implements static checking for set literals (errors and wrarnings, 34 | constant evaluation). 35 | 36 | ### Task4 : Task3 (DDC implementation) 37 | 38 | DDC implements backend support. 39 | 40 | ### Task5 : Task2 (VM support) 41 | 42 | VM implements backend support. 43 | 44 | ### Task6 : Task2 (dart2js support) 45 | 46 | dart2js implements backend support. 47 | 48 | ### Task7 : Task0 (Intellij support) 49 | 50 | IntelliJ parser supports set literals 51 | 52 | ### Task8 : Task1 (Grok support) 53 | 54 | Grok implements any required support. 55 | 56 | ### Task9 : Task3 (Dartfmt support) 57 | 58 | Dartfmt implements formatting support. 59 | 60 | ### Task9 : Task3 (Dartdoc support) 61 | 62 | Dartdoc implements support. 63 | 64 | ### Task10 : (Specification) 65 | 66 | Add set literals to formal spec 67 | 68 | ### Task11 : (Documentation) 69 | 70 | Document in language references 71 | 72 | ### Task12 : (co19 tests) 73 | 74 | co19 tests written. 75 | 76 | ### Task13 : (Language tests) 77 | 78 | Language tests written. 79 | 80 | ### Task14 : Task1 (Angular compiler, sourcegen) 81 | 82 | Angular compiler and sourcegen clients support set literals. 83 | 84 | ### Task15 : Task14 (Google3 roll) 85 | 86 | Roll to google3 with flag enabled. 87 | 88 | ### Task16 : * (Launch) 89 | 90 | Remove the experimental flag, enable by default, announce the feature. 91 | 92 | 93 | ## Timeline 94 | 95 | Completion goals for the phases: 96 | 97 | - Task0: Mid November 2018 98 | - Task1: November 16, 2018 99 | - Task2, Task3: November 30, 2018 100 | - Tasks 4-14: December 14, 2018 101 | - Task15: December 21, 2018 102 | - Task16: January, 2019 103 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/benchmarks/.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | .dart_tool/ 3 | .packages 4 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/benchmarks/Makefile: -------------------------------------------------------------------------------- 1 | # Runs the benchmarks on a few platforms. 2 | 3 | # Note: this assumes: 4 | # 5 | # - The language repo's root directory is adjacent to the root directory of the 6 | # Dart SDK repo, which is named "dart". 7 | # 8 | # - "node" is on your PATH. 9 | # 10 | # - You have built the AoT runtime by running this from the SDK root directory: 11 | # 12 | # tools/build.py -m release runtime dart_precompiled_runtime 13 | 14 | SDK := "../../../../../dart/sdk" 15 | 16 | # See https://japhr.blogspot.com/2014/07/command-line-arguments-with-nodejs-and.html. 17 | DART2JS_MAIN := 'function dartMainRunner(main, args) { main(process.argv.slice(2)); }' 18 | 19 | all: aot dart2js jit 20 | 21 | aot: 22 | @ mkdir -p out 23 | @ $(SDK)/pkg/vm/tool/precompiler2 bin/profile.dart out/profile.snapshot 24 | @ $(SDK)/pkg/vm/tool/dart_precompiled_runtime2 out/profile.snapshot "VM AoT" 0 --csv 25 | @ $(SDK)/pkg/vm/tool/dart_precompiled_runtime2 out/profile.snapshot "VM AoT" 5 --csv 26 | @ $(SDK)/pkg/vm/tool/dart_precompiled_runtime2 out/profile.snapshot "VM AoT" 50 --csv 27 | 28 | dart2js: 29 | @ mkdir -p out 30 | @ $(SDK)/sdk/bin/dart2js -O4 bin/profile.dart -o out/profile.js 31 | @ echo $(DART2JS_MAIN) >> out/profile.js 32 | @ node out/profile.js "dart2js -O4" 0 --csv 33 | @ node out/profile.js "dart2js -O4" 5 --csv 34 | @ node out/profile.js "dart2js -O4" 50 --csv 35 | 36 | jit: 37 | @ $(SDK)/sdk/bin/dart bin/profile.dart "VM JIT" 0 --csv 38 | @ $(SDK)/sdk/bin/dart bin/profile.dart "VM JIT" 5 --csv 39 | @ $(SDK)/sdk/bin/dart bin/profile.dart "VM JIT" 50 --csv 40 | 41 | .PHONY: all aot dart2js jit 42 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/benchmarks/bin/lrhn_benchmark.dart: -------------------------------------------------------------------------------- 1 | import "dart:collection"; 2 | 3 | void copy1(Map from, Map to) { 4 | for (var entry in from.entries) { 5 | to[entry.key] = entry.value; 6 | } 7 | } 8 | 9 | void copy2(Map from, Map to) { 10 | for (var key in from.keys) { 11 | to[key] = from[key]!; 12 | } 13 | } 14 | 15 | void copy3(Map from, Map to) { 16 | Map? tmp = to; 17 | from.forEach((key, value) { 18 | tmp![key] = value; 19 | }); 20 | tmp = null; 21 | } 22 | 23 | void copy4(Map from, Map to) { 24 | to.addAll(from); 25 | } 26 | 27 | main() { 28 | for (int i = 0; i < 5; i++) { 29 | bench("entries", copy1); 30 | bench("keys", copy2); 31 | bench("forEach", copy3); 32 | bench("addAll", copy4); 33 | } 34 | } 35 | 36 | int id(int x) => x; 37 | var maps = List.generate(100, (n) { 38 | var map = Map.fromIterable(Iterable.generate(n * 10), 39 | key: (n) => "#$n"); 40 | if (n % 4 == 1) map = SplayTreeMap.from(map); 41 | if (n % 4 == 2) map = HashMap.from(map); 42 | return map; 43 | }); 44 | 45 | void bench( 46 | String name, void Function(Map, Map) action) { 47 | var e = 0; 48 | var c = 0; 49 | var sw = Stopwatch()..start(); 50 | do { 51 | for (var from in maps) { 52 | var to = {}; 53 | action(from, to); 54 | c += from.length; 55 | } 56 | e = sw.elapsedMilliseconds; 57 | } while (e < 2000); 58 | print("$name: ${c / e} entries/ms"); 59 | } 60 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/benchmarks/bin/profile_list_spread.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | const trialMs = 100; 4 | const lengths = [0, 1, 2, 5, 10, 20, 50, 100, 1000]; 5 | 6 | var csv = StringBuffer(); 7 | 8 | class CustomList extends ListBase { 9 | final List _inner; 10 | 11 | int get length => _inner.length; 12 | 13 | set length(int value) => _inner.length = value; 14 | 15 | CustomList(this._inner); 16 | 17 | T operator [](int index) => _inner[index]; 18 | 19 | void operator []=(int index, T value) => _inner[index] = value; 20 | } 21 | 22 | void main() { 23 | for (var length in lengths) { 24 | var baseline = runBench("iterate", length, iterate); 25 | runBench("List for", length, addList, baseline); 26 | runBench("resize and set", length, resizeAndSet, baseline); 27 | runBench("addAll()", length, addAll, baseline); 28 | runBench("forEach()", length, forEach, baseline); 29 | print(""); 30 | } 31 | 32 | // print(""); 33 | // print(csv); 34 | } 35 | 36 | double runBench( 37 | String name, int length, void Function(List, List) action, 38 | [double? baseline]) { 39 | var from = []; 40 | for (var i = 0; i < length; i++) { 41 | from.add(String.fromCharCode(i % 26 + 65)); 42 | } 43 | 44 | var froms = [from, CustomList(from)]; 45 | 46 | var rate = benchBest(froms, action); 47 | 48 | if (baseline == null) { 49 | print("${length.toString().padLeft(4)} ${name.padRight(15)} " 50 | "${rate.toStringAsFixed(2).padLeft(10)} spreads/ms " 51 | " ${'-' * 20}"); 52 | } else { 53 | var comparison = rate / baseline; 54 | var bar = "=" * (comparison * 20).toInt(); 55 | if (comparison > 4.0) bar = "!!!"; 56 | print("${length.toString().padLeft(4)} ${name.padRight(15)} " 57 | "${rate.toStringAsFixed(2).padLeft(10)} spreads/ms " 58 | "${comparison.toStringAsFixed(2).padLeft(6)}x baseline $bar"); 59 | } 60 | 61 | csv.writeln("$length,$name,$rate"); 62 | return rate; 63 | } 64 | 65 | /// Runs [bench] a number of times and returns the best (highest) result. 66 | double benchBest(List> froms, 67 | void Function(List, List) action) { 68 | var best = 0.0; 69 | for (var i = 0; i < 4; i++) { 70 | var result = bench(froms, action); 71 | if (result > best) best = result; 72 | } 73 | 74 | return best; 75 | } 76 | 77 | /// Spreads each list in [froms] into the middle of a list using [action]. 78 | /// 79 | /// Returns the number of times it was able to do this per millisecond, on 80 | /// average. Higher is better. 81 | double bench(List> froms, 82 | void Function(List, List) action) { 83 | var elapsed = 0; 84 | var count = 0; 85 | var watch = Stopwatch()..start(); 86 | do { 87 | for (var i = 0; i < froms.length; i++) { 88 | var from = froms[i]; 89 | var to = ["a", "b"]; 90 | 91 | action(from, to); 92 | to.add("b"); 93 | to.add("c"); 94 | 95 | count++; 96 | } 97 | elapsed = watch.elapsedMilliseconds; 98 | } while (elapsed < trialMs); 99 | 100 | return count / elapsed; 101 | } 102 | 103 | void iterate(List from, List to) { 104 | for (var e in from) { 105 | to.add(e); 106 | } 107 | } 108 | 109 | void addList(List from, List to) { 110 | var length = from.length; 111 | for (var i = 0; i < length; i++) { 112 | to.add(from[i]); 113 | } 114 | } 115 | 116 | void resizeAndSet(List from, List to) { 117 | var length = from.length; 118 | var j = to.length; 119 | to.length = to.length + length; 120 | for (var i = 0; i < length; i++) { 121 | to[j] = from[i]; 122 | } 123 | } 124 | 125 | void addAll(List from, List to) { 126 | to.addAll(from); 127 | } 128 | 129 | void forEach(List from, List to) { 130 | List? temp = to; 131 | from.forEach((s) { 132 | temp!.add(s); 133 | }); 134 | temp = null; 135 | } 136 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/benchmarks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: benchmarks 2 | publish_to: none 3 | environment: 4 | sdk: ">=2.12.0 <3.0.0" 5 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/examples/postfix-ellipses/other.dart: -------------------------------------------------------------------------------- 1 | // flutter/packages/flutter/test/services/message_codecs_test.dart 2 | _checkEncoding( 3 | standard, 4 | Uint8List(253), 5 | [8, 253, List.filled(253, 0)...], 6 | ); 7 | 8 | // flutter/packages/flutter_driver/lib/src/common/find.dart 9 | Map serialize() => { 10 | super.serialize()..., 11 | 'text': text, 12 | }; 13 | 14 | // packages/angel_framework-1.1.5+1/lib/src/core/service.dart 15 | post( 16 | '/:id', 17 | (RequestContext req, res) => req.lazyBody().then((body) => this.update( 18 | toId(req.params['id']), 19 | body, 20 | { 21 | 'query': req.query, 22 | restProvider..., 23 | req.serviceParams... 24 | })), 25 | middleware: [ 26 | handlers..., 27 | updateMiddleware?.handlers...? 28 | ]); 29 | 30 | // packages/aqueduct-3.0.1/lib/src/db/schema/schema_table.dart 31 | var diffs = [ 32 | _differingColumns.expand((diff) => diff.errorMessages)..., 33 | uniqueSetDifference?.errorMessages...? 34 | ]; 35 | 36 | // packages/aqueduct-3.0.1/test/auth/auth_code_controller_test.dart: 37 | var m = {form..., "response_type": "code"}; 38 | 39 | // packages/aws_client-0.1.2/lib/src/request.dart 40 | String canonical = [ 41 | method.toUpperCase(), 42 | uri.path, 43 | canonicalQuery, 44 | canonicalHeaders..., 45 | '', 46 | signedHeaders, 47 | payloadHash 48 | ].join('\n'); 49 | 50 | // packages/build_runner-0.10.2/lib/src/entrypoint/test.dart 51 | var outputMap = {options.outputMap...?, tempPath: null}; 52 | 53 | // packages/build_web_compilers-0.4.3+1/lib/src/dart2js_bootstrap.dart 54 | args = [ 55 | dart2JsArgs..., 56 | '--packages=$packageFile', 57 | '-o$jsOutputPath', 58 | dartPath, 59 | _shouldAddNoSyncAsyncFlag(enableSyncAsync) ? ['--no-sync-async'] : []... 60 | ]; 61 | 62 | // packages/dartdoc-0.21.1/lib/src/model.dart 63 | _allInstanceProperties = [ 64 | instanceProperties.toList()..sort(byName)..., 65 | inheritedProperties.toList()..sort(byName)..., 66 | ] 67 | 68 | // packages/dartis-0.2.0/lib/src/command/commands.dart 69 | Future geoadd(K key, 70 | {GeoItem item, Iterable> items = const []}) => 71 | run([ 72 | r'GEOADD', 73 | key, 74 | _expandGeoItem(item)..., 75 | items.expand(_expandGeoItem)... 76 | ]); 77 | 78 | // packages/dartis-0.2.0/lib/src/command/commands.dart 79 | return run([ 80 | r'SORT', 81 | key, 82 | by == null ? null : r'BY', 83 | by, 84 | offset == null ? null : r'LIMIT', 85 | offset, 86 | count, 87 | get.expand((pattern) => [r'GET', pattern])..., 88 | order?.name, 89 | alpha ? r'ALPHA' : null, 90 | r'STORE', 91 | destination 92 | ]; 93 | 94 | // packages/sass-1.14.0/lib/src/executable/watch.dart 95 | var directoriesToWatch = [ 96 | options.sourceDirectoriesToDestinations.keys..., 97 | options.sourcesToDestinations.keys.map(p.dirname)..., 98 | options.loadPaths... 99 | ]; 100 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/examples/prefix-ellipses/other.dart: -------------------------------------------------------------------------------- 1 | // flutter/packages/flutter/test/services/message_codecs_test.dart 2 | _checkEncoding( 3 | standard, 4 | Uint8List(253), 5 | [8, 253, ...List.filled(253, 0)], 6 | ); 7 | 8 | // flutter/packages/flutter_driver/lib/src/common/find.dart 9 | Map serialize() => { 10 | ...super.serialize(), 11 | 'text': text, 12 | }; 13 | 14 | // packages/angel_framework-1.1.5+1/lib/src/core/service.dart 15 | post( 16 | '/:id', 17 | (RequestContext req, res) => req.lazyBody().then((body) => this.update( 18 | toId(req.params['id']), 19 | body, 20 | { 21 | 'query': req.query, 22 | ...restProvider, 23 | ...req.serviceParams 24 | })), 25 | middleware: [ 26 | ...handlers, 27 | ...?updateMiddleware?.handlers 28 | ]); 29 | 30 | // packages/aqueduct-3.0.1/lib/src/db/schema/schema_table.dart 31 | var diffs = [ 32 | ..._differingColumns.expand((diff) => diff.errorMessages), 33 | ...?uniqueSetDifference?.errorMessages 34 | ]; 35 | 36 | // packages/aqueduct-3.0.1/test/auth/auth_code_controller_test.dart: 37 | var m = {...form, "response_type": "code"}; 38 | 39 | // packages/aws_client-0.1.2/lib/src/request.dart 40 | String canonical = [ 41 | method.toUpperCase(), 42 | uri.path, 43 | canonicalQuery, 44 | ...canonicalHeaders, 45 | '', 46 | signedHeaders, 47 | payloadHash 48 | ].join('\n'); 49 | 50 | // packages/build_runner-0.10.2/lib/src/entrypoint/test.dart 51 | var outputMap = {...?options.outputMap, tempPath: null}; 52 | 53 | // packages/build_web_compilers-0.4.3+1/lib/src/dart2js_bootstrap.dart 54 | args = [ 55 | ...dart2JsArgs, 56 | '--packages=$packageFile', 57 | '-o$jsOutputPath', 58 | dartPath, 59 | ..._shouldAddNoSyncAsyncFlag(enableSyncAsync) ? ['--no-sync-async'] : [] 60 | ]; 61 | 62 | // packages/dartdoc-0.21.1/lib/src/model.dart 63 | _allInstanceProperties = [ 64 | ...instanceProperties.toList()..sort(byName), 65 | ...inheritedProperties.toList()..sort(byName), 66 | ] 67 | 68 | // packages/dartis-0.2.0/lib/src/command/commands.dart 69 | Future geoadd(K key, 70 | {GeoItem item, Iterable> items = const []}) => 71 | run([ 72 | r'GEOADD', 73 | key, 74 | ..._expandGeoItem(item), 75 | ...items.expand(_expandGeoItem) 76 | ]); 77 | 78 | // packages/dartis-0.2.0/lib/src/command/commands.dart 79 | return run([ 80 | r'SORT', 81 | key, 82 | by == null ? null : r'BY', 83 | by, 84 | offset == null ? null : r'LIMIT', 85 | offset, 86 | count, 87 | ...get.expand((pattern) => [r'GET', pattern]), 88 | order?.name, 89 | alpha ? r'ALPHA' : null, 90 | r'STORE', 91 | destination 92 | ]; 93 | 94 | // packages/sass-1.14.0/lib/src/executable/watch.dart 95 | var directoriesToWatch = [ 96 | ...options.sourceDirectoriesToDestinations.keys, 97 | ...options.sourcesToDestinations.keys.map(p.dirname), 98 | ...options.loadPaths 99 | ]; 100 | -------------------------------------------------------------------------------- /accepted/2.3/spread-collections/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for "Spread Collections" 2 | 3 | Owner: rnystrom@google.com ([@munificent](https://github.com/munificent/) on GitHub) 4 | 5 | Relevant links: 6 | 7 | * [Tracking issue](https://github.com/dart-lang/language/issues/47) 8 | * [Proposal](https://github.com/dart-lang/language/blob/master/accepted/2.3/spread-collections/feature-specification.md) 9 | 10 | ## Phase 0 (Prerequisite) 11 | 12 | ### "spread-collections" Experimental flag 13 | 14 | The implementation of this feature should be hidden behind an [experiment 15 | flag][]. Tools must be passed the flag `--enable-experiment=spread-collections` 16 | to enable the feature. 17 | 18 | [experiment flag]: https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md 19 | 20 | While this feature is under development, individual tools may have incomplete or 21 | changing implementations behind the flag. When all tools have completely 22 | implemented the feature, the the feature will be enabled by default, and the 23 | flag removed in a stable release. 24 | 25 | ### Tests 26 | 27 | The language team adds tests for the feature. 28 | 29 | ## Phase 1 (Foundation) 30 | 31 | ### CFE 32 | 33 | The CFE implements parsing the new syntax, type checking it, and compiling it to 34 | Kernel. Since the CFE will be implementing constant evaluation, it also 35 | implements evaluating `...` in constant collections. 36 | 37 | This feature can likely be implemented entirely in the front end, so back-end 38 | support may not be needed. If it does require Kernel changes, the back end will 39 | need to handle those changes. 40 | 41 | ### Analyzer 42 | 43 | The analyzer implements parsing the new syntax, type checking it, and 44 | evaluating `...` in constant collections. 45 | 46 | ## Phase 2 (Tool Implementation) 47 | 48 | ### dart2js 49 | 50 | If the feature is handled by the front end, there may be no dart2js work. 51 | Otherwise, dart2js may need to handle any Kernel changes or otherwise add 52 | support for this. 53 | 54 | ### Dartfmt 55 | 56 | Define and implement formatting rules for the new syntax. Add formatting tests. 57 | 58 | ### DDC 59 | 60 | If this feature can be implemented entirely in the front end with no Kernel 61 | changes, and DDC is entirely onto the CFE, then no DDC changes may be needed. 62 | Otherwise, DDC may need to handle any Kernel changes or otherwise add support 63 | for this. 64 | 65 | DDC may need to support canonicalizing constant collections with spread 66 | operators. 67 | 68 | ### IntelliJ 69 | 70 | Update the IntelliJ parser to handle the new syntax (this has some lead time, 71 | so needs to be done early). 72 | 73 | ### Analyzer / analysis server 74 | 75 | There a are a handful of usability features that would be nice: 76 | 77 | * Add a "quick fix" to turn common idioms into uses of the spread operator 78 | like: 79 | 80 | ```dart 81 | [a, b]..addAll(c)..add(d); 82 | 83 | // Into: 84 | [a, b, ...c, d] 85 | ``` 86 | 87 | Depending on how dartfix is coming along, this could be added to that. 88 | 89 | * Auto-complete should gracefully handle the user typing `...` inside a 90 | collection literal if it doesn't already. 91 | 92 | * Good error messages if a user tries to use `...` outside of a collection 93 | literal, explaining where the syntax is allowed. 94 | 95 | ### dartfix 96 | 97 | Possibly, expose the quick fix from above. 98 | 99 | ### linter 100 | 101 | Add a lint rule (`prefer_spread_operators`?), corresponding to the analyzer 102 | code assist that flags opportunities to use spreads. 103 | 104 | ### VM 105 | 106 | If the feature is handled by the front end, there may be no VM work. Otherwise, 107 | the VM may need to handle any Kernel changes or otherwise add support for this. 108 | 109 | ### Co19 tests 110 | 111 | The co19 team can start implementing tests early using the experimental flag. 112 | Those tests should not be run by default until the feature has been released. 113 | 114 | ## Phase 3 (Release) 115 | 116 | ### Enabling 117 | 118 | The language team updates the experimental flag `spread-collections` to always 119 | be enabled and no longer be available to users, and releases this update in the 120 | next stable Dart release. 121 | 122 | ### Use 123 | 124 | The Dart team refactors existing code in the SDK and team-maintained packages 125 | to use the new syntax where appropriate. 126 | 127 | ### Documentation 128 | 129 | The language team adds the feature to the CHANGELOG. They write some sort of 130 | announcement email or blog post. 131 | 132 | ## Phase 4 (Clean-up) 133 | 134 | ### Remove flag 135 | 136 | All tools may now remove the dependencies on the flag in the experiments flag 137 | definition file. When all SDK tools have done so, the flag is removed from the 138 | experiments flag definition file. 139 | 140 | ## Timeline 141 | 142 | Completion goals for the phases: 143 | 144 | * Phase 0 (Prerequisite): TODO 145 | * Phase 1 (Foundation): TODO 146 | * Phase 2 (Tool Implementation): TODO 147 | * Phase 3 (Release): TODO 148 | * Phase 4 (Clean-up): TODO 149 | -------------------------------------------------------------------------------- /accepted/2.5/constant-update-2018/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for the Q4 2018 Constant Update 2 | 3 | Relevant documents: 4 | - [Tracking issue](https://github.com/dart-lang/language/issues/60) 5 | - [Full proposal](https://github.com/dart-lang/language/blob/master/accepted/2.5/constant-update-2018/feature-specification.md) 6 | 7 | ## Implementation and Release plan 8 | 9 | ### Release flags 10 | 11 | The implementation of these changes must happen behind an [*experiments flag*](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md). 12 | Tools need to be passed the flag `--enable-experiment=constant-update-2018` 13 | for the changes to be enabled. 14 | 15 | The `--enable-experiment` option takes a comma separated list of names of experiments 16 | to enable, and the option can be passed multiple times to a tool, 17 | enabling any experiment mentioned in any of the option arguments. 18 | 19 | The list of available flags at any time is defined by a 20 | `.dart` experiments flag definition file (location and exact content TBD). 21 | The file lists flags that are currently available to users, 22 | as well as some prior flags that are now enabled by default and not available 23 | to users. 24 | 25 | While developing, individual tools may have incomplete implementations behind the flag. 26 | When all tools have completely implemented the feature, 27 | the feature will be enabled, and the flag removed, in a stable release. 28 | 29 | 30 | ### Phase 0 (Prerequisite) 31 | 32 | All tools add support for experimental flags, if not yet supported. 33 | Tools must refuse to run if supplied with unsupported experimental flags. 34 | 35 | Projects embedded in other tools, like the Common Front-end (CFE) embedded in the VM or dart2js, 36 | must be able to receive experimental flags programmatically from the embedder, 37 | which can then accept them on the command line. 38 | 39 | #### Tests 40 | 41 | The language team adds tests for the new syntax. 42 | 43 | ### Phase 1 (Implementation) 44 | 45 | #### Analyzer and CFE 46 | The analyzer and CFE implements support for the new constant and potentially constant expressions 47 | behind the experimental flag. 48 | 49 | The CFE plans to implement constant evaluation itself, rather than deferring it to the 50 | backends. The new constant features will be included in this implementation, 51 | so back-ends should not need to implement the new behavior. 52 | 53 | If the implementation requires changes to the Kernel format, then backends may need to adapt to that, 54 | just as with any other Kernel format change. 55 | 56 | #### Intellij/Grok/Dartfmt 57 | 58 | Support for the new constant expressions is added to the relevant tooling. 59 | 60 | It is very likely that no changes are needed here, 61 | as long as the analyzer supports the new expressions. 62 | All the affected expressions are already valid non-constant expressions. 63 | 64 | #### Co19 tests 65 | 66 | The co19 team can start implementing tests early using the experimental 67 | flag. 68 | Those tests should not be tested by default by the Dart SDK until the 69 | feature has been released. 70 | 71 | ### Phase 2 (Release) 72 | 73 | #### Language team 74 | 75 | The language team updates the experimental flag `const-update-2018` to 76 | always be enabled and no longer be available to users, and releases 77 | This update is released as part of the next stable Dart release. 78 | 79 | ### Phase 3 (Clean-up) 80 | 81 | All tools may now remove the dependencies on the flag in 82 | the experiments flag definition file. 83 | 84 | When all SDK tools have done so, 85 | the flag is removed from the experiments flag definition file. 86 | 87 | ## Timeline 88 | 89 | Completion goals for the phases: 90 | 91 | - Phase 0: Mid November 2018 92 | - Phase 1: Early December 2018 93 | - Phase 2: Mid December 2018 94 | - Phase 3: Q1 2019 95 | -------------------------------------------------------------------------------- /accepted/2.5/contravariant-superinterface-2018/feature-specification.md: -------------------------------------------------------------------------------- 1 | # A Non-Covariant Type Variable in a Superinterface is an Error. 2 | 3 | Author: eernst@google.com (@eernstg) 4 | 5 | Version: 0.1. 6 | 7 | ## Motivation and Scope 8 | 9 | The ability to use a type variable contravariantly in a superinterface of a 10 | generic class creates an "anti-parallel" subtype relationship for a given 11 | class and a direct superinterface thereof, and the same thing can happen 12 | indirectly in many ways. This creates various complications for the static 13 | analysis and the enforcement of the heap invariant (aka soundness), as 14 | illustrated below. Similar complications arise in the invariant 15 | case. Hence, this feature makes all non-covariant usages of a type variable 16 | in a superinterface a compile-time error. 17 | 18 | Here is an example: 19 | 20 | ```dart 21 | class A { 22 | X x; 23 | A(this.x); 24 | } 25 | 26 | class B extends A { 27 | B(void Function(X) f): super(f); 28 | } 29 | 30 | main() { 31 | // Upcast: `B <: B` by class covariance. 32 | B b = B((int i) => print(i.runtimeType)); 33 | // Upcast: `B <: A` by `extends` clause. 34 | A a = b; 35 | // Upcast: `A <: A` 36 | // by class covariance, plus `double <: num` and `void <: void`. 37 | a.x(3.14); 38 | } 39 | ``` 40 | 41 | Every assignment in `main` involves an upcast, so there are no downcasts at 42 | all and the program should be safe. However, execution fails at `a.x(3.14)` 43 | because we are passing an actual argument of type `double` to a function 44 | whose corresponding parameter type is `int`. 45 | 46 | Note that the heap invariant is violated during execution at the point 47 | where `a` is initialized, even though the program has no error according 48 | to the existing rules (before the inclusion of this feature). 49 | 50 | The underlying issue is that the contravariant usage of a type variable in 51 | a superinterface creates a twisted subtype lattice where `B` "goes in one 52 | direction" (`B <: B`) and the superinterface `A` "goes in the 53 | opposite direction" (`A` is a direct superinterface of 54 | `B` and `A` is a direct superinterface of 55 | `B`, but we have `A <: A` 56 | rather than the opposite): 57 | 58 | ```dart 59 | A :> A 60 | ^ ^ 61 | | | 62 | | | 63 | B <: B 64 | ``` 65 | 66 | We typically have a "parallel" subtype relationship: 67 | 68 | ```dart 69 | Iterable <: Iterable 70 | ^ ^ 71 | | | 72 | | | 73 | List <: List 74 | ``` 75 | 76 | But with the example above we have an "anti-parallel" relationship, and 77 | that creates the opportunity to have a series of upcasts that takes us from 78 | `int` to `double` in part of the type without ever seeing a discrepancy 79 | (because we can just as well go up to `A` in the 80 | last step rather than `A`). 81 | 82 | With such scenarios in mind, this feature amounts to adding a new 83 | compile-time error, as specified below. 84 | 85 | 86 | ## Static Analysis 87 | 88 | Let `C` be a generic class that declares a formal type parameter `X`, and 89 | assume that `T` is a direct superinterface of `C`. It is a compile-time 90 | error if `X` occurs contravariantly or invariantly in `T`. 91 | 92 | 93 | ## Dynamic Semantics 94 | 95 | There is no dynamic semantics associated with this feature. 96 | 97 | 98 | ## Revisions 99 | 100 | * Version 0.1, Nov 29 2018: Initial version. 101 | -------------------------------------------------------------------------------- /accepted/2.5/contravariant-superinterface-2018/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for the Q1 2019 Superinterface Contravariance Error. 2 | 3 | Relevant documents: 4 | - [Tracking issue](https://github.com/dart-lang/language/issues/113) 5 | - [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/2.5/contravariant-superinterface-2018/feature-specification.md) 6 | 7 | 8 | ## Implementation and Release plan 9 | 10 | This feature is concerned with the introduction of one extra compile-time 11 | error, and the breakage has been estimated to be very low. 12 | Still, we will use an 13 | [experiments flag](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md) 14 | in order to enable a controlled deployment. 15 | 16 | 17 | ### Phase 0 (Release flag) 18 | 19 | In this phase every tool adds support for an experiments flag: The flag 20 | `--enable-experiment=covariant-only-superinterfaces` must be passed for the 21 | changes to be enabled. 22 | 23 | 24 | ### Phase 1 (Implementation) 25 | 26 | All tools add the implementation of the associated compile-time check, and 27 | start emitting the new error during static analysis if the experimental flag 28 | is supplied. 29 | 30 | 31 | ### Phase 2 (Release) 32 | 33 | A single commit removes the experimental flag from all implementations, 34 | causing them all to start emitting the new error during static analysis under 35 | normal execution. The update is released as part of the next stable Dart release. 36 | 37 | 38 | ## Timeline 39 | 40 | Completion goals for the phases: 41 | 42 | - Phase 0: Q1 2019 43 | - Phase 1: Q1 2019 44 | - Phase 2: Q1 2019 45 | -------------------------------------------------------------------------------- /accepted/README.md: -------------------------------------------------------------------------------- 1 | # Accepted language features 2 | 3 | This directory holds feature specifications, implementation plan documents, etc. 4 | for accepted Dart language changes. 5 | 6 | For the full Dart Language Specification, please see our homepage: 7 | https://dart.dev/guides/language/spec 8 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/3.0/patterns/exhaustiveness.md 4 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/README.md: -------------------------------------------------------------------------------- 1 | This is a prototype implementation of the exhaustiveness checking algorithm. 2 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | linter: 3 | rules: 4 | - avoid_null_checks_in_equality_operators 5 | - avoid_unused_constructor_parameters 6 | - await_only_futures 7 | - camel_case_types 8 | - cancel_subscriptions 9 | - comment_references 10 | - constant_identifier_names 11 | - control_flow_in_finally 12 | - directives_ordering 13 | - empty_statements 14 | - hash_and_equals 15 | - implementation_imports 16 | - collection_methods_unrelated_type 17 | - library_names 18 | - library_prefixes 19 | - non_constant_identifier_names 20 | - overridden_fields 21 | - package_api_docs 22 | - package_names 23 | - package_prefixed_library_names 24 | - prefer_final_fields 25 | - prefer_generic_function_type_aliases 26 | - prefer_typing_uninitialized_variables 27 | - test_types_in_equals 28 | - throw_in_finally 29 | - unnecessary_brace_in_string_interps 30 | - unrelated_type_equality_checks 31 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/benchmark/large_fields_call_counts.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/exhaustive.dart'; 5 | import 'package:exhaustiveness_prototype/profile.dart' as profile; 6 | import 'package:exhaustiveness_prototype/space.dart'; 7 | import 'package:exhaustiveness_prototype/static_type.dart'; 8 | 9 | import '../test/utils.dart'; 10 | 11 | void main() { 12 | profile.enabled = true; 13 | 14 | // (A) 15 | // /|\ 16 | // B C D 17 | var a = StaticType('A', isSealed: true); 18 | var b = StaticType('B', inherits: [a]); 19 | var c = StaticType('C', inherits: [a]); 20 | var d = StaticType('D', inherits: [a]); 21 | var t = StaticType('T', fields: {'w': a, 'x': a, 'y': a, 'z': a}); 22 | 23 | expectExhaustiveOnlyAll(t, [ 24 | {'w': b, 'x': b, 'y': b, 'z': b}, 25 | {'w': b, 'x': b, 'y': b, 'z': c}, 26 | {'w': b, 'x': b, 'y': b, 'z': d}, 27 | {'w': b, 'x': b, 'y': c, 'z': b}, 28 | {'w': b, 'x': b, 'y': c, 'z': c}, 29 | {'w': b, 'x': b, 'y': c, 'z': d}, 30 | {'w': b, 'x': b, 'y': d, 'z': b}, 31 | {'w': b, 'x': b, 'y': d, 'z': c}, 32 | {'w': b, 'x': b, 'y': d, 'z': d}, 33 | {'w': b, 'x': c, 'y': b, 'z': b}, 34 | {'w': b, 'x': c, 'y': b, 'z': c}, 35 | {'w': b, 'x': c, 'y': b, 'z': d}, 36 | {'w': b, 'x': c, 'y': c, 'z': b}, 37 | {'w': b, 'x': c, 'y': c, 'z': c}, 38 | {'w': b, 'x': c, 'y': c, 'z': d}, 39 | {'w': b, 'x': c, 'y': d, 'z': b}, 40 | {'w': b, 'x': c, 'y': d, 'z': c}, 41 | {'w': b, 'x': c, 'y': d, 'z': d}, 42 | {'w': b, 'x': d, 'y': b, 'z': b}, 43 | {'w': b, 'x': d, 'y': b, 'z': c}, 44 | {'w': b, 'x': d, 'y': b, 'z': d}, 45 | {'w': b, 'x': d, 'y': c, 'z': b}, 46 | {'w': b, 'x': d, 'y': c, 'z': c}, 47 | {'w': b, 'x': d, 'y': c, 'z': d}, 48 | {'w': b, 'x': d, 'y': d, 'z': b}, 49 | {'w': b, 'x': d, 'y': d, 'z': c}, 50 | {'w': b, 'x': d, 'y': d, 'z': d}, 51 | {'w': c, 'x': b, 'y': b, 'z': b}, 52 | {'w': c, 'x': b, 'y': b, 'z': c}, 53 | {'w': c, 'x': b, 'y': b, 'z': d}, 54 | {'w': c, 'x': b, 'y': c, 'z': b}, 55 | {'w': c, 'x': b, 'y': c, 'z': c}, 56 | {'w': c, 'x': b, 'y': c, 'z': d}, 57 | {'w': c, 'x': b, 'y': d, 'z': b}, 58 | {'w': c, 'x': b, 'y': d, 'z': c}, 59 | {'w': c, 'x': b, 'y': d, 'z': d}, 60 | {'w': c, 'x': c, 'y': b, 'z': b}, 61 | {'w': c, 'x': c, 'y': b, 'z': c}, 62 | {'w': c, 'x': c, 'y': b, 'z': d}, 63 | {'w': c, 'x': c, 'y': c, 'z': b}, 64 | {'w': c, 'x': c, 'y': c, 'z': c}, 65 | {'w': c, 'x': c, 'y': c, 'z': d}, 66 | {'w': c, 'x': c, 'y': d, 'z': b}, 67 | {'w': c, 'x': c, 'y': d, 'z': c}, 68 | {'w': c, 'x': c, 'y': d, 'z': d}, 69 | {'w': c, 'x': d, 'y': b, 'z': b}, 70 | {'w': c, 'x': d, 'y': b, 'z': c}, 71 | {'w': c, 'x': d, 'y': b, 'z': d}, 72 | {'w': c, 'x': d, 'y': c, 'z': b}, 73 | {'w': c, 'x': d, 'y': c, 'z': c}, 74 | {'w': c, 'x': d, 'y': c, 'z': d}, 75 | {'w': c, 'x': d, 'y': d, 'z': b}, 76 | {'w': c, 'x': d, 'y': d, 'z': c}, 77 | {'w': c, 'x': d, 'y': d, 'z': d}, 78 | {'w': d, 'x': b, 'y': b, 'z': b}, 79 | {'w': d, 'x': b, 'y': b, 'z': c}, 80 | {'w': d, 'x': b, 'y': b, 'z': d}, 81 | {'w': d, 'x': b, 'y': c, 'z': b}, 82 | {'w': d, 'x': b, 'y': c, 'z': c}, 83 | {'w': d, 'x': b, 'y': c, 'z': d}, 84 | {'w': d, 'x': b, 'y': d, 'z': b}, 85 | {'w': d, 'x': b, 'y': d, 'z': c}, 86 | {'w': d, 'x': b, 'y': d, 'z': d}, 87 | {'w': d, 'x': c, 'y': b, 'z': b}, 88 | {'w': d, 'x': c, 'y': b, 'z': c}, 89 | {'w': d, 'x': c, 'y': b, 'z': d}, 90 | {'w': d, 'x': c, 'y': c, 'z': b}, 91 | {'w': d, 'x': c, 'y': c, 'z': c}, 92 | {'w': d, 'x': c, 'y': c, 'z': d}, 93 | {'w': d, 'x': c, 'y': d, 'z': b}, 94 | {'w': d, 'x': c, 'y': d, 'z': c}, 95 | {'w': d, 'x': c, 'y': d, 'z': d}, 96 | {'w': d, 'x': d, 'y': b, 'z': b}, 97 | {'w': d, 'x': d, 'y': b, 'z': c}, 98 | {'w': d, 'x': d, 'y': b, 'z': d}, 99 | {'w': d, 'x': d, 'y': c, 'z': b}, 100 | {'w': d, 'x': d, 'y': c, 'z': c}, 101 | {'w': d, 'x': d, 'y': c, 'z': d}, 102 | {'w': d, 'x': d, 'y': d, 'z': b}, 103 | {'w': d, 'x': d, 'y': d, 'z': c}, 104 | {'w': d, 'x': d, 'y': d, 'z': d}, 105 | ]); 106 | } 107 | 108 | /// Test that [cases] are exhaustive over [type] if and only if all cases are 109 | /// included and that all subsets of the cases are not exhaustive. 110 | void expectExhaustiveOnlyAll(StaticType type, List cases) { 111 | var spaces = parseSpaces(cases); 112 | profile.reset(); 113 | print(isExhaustive(Space(type), spaces)); 114 | profile.log(); 115 | } 116 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/benchmark/large_fields_timed.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'dart:math'; 5 | 6 | import 'package:exhaustiveness_prototype/exhaustive.dart'; 7 | import 'package:exhaustiveness_prototype/space.dart'; 8 | import 'package:exhaustiveness_prototype/static_type.dart'; 9 | 10 | import '../test/utils.dart'; 11 | 12 | void main() { 13 | // (A) 14 | // /|\ 15 | // B C D 16 | var a = StaticType('A', isSealed: true); 17 | var b = StaticType('B', inherits: [a]); 18 | var c = StaticType('C', inherits: [a]); 19 | var d = StaticType('D', inherits: [a]); 20 | var t = StaticType('T', fields: {'w': a, 'x': a, 'y': a, 'z': a}); 21 | 22 | expectExhaustiveOnlyAll(t, [ 23 | {'w': b, 'x': b, 'y': b, 'z': b}, 24 | {'w': b, 'x': b, 'y': b, 'z': c}, 25 | {'w': b, 'x': b, 'y': b, 'z': d}, 26 | {'w': b, 'x': b, 'y': c, 'z': b}, 27 | {'w': b, 'x': b, 'y': c, 'z': c}, 28 | {'w': b, 'x': b, 'y': c, 'z': d}, 29 | {'w': b, 'x': b, 'y': d, 'z': b}, 30 | {'w': b, 'x': b, 'y': d, 'z': c}, 31 | {'w': b, 'x': b, 'y': d, 'z': d}, 32 | {'w': b, 'x': c, 'y': b, 'z': b}, 33 | {'w': b, 'x': c, 'y': b, 'z': c}, 34 | {'w': b, 'x': c, 'y': b, 'z': d}, 35 | {'w': b, 'x': c, 'y': c, 'z': b}, 36 | {'w': b, 'x': c, 'y': c, 'z': c}, 37 | {'w': b, 'x': c, 'y': c, 'z': d}, 38 | {'w': b, 'x': c, 'y': d, 'z': b}, 39 | {'w': b, 'x': c, 'y': d, 'z': c}, 40 | {'w': b, 'x': c, 'y': d, 'z': d}, 41 | {'w': b, 'x': d, 'y': b, 'z': b}, 42 | {'w': b, 'x': d, 'y': b, 'z': c}, 43 | {'w': b, 'x': d, 'y': b, 'z': d}, 44 | {'w': b, 'x': d, 'y': c, 'z': b}, 45 | {'w': b, 'x': d, 'y': c, 'z': c}, 46 | {'w': b, 'x': d, 'y': c, 'z': d}, 47 | {'w': b, 'x': d, 'y': d, 'z': b}, 48 | {'w': b, 'x': d, 'y': d, 'z': c}, 49 | {'w': b, 'x': d, 'y': d, 'z': d}, 50 | {'w': c, 'x': b, 'y': b, 'z': b}, 51 | {'w': c, 'x': b, 'y': b, 'z': c}, 52 | {'w': c, 'x': b, 'y': b, 'z': d}, 53 | {'w': c, 'x': b, 'y': c, 'z': b}, 54 | {'w': c, 'x': b, 'y': c, 'z': c}, 55 | {'w': c, 'x': b, 'y': c, 'z': d}, 56 | {'w': c, 'x': b, 'y': d, 'z': b}, 57 | {'w': c, 'x': b, 'y': d, 'z': c}, 58 | {'w': c, 'x': b, 'y': d, 'z': d}, 59 | {'w': c, 'x': c, 'y': b, 'z': b}, 60 | {'w': c, 'x': c, 'y': b, 'z': c}, 61 | {'w': c, 'x': c, 'y': b, 'z': d}, 62 | {'w': c, 'x': c, 'y': c, 'z': b}, 63 | {'w': c, 'x': c, 'y': c, 'z': c}, 64 | {'w': c, 'x': c, 'y': c, 'z': d}, 65 | {'w': c, 'x': c, 'y': d, 'z': b}, 66 | {'w': c, 'x': c, 'y': d, 'z': c}, 67 | {'w': c, 'x': c, 'y': d, 'z': d}, 68 | {'w': c, 'x': d, 'y': b, 'z': b}, 69 | {'w': c, 'x': d, 'y': b, 'z': c}, 70 | {'w': c, 'x': d, 'y': b, 'z': d}, 71 | {'w': c, 'x': d, 'y': c, 'z': b}, 72 | {'w': c, 'x': d, 'y': c, 'z': c}, 73 | {'w': c, 'x': d, 'y': c, 'z': d}, 74 | {'w': c, 'x': d, 'y': d, 'z': b}, 75 | {'w': c, 'x': d, 'y': d, 'z': c}, 76 | {'w': c, 'x': d, 'y': d, 'z': d}, 77 | {'w': d, 'x': b, 'y': b, 'z': b}, 78 | {'w': d, 'x': b, 'y': b, 'z': c}, 79 | {'w': d, 'x': b, 'y': b, 'z': d}, 80 | {'w': d, 'x': b, 'y': c, 'z': b}, 81 | {'w': d, 'x': b, 'y': c, 'z': c}, 82 | {'w': d, 'x': b, 'y': c, 'z': d}, 83 | {'w': d, 'x': b, 'y': d, 'z': b}, 84 | {'w': d, 'x': b, 'y': d, 'z': c}, 85 | {'w': d, 'x': b, 'y': d, 'z': d}, 86 | {'w': d, 'x': c, 'y': b, 'z': b}, 87 | {'w': d, 'x': c, 'y': b, 'z': c}, 88 | {'w': d, 'x': c, 'y': b, 'z': d}, 89 | {'w': d, 'x': c, 'y': c, 'z': b}, 90 | {'w': d, 'x': c, 'y': c, 'z': c}, 91 | {'w': d, 'x': c, 'y': c, 'z': d}, 92 | {'w': d, 'x': c, 'y': d, 'z': b}, 93 | {'w': d, 'x': c, 'y': d, 'z': c}, 94 | {'w': d, 'x': c, 'y': d, 'z': d}, 95 | {'w': d, 'x': d, 'y': b, 'z': b}, 96 | {'w': d, 'x': d, 'y': b, 'z': c}, 97 | {'w': d, 'x': d, 'y': b, 'z': d}, 98 | {'w': d, 'x': d, 'y': c, 'z': b}, 99 | {'w': d, 'x': d, 'y': c, 'z': c}, 100 | {'w': d, 'x': d, 'y': c, 'z': d}, 101 | {'w': d, 'x': d, 'y': d, 'z': b}, 102 | {'w': d, 'x': d, 'y': d, 'z': c}, 103 | {'w': d, 'x': d, 'y': d, 'z': d}, 104 | ]); 105 | } 106 | 107 | /// Test that [cases] are exhaustive over [type] if and only if all cases are 108 | /// included and that all subsets of the cases are not exhaustive. 109 | void expectExhaustiveOnlyAll(StaticType type, List cases) { 110 | const trials = 100; 111 | 112 | var best = 9999999; 113 | for (var j = 0; j < 100000; j++) { 114 | var watch = Stopwatch()..start(); 115 | for (var i = 0; i < trials; i++) { 116 | var spaces = parseSpaces(cases); 117 | var actual = isExhaustive(Space(type), spaces); 118 | if (!actual) { 119 | throw 'Expected exhaustive'; 120 | } 121 | } 122 | 123 | var elapsed = watch.elapsedMilliseconds; 124 | best = min(elapsed, best); 125 | print('${elapsed / trials}ms (best ${best / trials}ms)'); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/equal.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'profile.dart' as profile; 5 | import 'space.dart'; 6 | 7 | /// Returns `true` if [left] and [right] are equivalent spaces. 8 | /// 9 | /// Equality is defined purely structurally/syntactically. 10 | bool equal(Space left, Space right, String reason) { 11 | profile.count('equal', reason); 12 | 13 | if (identical(left, right)) return true; 14 | 15 | // Empty is only equal to itself (and will get caught by the previous check). 16 | if (left == Space.empty) return false; 17 | if (right == Space.empty) return false; 18 | 19 | if (left is UnionSpace && right is UnionSpace) { 20 | return _equalUnions(left, right); 21 | } 22 | 23 | if (left is ExtractSpace && right is ExtractSpace) { 24 | return _equalExtracts(left, right); 25 | } 26 | 27 | // If we get here, one is a union and one is an extract. 28 | return false; 29 | } 30 | 31 | /// Returns `true` if [left] and [right] contain equal arms in any order. 32 | /// 33 | /// Assumes that all duplicates have already been removed from each union. 34 | bool _equalUnions(UnionSpace left, UnionSpace right) { 35 | if (left.arms.length != right.arms.length) return false; 36 | 37 | /// For each left arm, should find an equal right arm. 38 | for (var leftArm in left.arms) { 39 | var found = false; 40 | for (var rightArm in right.arms) { 41 | if (equal(leftArm, rightArm, 'recurse union')) { 42 | found = true; 43 | break; 44 | } 45 | } 46 | if (!found) return false; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | /// Returns `true` if [left] and [right] have the same type and the same fields 53 | /// with equal subspaces. 54 | bool _equalExtracts(ExtractSpace left, ExtractSpace right) { 55 | // Must have the same type. 56 | if (left.type != right.type) return false; 57 | 58 | // And the same fields. 59 | var fields = {...left.fields.keys, ...right.fields.keys}; 60 | if (left.fields.length != fields.length) return false; 61 | if (right.fields.length != fields.length) return false; 62 | 63 | for (var field in fields) { 64 | if (!equal(left.fields[field]!, right.fields[field]!, 'recurse extract')) { 65 | return false; 66 | } 67 | } 68 | 69 | return true; 70 | } 71 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/exhaustive.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'space.dart'; 5 | import 'static_type.dart'; 6 | import 'subtract.dart'; 7 | 8 | /// Returns `true` if [cases] exhaustively covers all possible values of 9 | /// [value]. 10 | /// 11 | /// This is defined simply in terms of subtraction and unions: [cases] is a 12 | /// union space, and it's exhaustive if subtracting it from [value] leaves 13 | /// nothing. 14 | bool isExhaustive(Space value, List cases) { 15 | return subtract(value, Space.union(cases)) == Space.empty; 16 | } 17 | 18 | /// Checks the [cases] representing a series of switch cases to see if they 19 | /// exhaustively cover all possible values of the matched [valueType]. Also 20 | /// checks to see if any case can't be matched because it's covered by previous 21 | /// cases. 22 | /// 23 | /// Returns a string containing any unreachable case or non-exhaustive match 24 | /// errors. Returns an empty string if all cases are reachable and the cases 25 | /// are exhaustive. 26 | String reportErrors(StaticType valueType, List cases) { 27 | var errors = []; 28 | 29 | var remaining = Space(valueType); 30 | for (var i = 0; i < cases.length; i++) { 31 | // See if this case is covered by previous ones. 32 | if (i > 0) { 33 | var previous = Space.union(cases.sublist(0, i)); 34 | if (subtract(cases[i], previous) == Space.empty) { 35 | errors.add('Case #${i + 1} ${cases[i]} is covered by $previous.'); 36 | } 37 | } 38 | 39 | remaining = subtract(remaining, cases[i]); 40 | } 41 | 42 | if (remaining != Space.empty) { 43 | errors.add( 44 | '$valueType is not exhaustively matched by ${Space.union(cases)}.'); 45 | } 46 | 47 | return errors.join('\n'); 48 | } 49 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/intersect.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'profile.dart' as profile; 5 | import 'space.dart'; 6 | import 'static_type.dart'; 7 | 8 | /// Calculates the intersection of [left] and [right]. 9 | /// 10 | /// This is used to tell if two field spaces on a pair of spaces being 11 | /// subtracted have no common values. 12 | Space intersect(Space left, Space right) { 13 | profile.count('intersect'); 14 | 15 | // The intersection with an empty space is always empty. 16 | if (left == Space.empty) return Space.empty; 17 | if (right == Space.empty) return Space.empty; 18 | 19 | // The intersection of a union is the union of the intersections of its arms. 20 | if (left is UnionSpace) { 21 | return Space.union(left.arms.map((arm) => intersect(arm, right)).toList()); 22 | } 23 | 24 | if (right is UnionSpace) { 25 | return Space.union(right.arms.map((arm) => intersect(left, arm)).toList()); 26 | } 27 | 28 | // Otherwise, we're intersecting two [ExtractSpaces]. 29 | return _intersectExtracts(left as ExtractSpace, right as ExtractSpace); 30 | } 31 | 32 | /// Returns the interaction of extract spaces [left] and [right]. 33 | Space _intersectExtracts(ExtractSpace left, ExtractSpace right) { 34 | var type = intersectTypes(left.type, right.type); 35 | 36 | // If the types are disjoint, the intersection is empty. 37 | if (type == null) return Space.empty; 38 | 39 | // Recursively intersect the fields. 40 | var fieldNames = {...left.fields.keys, ...right.fields.keys}.toList(); 41 | 42 | // Sorting isn't needed for correctness, just to make the tests less brittle. 43 | fieldNames.sort(); 44 | 45 | var fields = {}; 46 | for (var name in fieldNames) { 47 | var field = _intersectFields(left.fields[name], right.fields[name]); 48 | 49 | // If the fields are disjoint, then the entire space will have no values. 50 | if (field == Space.empty) return Space.empty; 51 | fields[name] = field; 52 | } 53 | 54 | return Space(type, fields); 55 | } 56 | 57 | Space _intersectFields(Space? left, Space? right) { 58 | if (left == null) return right!; 59 | if (right == null) return left; 60 | return intersect(left, right); 61 | } 62 | 63 | /// Returns the intersection of two static types [left] and [right]. 64 | /// 65 | /// Returns `null` if the intersection is empty. 66 | StaticType? intersectTypes(StaticType left, StaticType right) { 67 | // If one type is a subtype, the subtype is the intersection. 68 | if (left.isSubtypeOf(right)) return left; 69 | if (right.isSubtypeOf(left)) return right; 70 | 71 | if (left.isNullable) { 72 | if (right.isNullable) { 73 | var intersection = intersectTypes(left.underlying, right.underlying); 74 | if (intersection == null) return null; 75 | return intersection.nullable; 76 | } else { 77 | return intersectTypes(left.underlying, right); 78 | } 79 | } else if (right.isNullable) { 80 | return intersectTypes(left, right.underlying); 81 | } 82 | 83 | // If we allow sealed types to share subtypes, then this will need to be more 84 | // sophisticated. Here: 85 | // 86 | // (A) (B) 87 | // / \ / \ 88 | // C D E 89 | // 90 | // The intersection of A and B should be D. Here: 91 | // 92 | // (A) (B) 93 | // | \ / | 94 | // |\ \/ /| 95 | // | \/\/ | 96 | // C D E F 97 | // 98 | // It should be D, E. 99 | 100 | // Unrelated types. 101 | return null; 102 | } 103 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/intersect_empty.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/static_type.dart'; 5 | 6 | import 'space.dart'; 7 | 8 | /// Calculates whether the intersection of [left] and [right] is empty. 9 | /// 10 | /// This is used to tell if two field spaces on a pair of spaces being 11 | /// subtracted have no common values. 12 | bool intersectEmpty(Space left, Space right) { 13 | // The intersection with an empty space is always empty. 14 | if (left == Space.empty) return true; 15 | if (right == Space.empty) return true; 16 | 17 | // The intersection of a union is empty if all of the arms are. 18 | if (left is UnionSpace) { 19 | return left.arms.every((arm) => intersectEmpty(arm, right)); 20 | } 21 | 22 | if (right is UnionSpace) { 23 | return right.arms.every((arm) => intersectEmpty(left, arm)); 24 | } 25 | 26 | // Otherwise, we're intersecting two [ExtractSpaces]. 27 | return _intersectExtracts(left as ExtractSpace, right as ExtractSpace); 28 | } 29 | 30 | /// Returns the interaction of extract spaces [left] and [right]. 31 | bool _intersectExtracts(ExtractSpace left, ExtractSpace right) { 32 | if (intersectTypes(left.type, right.type)) return true; 33 | 34 | // Recursively intersect the fields. 35 | var fieldNames = {...left.fields.keys, ...right.fields.keys}.toList(); 36 | for (var name in fieldNames) { 37 | // If the fields are disjoint, then the entire space will have no values. 38 | if (_intersectFields(left.fields[name], right.fields[name])) return true; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | bool _intersectFields(Space? left, Space? right) { 45 | if (left == null) return right! == Space.empty; 46 | if (right == null) return left == Space.empty; 47 | return intersectEmpty(left, right); 48 | } 49 | 50 | /// Returns true if the intersection of two static types [left] and [right] is 51 | /// empty. 52 | bool intersectTypes(StaticType left, StaticType right) { 53 | // If one type is a subtype, the subtype is the intersection. 54 | if (left.isSubtypeOf(right)) return false; 55 | if (right.isSubtypeOf(left)) return false; 56 | 57 | // Unrelated types. 58 | return true; 59 | } 60 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/profile.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:math'; 6 | 7 | var enabled = false; 8 | 9 | final _counts = {}; 10 | 11 | void count(String name, [String? subname]) { 12 | if (!enabled) return; 13 | _counts.putIfAbsent(name, () => 0); 14 | _counts[name] = _counts[name]! + 1; 15 | 16 | if (subname != null) { 17 | count('$name/$subname'); 18 | } 19 | } 20 | 21 | void run(void Function() callback) { 22 | reset(); 23 | try { 24 | callback(); 25 | } finally { 26 | log(); 27 | reset(); 28 | } 29 | } 30 | 31 | void reset() { 32 | _counts.clear(); 33 | } 34 | 35 | void log() { 36 | var names = _counts.keys.toList(); 37 | names.sort(); 38 | var nameLength = 39 | names.fold(0, (length, name) => max(length, name.length)); 40 | var countLength = _counts.values 41 | .fold(0, (length, count) => max(length, count.toString().length)); 42 | 43 | for (var name in names) { 44 | print('${name.padRight(nameLength)} = ' 45 | '${_counts[name].toString().padLeft(countLength)}'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/space.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/equal.dart'; 5 | 6 | import 'static_type.dart'; 7 | 8 | // TODO: List spaces. 9 | 10 | abstract class Space { 11 | static final empty = _EmptySpace._(); 12 | static final top = Space(StaticType.top); 13 | 14 | factory Space.union(List arms) { 15 | // Simplify the arms if possible. 16 | var allArms = []; 17 | 18 | void addSpace(Space space) { 19 | // Discard duplicate arms. Duplicates can appear when working through a 20 | // series of cases that destructure multiple fields with different types. 21 | // Discarding the duplicates isn't necessary for correctness (a union with 22 | // redundant arms contains the same set of values), but improves 23 | // performance greatly. In the "sealed subtypes large T with all cases" 24 | // test, you end up with a union containing 2520 arms, 2488 are 25 | // duplicates. With this check, the largest union has only 5 arms. 26 | // 27 | // This is O(n^2) since we define only equality on spaces, but a real 28 | // implementation would likely define hash code too and then simply 29 | // create a hash set to merge duplicates in O(n) time. 30 | for (var existing in allArms) { 31 | if (equal(existing, space, 'dedupe union')) return; 32 | } 33 | 34 | allArms.add(space); 35 | } 36 | 37 | for (var space in arms) { 38 | // Discard empty arms. 39 | if (space == empty) continue; 40 | 41 | // Flatten unions. We don't need to flatten recursively since we always 42 | // go through this constructor to create unions. A UnionSpace will never 43 | // contain UnionSpaces. 44 | if (space is UnionSpace) { 45 | for (var arm in space.arms) { 46 | addSpace(arm); 47 | } 48 | } else { 49 | addSpace(space); 50 | } 51 | } 52 | 53 | if (allArms.isEmpty) return empty; 54 | if (allArms.length == 1) return allArms.first; 55 | return UnionSpace._(allArms); 56 | } 57 | 58 | factory Space(StaticType type, [Map fields = const {}]) => 59 | ExtractSpace._(type, fields); 60 | 61 | factory Space.record([Map fields = const {}]) => 62 | Space(StaticType.top, fields); 63 | 64 | Space._(); 65 | 66 | /// An untyped record space with no fields matches all values and thus isn't 67 | /// very useful. 68 | bool get isTop => false; 69 | } 70 | 71 | /// A union of spaces. The space A|B contains all of the values of A and B. 72 | class UnionSpace extends Space { 73 | final List arms; 74 | 75 | UnionSpace._(this.arms) : super._() { 76 | assert(arms.length > 1); 77 | } 78 | 79 | @override 80 | String toString() => arms.join('|'); 81 | } 82 | 83 | /// The main space for matching types and destructuring. 84 | /// 85 | /// It has a type which determines the type of values it contains. The type may 86 | /// be [StaticType.top] to indicate that it doesn't filter by type. 87 | /// 88 | /// It may also contain zero or more named fields. The space then only contains 89 | /// values where the field values are contained by the corresponding field 90 | /// spaces. 91 | class ExtractSpace extends Space { 92 | /// The type of values the space matches. 93 | final StaticType type; 94 | 95 | /// Any field subspaces the space matches. 96 | final Map fields; 97 | 98 | ExtractSpace._(this.type, [this.fields = const {}]) : super._(); 99 | 100 | /// An [ExtractSpace] with no type and no fields contains all values. 101 | @override 102 | bool get isTop => type == StaticType.top && fields.isEmpty; 103 | 104 | @override 105 | String toString() { 106 | if (isTop) return '()'; 107 | 108 | // If there are no fields, just show the type. 109 | if (fields.isEmpty) return type.name; 110 | 111 | var buffer = StringBuffer(); 112 | 113 | // We model a bare record pattern by treating it like an extractor on top. 114 | if (type != StaticType.top) buffer.write(type.name); 115 | 116 | buffer.write('('); 117 | var first = true; 118 | 119 | // Positional fields have stringified number names. 120 | for (var i = 0;; i++) { 121 | var pattern = fields[i.toString()]; 122 | if (pattern == null) break; 123 | 124 | if (!first) buffer.write(', '); 125 | buffer.write(pattern); 126 | first = false; 127 | } 128 | 129 | fields.forEach((name, pattern) { 130 | // Skip positional fields. 131 | if (int.tryParse(name) != null) return; 132 | 133 | if (!first) buffer.write(', '); 134 | buffer.write('$name: $pattern'); 135 | first = false; 136 | }); 137 | 138 | buffer.write(')'); 139 | 140 | return buffer.toString(); 141 | } 142 | } 143 | 144 | /// The uninhabited space. 145 | class _EmptySpace extends Space { 146 | _EmptySpace._() : super._(); 147 | 148 | @override 149 | String toString() => '∅'; 150 | } 151 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/lib/static_type.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // TODO: Generics. 6 | 7 | /// A static type in the type system. 8 | class StaticType { 9 | /// Built-in top type that all types are a subtype of. 10 | static final top = StaticType('top', inherits: []); 11 | 12 | static final nullType = StaticType('Null'); 13 | 14 | final String name; 15 | 16 | late final StaticType nullable = StaticType._nullable(this); 17 | 18 | /// If this type is a nullable type, then this is the underlying type. 19 | /// 20 | /// Otherwise `null`. 21 | final StaticType? _underlying; 22 | 23 | /// The underlying type of this nullable type. It's an error to call this on 24 | /// a non-nullable type. 25 | StaticType get underlying => _underlying!; 26 | 27 | /// Whether this type is sealed. A sealed type is implicitly abstract and has 28 | /// a closed set of known subtypes. This means that every instance of the 29 | /// type must be an instance of one of those subtypes. Conversely, if an 30 | /// instance is *not* an instance of one of those subtypes, that it must not 31 | /// be an instance of this type. 32 | /// 33 | /// Note that subtypes of a sealed type do not themselves have to be sealed. 34 | /// Consider: 35 | /// 36 | /// (A) 37 | /// / \ 38 | /// B C 39 | /// 40 | /// Here, A is sealed and B and C are not. There may be many unknown 41 | /// subclasses of B and C, or classes implementing their interfaces. That 42 | /// doesn't interfere with exhaustiveness checking because it's still the 43 | /// case that any instance of A must be either a B or C *or some subtype of 44 | /// one of those two types*. 45 | final bool isSealed; 46 | 47 | bool get isNullable => _underlying != null; 48 | 49 | /// The static types of the fields this type exposes for record destructuring. 50 | /// 51 | /// Includes inherited fields. 52 | Map get fields { 53 | return {for (var supertype in _supertypes) ...supertype.fields, ..._fields}; 54 | } 55 | 56 | final Map _fields; 57 | 58 | final List _supertypes = []; 59 | 60 | /// The immediate subtypes of this type. 61 | Iterable get subtypes => _subtypes; 62 | final List _subtypes = []; 63 | 64 | StaticType(this.name, 65 | {this.isSealed = false, 66 | List? inherits, 67 | Map fields = const {}}) 68 | : _underlying = null, 69 | _fields = fields { 70 | if (inherits != null) { 71 | for (var type in inherits) { 72 | _supertypes.add(type); 73 | type._subtypes.add(this); 74 | } 75 | } else { 76 | _supertypes.add(top); 77 | } 78 | 79 | var sealed = 0; 80 | for (var supertype in _supertypes) { 81 | if (supertype.isSealed) sealed++; 82 | } 83 | 84 | // We don't allow a sealed type's subtypes to be shared with some other 85 | // sibling supertype, as in D here: 86 | // 87 | // (A) (B) 88 | // / \ / \ 89 | // C D E 90 | // 91 | // We could remove this restriction but doing so will require 92 | // expandTypes() to be more complex. In the example here, if we subtract 93 | // E from A, the result should be C|D. That requires knowing that B should 94 | // be expanded, which expandTypes() doesn't currently handle. 95 | if (sealed > 1) throw ArgumentError('Can only have one sealed supertype.'); 96 | } 97 | 98 | StaticType._nullable(StaticType underlying) 99 | : name = '${underlying.name}?', 100 | _underlying = underlying, 101 | isSealed = true, 102 | // No fields because it may match null which doesn't have them. 103 | _fields = {}; 104 | 105 | bool isSubtypeOf(StaticType other) { 106 | if (this == other) return true; 107 | 108 | // Null is a subtype of all nullable types. 109 | if (this == nullType && other._underlying != null) return true; 110 | 111 | // A nullable type is a subtype if the underlying type and Null both are. 112 | var underlying = _underlying; 113 | if (underlying != null) { 114 | return underlying.isSubtypeOf(other) && nullType.isSubtypeOf(other); 115 | } 116 | 117 | // A non-nullable type is a subtype of the underlying type of a nullable 118 | // type. 119 | var otherUnderlying = other._underlying; 120 | if (otherUnderlying != null) { 121 | return isSubtypeOf(otherUnderlying); 122 | } 123 | 124 | for (var supertype in _supertypes) { 125 | if (supertype.isSubtypeOf(other)) return true; 126 | } 127 | 128 | return false; 129 | } 130 | 131 | @override 132 | String toString() => name; 133 | } 134 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: exhaustiveness_prototype 2 | environment: 3 | sdk: '>=2.16.0 <3.0.0' 4 | dev_dependencies: 5 | lints: any 6 | test: '^1.20.1' 7 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/intersect_empty_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/intersect_empty.dart'; 5 | import 'package:exhaustiveness_prototype/space.dart'; 6 | import 'package:exhaustiveness_prototype/static_type.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | import 'utils.dart'; 10 | 11 | void main() { 12 | // (A) 13 | // / \ 14 | // B C 15 | var a = StaticType('A', isSealed: true); 16 | var b = StaticType('B', inherits: [a]); 17 | var c = StaticType('C', inherits: [a]); 18 | 19 | Space A({StaticType? x, StaticType? y, StaticType? z}) => ty( 20 | a, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 21 | Space B({StaticType? x, StaticType? y, StaticType? z}) => ty( 22 | b, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 23 | Space C({StaticType? x, StaticType? y, StaticType? z}) => ty( 24 | c, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 25 | 26 | test('records', () { 27 | expectIntersectEmpty(rec(x: a, y: a), rec(x: a, y: a), isFalse); 28 | expectIntersectEmpty(rec(x: a, y: a), rec(x: a), isFalse); 29 | expectIntersectEmpty(rec(w: a, x: a), rec(y: a, z: a), isFalse); 30 | expectIntersectEmpty(rec(w: a, x: a, y: a), rec(x: a, y: a, z: a), isFalse); 31 | }); 32 | 33 | test('types', () { 34 | // Note: More comprehensive tests under intersect_types_test.dart. 35 | expectIntersectEmpty(a, a, isFalse); 36 | expectIntersectEmpty(a, b, isFalse); 37 | expectIntersectEmpty(a, c, isFalse); 38 | expectIntersectEmpty(b, c, isTrue); 39 | }); 40 | 41 | test('field types', () { 42 | expectIntersectEmpty(rec(x: a, y: b), rec(x: b, y: a), isFalse); 43 | expectIntersectEmpty(rec(x: b), rec(x: c), isTrue); 44 | }); 45 | 46 | test('types and fields', () { 47 | expectIntersectEmpty(A(x: a), A(x: a), isFalse); 48 | expectIntersectEmpty(A(x: a), A(x: b), isFalse); 49 | expectIntersectEmpty(A(x: b), A(x: c), isTrue); 50 | 51 | expectIntersectEmpty(A(x: a), B(x: a), isFalse); 52 | expectIntersectEmpty(A(x: a), B(x: b), isFalse); 53 | expectIntersectEmpty(A(x: b), B(x: c), isTrue); 54 | 55 | expectIntersectEmpty(B(x: a), A(x: a), isFalse); 56 | expectIntersectEmpty(B(x: a), A(x: b), isFalse); 57 | expectIntersectEmpty(B(x: b), A(x: c), isTrue); 58 | 59 | expectIntersectEmpty(B(x: a), B(x: a), isFalse); 60 | expectIntersectEmpty(B(x: a), B(x: b), isFalse); 61 | expectIntersectEmpty(B(x: b), B(x: c), isTrue); 62 | 63 | expectIntersectEmpty(B(x: a), C(x: a), isTrue); 64 | expectIntersectEmpty(B(x: a), C(x: b), isTrue); 65 | expectIntersectEmpty(B(x: b), C(x: c), isTrue); 66 | }); 67 | } 68 | 69 | void expectIntersectEmpty(Object left, Object right, Matcher expected) { 70 | var leftSpace = parseSpace(left); 71 | var rightSpace = parseSpace(right); 72 | 73 | // Intersection is symmetric so try both directions. 74 | expect(intersectEmpty(leftSpace, rightSpace), expected); 75 | expect(intersectEmpty(rightSpace, leftSpace), expected); 76 | } 77 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/intersect_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/intersect.dart'; 5 | import 'package:exhaustiveness_prototype/space.dart'; 6 | import 'package:exhaustiveness_prototype/static_type.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | import 'utils.dart'; 10 | 11 | void main() { 12 | // (A) 13 | // / \ 14 | // B C 15 | var a = StaticType('A', isSealed: true); 16 | var b = StaticType('B', inherits: [a]); 17 | var c = StaticType('C', inherits: [a]); 18 | 19 | Space A({StaticType? x, StaticType? y, StaticType? z}) => ty( 20 | a, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 21 | Space B({StaticType? x, StaticType? y, StaticType? z}) => ty( 22 | b, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 23 | Space C({StaticType? x, StaticType? y, StaticType? z}) => ty( 24 | c, {if (x != null) 'x': x, if (y != null) 'y': y, if (z != null) 'z': z}); 25 | 26 | test('records', () { 27 | expectIntersect(rec(x: a, y: a), rec(x: a, y: a), rec(x: a, y: a)); 28 | expectIntersect(rec(x: a, y: a), rec(x: a), rec(x: a, y: a)); 29 | expectIntersect( 30 | rec(w: a, x: a), rec(y: a, z: a), rec(w: a, x: a, y: a, z: a)); 31 | expectIntersect(rec(w: a, x: a, y: a), rec(x: a, y: a, z: a), 32 | rec(w: a, x: a, y: a, z: a)); 33 | }); 34 | 35 | test('types', () { 36 | // Note: More comprehensive tests under intersect_types_test.dart. 37 | expectIntersect(a, a, a); 38 | expectIntersect(a, b, b); 39 | expectIntersect(a, c, c); 40 | expectIntersect(b, c, '∅'); 41 | }); 42 | 43 | test('field types', () { 44 | expectIntersect(rec(x: a, y: b), rec(x: b, y: a), rec(x: b, y: b)); 45 | expectIntersect(rec(x: b), rec(x: c), '∅'); 46 | }); 47 | 48 | test('types and fields', () { 49 | expectIntersect(A(x: a), A(x: a), A(x: a)); 50 | expectIntersect(A(x: a), A(x: b), A(x: b)); 51 | expectIntersect(A(x: b), A(x: c), '∅'); 52 | 53 | expectIntersect(A(x: a), B(x: a), B(x: a)); 54 | expectIntersect(A(x: a), B(x: b), B(x: b)); 55 | expectIntersect(A(x: b), B(x: c), '∅'); 56 | 57 | expectIntersect(B(x: a), A(x: a), B(x: a)); 58 | expectIntersect(B(x: a), A(x: b), B(x: b)); 59 | expectIntersect(B(x: b), A(x: c), '∅'); 60 | 61 | expectIntersect(B(x: a), B(x: a), B(x: a)); 62 | expectIntersect(B(x: a), B(x: b), B(x: b)); 63 | expectIntersect(B(x: b), B(x: c), '∅'); 64 | 65 | expectIntersect(B(x: a), C(x: a), '∅'); 66 | expectIntersect(B(x: a), C(x: b), '∅'); 67 | expectIntersect(B(x: b), C(x: c), '∅'); 68 | }); 69 | } 70 | 71 | void expectIntersect(Object left, Object right, Object expected) { 72 | var leftSpace = parseSpace(left); 73 | var rightSpace = parseSpace(right); 74 | var expectedText = parseSpace(expected).toString(); 75 | 76 | // Intersection is symmetric so try both directions. 77 | expect(intersect(leftSpace, rightSpace).toString(), expectedText); 78 | expect(intersect(rightSpace, leftSpace).toString(), expectedText); 79 | } 80 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/intersect_types_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/intersect.dart'; 5 | import 'package:exhaustiveness_prototype/static_type.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | test('hierarchy', () { 10 | // (A) 11 | // /|\ 12 | // B C(D) 13 | // / \ 14 | // E F 15 | var a = StaticType('A', isSealed: true); 16 | var b = StaticType('B', inherits: [a]); 17 | var c = StaticType('C', inherits: [a]); 18 | var d = StaticType('D', isSealed: true, inherits: [a]); 19 | var e = StaticType('E', inherits: [d]); 20 | var f = StaticType('F', inherits: [d]); 21 | 22 | expectIntersect(a, a, a); 23 | expectIntersect(a, b, b); 24 | expectIntersect(a, c, c); 25 | expectIntersect(a, d, d); 26 | expectIntersect(a, e, e); 27 | expectIntersect(a, f, f); 28 | 29 | expectIntersect(b, b, b); 30 | expectIntersect(b, c, null); 31 | expectIntersect(b, d, null); 32 | expectIntersect(b, e, null); 33 | expectIntersect(b, f, null); 34 | 35 | expectIntersect(c, c, c); 36 | expectIntersect(c, d, null); 37 | expectIntersect(c, e, null); 38 | expectIntersect(c, f, null); 39 | 40 | expectIntersect(d, d, d); 41 | expectIntersect(d, e, e); 42 | expectIntersect(d, f, f); 43 | 44 | expectIntersect(e, e, e); 45 | expectIntersect(e, f, null); 46 | }); 47 | 48 | test('sealed with multiple paths', () { 49 | // (A) 50 | // / \ 51 | // (B) C 52 | // / \ / 53 | // D E 54 | var a = StaticType('A', isSealed: true); 55 | var b = StaticType('B', isSealed: true, inherits: [a]); 56 | var c = StaticType('C', inherits: [a]); 57 | var d = StaticType('D', inherits: [b]); 58 | var e = StaticType('E', inherits: [b, c]); 59 | 60 | expectIntersect(a, a, a); 61 | expectIntersect(a, b, b); 62 | expectIntersect(a, c, c); 63 | expectIntersect(a, d, d); 64 | expectIntersect(a, e, e); 65 | expectIntersect(b, b, b); 66 | expectIntersect(b, c, null); 67 | expectIntersect(b, d, d); 68 | expectIntersect(b, e, e); 69 | expectIntersect(c, c, c); 70 | expectIntersect(c, d, null); 71 | expectIntersect(c, e, e); 72 | expectIntersect(d, d, d); 73 | expectIntersect(d, e, null); 74 | expectIntersect(e, e, e); 75 | }); 76 | 77 | test('nullable', () { 78 | // A 79 | // | 80 | // B 81 | var a = StaticType('A'); 82 | var b = StaticType('B', inherits: [a]); 83 | 84 | expectIntersect(a, a.nullable, a); 85 | expectIntersect(a, StaticType.nullType, null); 86 | expectIntersect(a.nullable, StaticType.nullType, StaticType.nullType); 87 | 88 | expectIntersect(a, b.nullable, b); 89 | expectIntersect(a.nullable, b, b); 90 | expectIntersect(a.nullable, b.nullable, b.nullable); 91 | }); 92 | } 93 | 94 | void expectIntersect(StaticType left, StaticType right, StaticType? expected) { 95 | // Intersection is symmetric so try both directions. 96 | expect(intersectTypes(left, right), expected); 97 | expect(intersectTypes(right, left), expected); 98 | } 99 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/is_exhaustive_nested_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/static_type.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import 'utils.dart'; 8 | 9 | void main() { 10 | group('nested records', () { 11 | // (A) 12 | // / \ 13 | // B C 14 | var a = StaticType('A', isSealed: true); 15 | var b = StaticType('B', inherits: [a]); 16 | var c = StaticType('C', inherits: [a]); 17 | var t = StaticType('T', fields: {'x': a, 'y': b}); 18 | var u = StaticType('U', fields: {'w': t, 'z': t}); 19 | 20 | expectExhaustiveOnlyAll(u, [ 21 | rec(w: rec(x: a), z: t), 22 | ]); 23 | 24 | expectExhaustiveOnlyAll(u, [ 25 | rec(w: rec(x: a, y: a), z: rec(x: a, y: a)), 26 | ]); 27 | 28 | expectExhaustiveOnlyAll(u, [ 29 | rec(w: rec(x: a, y: b), z: rec(x: a, y: b)), 30 | ]); 31 | 32 | expectExhaustiveOnlyAll(u, [ 33 | rec(w: rec(x: b), z: t), 34 | rec(w: rec(x: c), z: t), 35 | ]); 36 | 37 | expectExhaustiveOnlyAll(u, [ 38 | rec(w: rec(x: b, y: b), z: rec(x: b, y: b)), 39 | rec(w: rec(x: b, y: b), z: rec(x: c, y: b)), 40 | rec(w: rec(x: c, y: b), z: rec(x: b, y: b)), 41 | rec(w: rec(x: c, y: b), z: rec(x: c, y: b)), 42 | ]); 43 | }); 44 | 45 | group('nested with different fields of same name', () { 46 | // A B C D 47 | var a = StaticType('A'); 48 | var b = StaticType('B', fields: {'x': a}); 49 | var c = StaticType('C', fields: {'x': b}); 50 | var d = StaticType('D', fields: {'x': c}); 51 | 52 | expectExhaustiveOnlyAll(d, [ 53 | rec(x: rec(x: rec(x: a))), 54 | ]); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/report_errors_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/exhaustive.dart'; 5 | import 'package:exhaustiveness_prototype/static_type.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import 'utils.dart'; 9 | 10 | void main() { 11 | // Here, "(_)" means "sealed". A bare name is unsealed. 12 | // 13 | // (A) 14 | // / \ 15 | // (B) (C) 16 | // / \ \ 17 | // D E F 18 | // / \ 19 | // G H 20 | var a = StaticType('A', isSealed: true); 21 | var b = StaticType('B', isSealed: true, inherits: [a]); 22 | var c = StaticType('C', isSealed: true, inherits: [a]); 23 | var d = StaticType('D', inherits: [b]); 24 | var e = StaticType('E', inherits: [b]); 25 | var f = StaticType('F', inherits: [c]); 26 | var g = StaticType('G', inherits: [f]); 27 | var h = StaticType('H', inherits: [f]); 28 | 29 | test('exhaustiveness', () { 30 | // Case matching top type covers all subtypes. 31 | expectReportErrors(a, [a]); 32 | expectReportErrors(b, [a]); 33 | expectReportErrors(d, [a]); 34 | 35 | // Case matching subtype doesn't cover supertype. 36 | expectReportErrors(a, [b], 'A is not exhaustively matched by B.'); 37 | expectReportErrors(b, [b]); 38 | expectReportErrors(d, [b]); 39 | expectReportErrors(e, [b]); 40 | 41 | // Matching subtypes of sealed type is exhaustive. 42 | expectReportErrors(a, [b, c]); 43 | expectReportErrors(a, [d, e, f]); 44 | expectReportErrors(a, [b, f]); 45 | expectReportErrors(a, [c, d], 'A is not exhaustively matched by C|D.'); 46 | expectReportErrors(f, [g, h], 'F is not exhaustively matched by G|H.'); 47 | }); 48 | 49 | test('unreachable case', () { 50 | // Same type. 51 | expectReportErrors(b, [b, b], 'Case #2 B is covered by B.'); 52 | 53 | // Previous case is supertype. 54 | expectReportErrors(b, [a, b], 'Case #2 B is covered by A.'); 55 | 56 | // Previous subtype cases cover sealed supertype. 57 | expectReportErrors(a, [b, c, a], 'Case #3 A is covered by B|C.'); 58 | expectReportErrors(a, [d, e, f, a], 'Case #4 A is covered by D|E|F.'); 59 | expectReportErrors(a, [b, f, a], 'Case #3 A is covered by B|F.'); 60 | expectReportErrors(a, [c, d, a]); 61 | 62 | // Previous subtype cases do not cover unsealed supertype. 63 | expectReportErrors(f, [g, h, f]); 64 | }); 65 | 66 | test('covered record destructuring', () { 67 | var r = StaticType('R', fields: {'x': a, 'y': a, 'z': a}); 68 | 69 | // Wider field is not covered. 70 | expectReportErrors(r, [ 71 | {'x': b}, 72 | {'x': a} 73 | ]); 74 | 75 | // Narrower field is covered. 76 | expectReportErrors( 77 | r, 78 | [ 79 | {'x': a}, 80 | {'x': b} 81 | ], 82 | 'Case #2 (x: B) is covered by (x: A).'); 83 | }); 84 | 85 | test('nullable sealed', () { 86 | // (A) 87 | // / \ 88 | // B (C) 89 | // / \ 90 | // D E 91 | var a = StaticType('A', isSealed: true); 92 | var b = StaticType('B', inherits: [a]); 93 | var c = StaticType('C', isSealed: true, inherits: [a]); 94 | var d = StaticType('D', inherits: [c]); 95 | var e = StaticType('E', inherits: [c]); 96 | 97 | // Must cover null. 98 | expectReportErrors( 99 | a.nullable, [b, d, e], 'A? is not exhaustively matched by B|D|E.'); 100 | 101 | // Can cover null with any nullable subtype. 102 | expectReportErrors(a.nullable, [b.nullable, c]); 103 | expectReportErrors(a.nullable, [b, c.nullable]); 104 | expectReportErrors(a.nullable, [b, d.nullable, e]); 105 | expectReportErrors(a.nullable, [b, d, e.nullable]); 106 | 107 | // Can cover null with a null space. 108 | expectReportErrors(a.nullable, [b, c, StaticType.nullType]); 109 | expectReportErrors(a.nullable, [b, d, e, StaticType.nullType]); 110 | 111 | // Nullable covers the non-null. 112 | expectReportErrors( 113 | a.nullable, [a.nullable, a], 'Case #2 A is covered by A?.'); 114 | expectReportErrors( 115 | b.nullable, [a.nullable, b], 'Case #2 B is covered by A?.'); 116 | 117 | // Nullable covers null. 118 | expectReportErrors(a.nullable, [a.nullable, StaticType.nullType], 119 | 'Case #2 Null is covered by A?.'); 120 | expectReportErrors(b.nullable, [a.nullable, StaticType.nullType], 121 | 'Case #2 Null is covered by A?.'); 122 | }); 123 | } 124 | 125 | void expectReportErrors(StaticType valueType, List cases, 126 | [String errors = '']) { 127 | expect(reportErrors(valueType, parseSpaces(cases)), errors); 128 | } 129 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/exhaustiveness_prototype/test/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | import 'package:exhaustiveness_prototype/exhaustive.dart'; 5 | import 'package:exhaustiveness_prototype/space.dart'; 6 | import 'package:exhaustiveness_prototype/static_type.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | Map fieldsToSpace(Map fields) => 10 | fields.map((key, value) => MapEntry(key, parseSpace(value))); 11 | 12 | /// Make a [Space] with [type] and [fields]. 13 | Space ty(StaticType type, Map fields) => 14 | Space(type, fieldsToSpace(fields)); 15 | 16 | /// Make a record space with the given fields. 17 | Space rec({Object? w, Object? x, Object? y, Object? z}) => Space.record({ 18 | if (w != null) 'w': parseSpace(w), 19 | if (x != null) 'x': parseSpace(x), 20 | if (y != null) 'y': parseSpace(y), 21 | if (z != null) 'z': parseSpace(z) 22 | }); 23 | 24 | /// Parse a list of spaces using [parseSpace]. 25 | List parseSpaces(List objects) => 26 | objects.map(parseSpace).toList(); 27 | 28 | Space parseSpace(Object object) { 29 | if (object is Space) return object; 30 | if (object == '∅') return Space.empty; 31 | if (object is StaticType) return Space(object); 32 | if (object is List) { 33 | return Space.union(object.map(parseSpace).toList()); 34 | } 35 | if (object is Map) { 36 | return Space.record(fieldsToSpace(object)); 37 | } 38 | 39 | throw ArgumentError('Invalid space $object'); 40 | } 41 | 42 | /// Test that [spaces] is exhaustive over [value]. 43 | void expectExhaustive(Space value, List spaces) { 44 | _expectExhaustive(value, spaces, true); 45 | } 46 | 47 | /// Test that [spaces] is not exhaustive over [value]. 48 | void expectNotExhaustive(Space value, List spaces) { 49 | _expectExhaustive(value, spaces, false); 50 | } 51 | 52 | void _expectExhaustive(Space value, List spaces, bool expectation) { 53 | test( 54 | '$value - ${spaces.join(' - ')} ${expectation ? 'is' : 'is not'} ' 55 | 'exhaustive', () { 56 | _checkExhaustive(value, spaces, expectation); 57 | }); 58 | } 59 | 60 | /// Test that [cases] are exhaustive over [type] if and only if all cases are 61 | /// included and that all subsets of the cases are not exhaustive. 62 | void expectExhaustiveOnlyAll(StaticType type, List cases) { 63 | _testCases(type, cases, true); 64 | } 65 | 66 | /// Test that [cases] are not exhaustive over [type]. Also test that omitting 67 | /// each case is still not exhaustive. 68 | void expectNeverExhaustive(StaticType type, List cases) { 69 | _testCases(type, cases, false); 70 | } 71 | 72 | /// Test that [cases] are not exhaustive over [type]. 73 | void _testCases(StaticType type, List cases, bool expectation) { 74 | var valueSpace = Space(type); 75 | var spaces = parseSpaces(cases); 76 | 77 | test('$type with all cases', () { 78 | _checkExhaustive(valueSpace, spaces, expectation); 79 | }); 80 | 81 | // With any single case removed, should also not be exhaustive. 82 | for (var i = 0; i < spaces.length; i++) { 83 | var filtered = spaces.toList(); 84 | filtered.removeAt(i); 85 | 86 | test('$type without case ${spaces[i]}', () { 87 | _checkExhaustive(valueSpace, filtered, false); 88 | }); 89 | } 90 | } 91 | 92 | void _checkExhaustive(Space value, List spaces, bool expectation) { 93 | var actual = isExhaustive(value, spaces); 94 | if (expectation != actual) { 95 | if (expectation) { 96 | fail('Expected $spaces to cover $value but did not.'); 97 | } else { 98 | fail('Expected $spaces to not cover $value but did.'); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /accepted/future-releases/0546-patterns/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/3.0/patterns/feature-specification.md 4 | -------------------------------------------------------------------------------- /accepted/future-releases/async-star-behavior/implementation-plan.md: -------------------------------------------------------------------------------- 1 | # Implementation Plan for async-star/await-for behavior. 2 | 3 | Relevant documents: 4 | - [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/future-releases/async-star-behavior/feature-specification.md) 5 | ## Implementation and Release plan 6 | 7 | ### Phase 0 (Preliminaries) 8 | 9 | #### Specification 10 | 11 | The language specification already specifies the desired behavior. 12 | 13 | #### Tests 14 | 15 | The language team adds a set of tests for the new, desired behavior. 16 | See [https://dart-review.googlesource.com/c/sdk/+/85391]. 17 | 18 | ### Phase 1 (Implementation) 19 | 20 | Only tools with run-time behavior are affected. 21 | Tools like the analyzer and dart-fmt should not require any change. 22 | 23 | The Kernel and the back-ends need to collaborate on this change since the 24 | behavior is an interaction between the Kernel's "continuation" transformer 25 | and classes in the individual back-end libraries (in "async_patch.dart" files). 26 | 27 | The new behavior is guarded by the experiments flag `async-yield`, 28 | so to enable the new behavior, the tools need to be passed a flag 29 | like `--enable-experiments=async-yield`. 30 | 31 | ### Phase 2 (Preparation) 32 | 33 | This change is potentially breaking since it changes the interleaving 34 | of asynchronous execution. 35 | Very likely there is no code *depending* on the interleaving, given that it 36 | is un-intuitive and surprising to users, but some users have hit the problem, 37 | and it's unclear whether they have introduced a workaround. 38 | 39 | We need to check that Google code and Flutter code is not affected by the 40 | behavior. If it is, the code should be fixed before we release the change. 41 | The only way to check this is to actually run an updated SDK against the code 42 | base. 43 | 44 | ### Phase 3 (Release) 45 | 46 | The feature is released as part of the next stable Dart release. 47 | 48 | ## Timeline 49 | 50 | Completion goals for the phases: 51 | - Phase 0: (TODO) 52 | - Phase 1: (TODO) 53 | - Phase 2: (TODO) 54 | - Phase 3: (TODO) 55 | -------------------------------------------------------------------------------- /accepted/future-releases/class-modifiers/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/3.0/class-modifiers/feature-specification.md 4 | -------------------------------------------------------------------------------- /accepted/future-releases/records/records-feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/3.0/records/feature-specification.md 4 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | exclude: 3 | - accepted/2.3/spread-collections/examples/** 4 | - archive/newsletter/20171103 5 | -------------------------------------------------------------------------------- /archive/README.md: -------------------------------------------------------------------------------- 1 | ## Background material about features 2 | 3 | This directory contains background material only. Consult the 4 | [language specification](https://dart.dev/guides/language/spec) 5 | and the 6 | [language repository](https://github.com/dart-lang/language/tree/master/accepted) 7 | for current information. 8 | 9 | ### What is a feature specification? 10 | 11 | In order to move faster and get better feedback, we implement and iterate on 12 | language changes before the full official specification has been written. 13 | Still, the implementers need *something* to go on. 14 | 15 | For that, the language team writes _feature specifications_. These are 16 | intended to be precise enough for a good faith implementer to correctly 17 | understand the syntax and semantics of the language, but when the contents 18 | of a feature specification is integrated into the language specification we 19 | expect the extra processing to give rise to additional clarifications and 20 | corrections, which means that a feature specification is expected to be 21 | _nearly_ as complete and correct as the language specification. 22 | 23 | ### Feature specifications in this directory 24 | 25 | This directory contains older, archived feature specifications 26 | which were originally located in the [Dart SDK repository](https://github.com/dart-lang/sdk). 27 | Newer features can be found in, respectively should be submitted to, 28 | the language repository [here](https://github.com/dart-lang/language). 29 | 30 | The status of every feature specification in this directory is that it is 31 | background material, and the contents have been integrated into the language 32 | specification. Consequently, these feature specifications can only be used 33 | as a source of informal background information. Precise rules about the 34 | features should be looked up in the language specification. 35 | -------------------------------------------------------------------------------- /archive/feature-specifications/invalid_returns.md: -------------------------------------------------------------------------------- 1 | # Dart 2 function return checking 2 | 3 | **Owner**: leafp@google.com 4 | 5 | **Status**: This document is now background material. 6 | For normative text, please consult the language specification. 7 | 8 | **Note: Also see alternative presentation at the bottom for a dual presentation 9 | of these rules in terms of which things are errors, rather than which things are 10 | valid*.* 11 | 12 | 13 | ## Errors for sync and async function return values in Dart 2 14 | 15 | ### Expression bodied functions 16 | 17 | 18 | An asynchronous expression bodied function with return type `T` and body `exp` 19 | has a valid return if: 20 | * `flatten(T)` is `void` 21 | * or `return exp;` is a valid return for an equivalent block bodied function 22 | with return type `T` as defined below. 23 | 24 | A synchronous expression bodied function with return type `T` and body `exp` has 25 | a valid return if: 26 | * `T` is `void` 27 | * or `return exp;` is a valid return for an equivalent block bodied function 28 | with return type `T` as defined below. 29 | 30 | ### Block bodied functions 31 | 32 | #### Synchronous functions 33 | 34 | The rules for a synchronous non-generator function with declared return type `T` 35 | are: 36 | 37 | * `return;` is a valid return if any of the following are true: 38 | * `T` is `void` 39 | * `T` is `dynamic` 40 | * `T` is `Null`. 41 | 42 | * `return exp;` where `exp` has static type `S` is a valid return if: 43 | * `S` is `void` 44 | * and `T` is `void` or `dynamic` or `Null` 45 | 46 | * `return exp;` where `exp` has static type `S` is a valid return if: 47 | * `T` is `void` 48 | * and `S` is `void` or `dynamic` or `Null` 49 | 50 | * `return exp;` where `exp` has static type `S` is a valid return if: 51 | * `T` is not `void` 52 | * and `S` is not `void` 53 | * and `S` is assignable to `T` 54 | 55 | #### Asynchronous functions 56 | 57 | The rules for an asynchronous non-generator function with declared return type 58 | `T` are: 59 | 60 | * `return;` is a valid return if any of the following are true: 61 | * `flatten(T)` is `void` 62 | * `flatten(T)` is `dynamic` 63 | * `flatten(T)` is `Null`. 64 | 65 | * `return exp;` where `exp` has static type `S` is a valid return if: 66 | * `flatten(S)` is `void` 67 | * and `flatten(T)` is `void`, `dynamic` or `Null` 68 | 69 | * `return exp;` where `exp` has static type `S` is a valid return if: 70 | * `flatten(T)` is `void` 71 | * and `flatten(S)` is `void`, `dynamic` or `Null` 72 | 73 | * `return exp;` where `exp` has static type `S` is a valid return if: 74 | * `T` is not `void` 75 | * and `flatten(S)` is not `void` 76 | * and `Future` is assignable to `T` 77 | 78 | 79 | ## Errors for sync and async function return values in Dart 2: Alternative presentation in terms of which things *are* errors 80 | 81 | ### Expression bodied functions 82 | 83 | 84 | It is an error if an asynchronous expression bodied function with return type 85 | `T` has body `exp` and both: 86 | * `flatten(T)` is not `void` 87 | * `return exp;` would be an error in an equivalent block bodied function 88 | with return type `T` as defined below. 89 | 90 | It is an error if a synchronous expression bodied function with return type `T` 91 | has body `exp` and both: 92 | * `T` is not `void` 93 | * `return exp;` would be an error in an equivalent block bodied function 94 | with return type `T` as defined below. 95 | 96 | ### Block bodied functions 97 | 98 | #### Synchronous functions 99 | 100 | The rules for a synchronous non-generator function with declared return type `T` 101 | are: 102 | 103 | * `return;` is an error if `T` is not `void`, `dynamic`, or `Null` 104 | 105 | * `return exp;` where `exp` has static type `S` is an error if `T` is `void` and 106 | `S` is not `void`, `dynamic`, or `Null` 107 | 108 | * `return exp;` where `exp` has static type `S` is an error if `S` is `void` and 109 | `T` is not `void`, or `dynamic` or `Null`. 110 | 111 | * `return exp;` where `exp` has static type `S` is an error if `S` is not 112 | assignable to `T`. 113 | 114 | #### Asynchronous functions 115 | 116 | The rules for an asynchronous non-generator function with declared return type 117 | `T` are: 118 | 119 | * `return;` is an error if `flatten(T)` is not `void`, `dynamic`, or `Null` 120 | 121 | * `return exp;` where `exp` has static type `S` is an error if `T` is 122 | `void` and `flatten(S)` is not `void`, `dynamic`, or `Null` 123 | 124 | * `return exp;` where `exp` has static type `S` is an error if `flatten(S)` is 125 | `void` and `flatten(T)` is not `void`, `dynamic`, or `Null`. 126 | 127 | * `return exp;` where `exp` has static type `S` is an error if 128 | `Future` is not assignable to `T`. 129 | -------------------------------------------------------------------------------- /archive/feature-specifications/mixin-declaration.md: -------------------------------------------------------------------------------- 1 | # Dart 2 Mixin Declarations 2 | 3 | **Status**: This is now background material. 4 | 5 | ## The canonical version of this document now resides [here](https://github.com/dart-lang/language/blob/master/accepted/2.1/super-mixins/feature-specification.md). 6 | -------------------------------------------------------------------------------- /archive/feature-specifications/subtyping.md: -------------------------------------------------------------------------------- 1 | # Dart 2.0 Static and Runtime Subtyping 2 | 3 | leafp@google.com 4 | 5 | **Status**: This document has been integrated into the language specification. 6 | Also, an updated version taking non-null types into account exists 7 | [here](https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md). 8 | 9 | **Contents of this document**: Deleted. 10 | -------------------------------------------------------------------------------- /archive/newsletter/20171027.md: -------------------------------------------------------------------------------- 1 | # Dart Language and Library Newsletter 2 | 2017-10-27 3 | @floitschG 4 | 5 | Welcome to the Dart Language and Library Newsletter. 6 | 7 | ## Library Updates 8 | This week's newsletter is all about the planned library changes for Dart 2.0. 9 | 10 | We have collected our plans in [this document](lib/lib.md). 11 | 12 | Please let us know what you think. 13 | -------------------------------------------------------------------------------- /archive/newsletter/20171103/json.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'dart:math'; 4 | 5 | main() { 6 | for (int i = 0; i < 5; i++) { 7 | var sw = new Stopwatch()..start(); 8 | // Here we just read the contents of a file, but the string could come from 9 | // anywhere. 10 | var input = new File("big.json").readAsStringSync(); 11 | print("Reading took: ${sw.elapsedMicroseconds}us"); 12 | 13 | // Measure synchronous decoding. 14 | sw.reset(); 15 | var decoded = JSON.decode(input); 16 | print("Decoding took: ${sw.elapsedMicroseconds}us"); 17 | 18 | // Measure chunked decoding. 19 | sw.reset(); 20 | const chunkCount = 100; // Actually one more for simplicity. 21 | var result; 22 | // This is where the chunked converter will publish its result. 23 | var outSink = new ChunkedConversionSink.withCallback((List x) { 24 | result = x.single; 25 | }); 26 | 27 | var inSink = JSON.decoder.startChunkedConversion(outSink); 28 | var chunkSw = new Stopwatch()..start(); 29 | var maxChunkTime = 0; 30 | var chunkSize = input.length ~/ chunkCount; 31 | int i; 32 | for (i = 0; i < chunkCount; i++) { 33 | chunkSw.reset(); 34 | var chunk = input.substring(i * chunkSize, (i + 1) * chunkSize); 35 | inSink.add(chunk); 36 | maxChunkTime = max(maxChunkTime, chunkSw.elapsedMicroseconds); 37 | } 38 | // Now add the last chunk (which could be non-empty because of the rounding 39 | // division). 40 | chunkSw.reset(); 41 | inSink.add(input.substring(i * chunkSize)); 42 | inSink.close(); 43 | maxChunkTime = max(maxChunkTime, chunkSw.elapsedMicroseconds); 44 | assert(result != null); 45 | print("Decoding took at most ${maxChunkTime}us per chunk," 46 | " and ${sw.elapsedMicroseconds} in total"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /archive/newsletter/20171103/json2.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'dart:math'; 4 | 5 | main() { 6 | for (int i = 0; i < 5; i++) { 7 | var sw = new Stopwatch()..start(); 8 | // Here we just read the contents of a file, but the string could come from 9 | // anywhere. 10 | var input = new File("big.json").readAsStringSync(); 11 | print("Reading took: ${sw.elapsedMicroseconds}us"); 12 | 13 | // Measure synchronous decoding. 14 | sw.reset(); 15 | var decoded = JSON.decode(input); 16 | print("Decoding took: ${sw.elapsedMicroseconds}us"); 17 | 18 | // Measure chunked decoding. 19 | sw.reset(); 20 | const chunkCount = 100; // Actually one more for simplicity. 21 | var result; 22 | // This is where the chunked converter will publish its result. 23 | var outSink = new ChunkedConversionSink.withCallback((List x) { 24 | result = x.single; 25 | }); 26 | 27 | var inSink = JSON.decoder.startChunkedConversion(outSink); 28 | var chunkSw = new Stopwatch()..start(); 29 | var maxChunkTime = 0; 30 | var chunkSize = input.length ~/ chunkCount; 31 | int i; 32 | for (i = 0; i < 100; i++) { 33 | chunkSw.reset(); 34 | inSink.addSlice(input, i * chunkSize, (i + 1) * chunkSize, false); 35 | maxChunkTime = max(maxChunkTime, chunkSw.elapsedMicroseconds); 36 | } 37 | // Now add the last chunk (which could be non-empty because of the rounding 38 | // division). 39 | chunkSw.reset(); 40 | inSink.addSlice(input, i * chunkSize, input.length, true); 41 | maxChunkTime = max(maxChunkTime, chunkSw.elapsedMicroseconds); 42 | assert(result != null); 43 | print("Decoding took at most ${maxChunkTime}us per chunk," 44 | " and ${sw.elapsedMicroseconds} in total"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /archive/newsletter/20171103/json3.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | import 'dart:math'; 5 | 6 | /// Decodes [input] in a chunked way and yields to the event loop 7 | /// as soon as [maxMicroseconds] have elapsed. 8 | Future decodeJsonChunked(String input, int maxMicroseconds) { 9 | const chunkCount = 100; // Actually one more. 10 | 11 | var result; 12 | var outSink = new ChunkedConversionSink.withCallback((x) { 13 | result = x[0]; 14 | }); 15 | var inSink = JSON.decoder.startChunkedConversion(outSink); 16 | var chunkSize = input.length ~/ chunkCount; 17 | 18 | int i = 0; 19 | 20 | Future addChunks() { 21 | var sw = new Stopwatch()..start(); 22 | while (i < 100) { 23 | inSink.addSlice(input, i * chunkSize, (i + 1) * chunkSize, false); 24 | i++; 25 | if (sw.elapsedMicroseconds > maxMicroseconds) { 26 | // Usually one has to pay attention not to chain too many futures, 27 | // but here we know that there are at most chunkCount linked futures. 28 | return new Future(addChunks); 29 | } 30 | } 31 | inSink.addSlice(input, i * chunkSize, input.length, true); 32 | return new Future.value(result); 33 | } 34 | 35 | return addChunks(); 36 | } 37 | 38 | main() { 39 | var input = new File("big.json").readAsStringSync(); 40 | var sw = new Stopwatch()..start(); 41 | bool done = false; 42 | // Show that the event-loop is free to do something: 43 | new Timer.periodic(const Duration(milliseconds: 2), (timer) { 44 | print("."); 45 | if (done) timer.cancel(); 46 | }); 47 | var future = decodeJsonChunked(input, 500); 48 | future.then((result) { 49 | print("done after ${sw.elapsedMicroseconds}us."); 50 | done = true; 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /archive/newsletter/20171124.md: -------------------------------------------------------------------------------- 1 | # Dart Language and Library Newsletter 2 | 2017-11-24 3 | @floitschG 4 | 5 | Welcome to the Dart Language and Library Newsletter. 6 | 7 | It is with some regret that I'm announcing the end of the Dart Language and Library Newsletter (at least written by me). Since Monday I am not on the language team anymore, and it would be unfair and manipulative to continue discussing language features. As a member of the Dart team, public comments and discussions do set the tone and raise expectations. While the newsletter usually avoided promises, I generally talked about features that I, as the tech lead, had influence over. I want to give the new team the same opportunity and give them the room to set their own direction. 8 | 9 | Writing the newsletters took me some time, but the positive feedback kept me going. Thank you all for the kind words I received. 10 | -------------------------------------------------------------------------------- /archive/newsletter/README.md: -------------------------------------------------------------------------------- 1 | # Dart Language and Library Newsletters 2 | 3 | This directory contains newsletters about the Dart language and 4 | some of its core libraries. 5 | For more information about the newsletters, see 6 | [this news post](https://news.dartlang.org/2017/11/dart-language-and-library-newsletters.html). 7 | 8 | * [November 10, 2017](20171110.md) 9 | * Did you know: Constructors (generative, factory, redirecting, ...) 10 | * Shorter final variables (`:=`) 11 | * [November 3, 2017](20171103.md) 12 | * Did you know: Chunked conversions 13 | * Optional positional and named parameters 14 | * [October 27, 2017](20171027.md) 15 | * Planned library changes for Dart 2.0: 16 | [docs/newsletter/lib/lib.md](lib/lib.md) 17 | * [October 20, 2017](20171020.md) 18 | * DateTime refactoring 19 | * [Date-Time Medium article](https://medium.com/@florian_32814/date-time-526a4f86badb) 20 | * [October 13, 2017](20171013.md) 21 | * Follow up: Evaluation order 22 | * Did you know: double.toString* 23 | * Why even simple language and library changes require so much thought, and why they often take so much time. 24 | * [October 6, 2017](20171006.md) 25 | * Did you know: Static initializers 26 | * Changing the evaluation order 27 | * [September 29, 2017](20170929.md) 28 | * Did you know: JSON encoding 29 | * Fixed-size integers 30 | * [September 22, 2017](20170922.md) 31 | * Did you know: Literal strings 32 | * Void as a type 33 | * [September 15, 2017](20170915.md) 34 | * Did you know: Labels 35 | * Making async functions start synchronously (instead of immediately returning) 36 | * [September 8, 2017](20170908.md) 37 | * Follow up: call 38 | * Fuzzy arrow 39 | * Enhanced type promotion 40 | * [September 1, 2017](20170901.md) 41 | * The case against call 42 | * Limitations on generic types 43 | * [August 25, 2017](20170825.md) 44 | * Separating mixins from normal classes 45 | * Corner cases: 46 | * Inference vs. manual types 47 | * Function types and covariant generics 48 | * [August 18, 2017](20170818.md) 49 | * Did you know: Trailing commas 50 | * Function type syntax: Options we considered 51 | * [August 11, 2017](20170811.md) 52 | * Follow ups 53 | * Void arrow functions 54 | * Deferred loading 55 | * Supporting const functions 56 | * Shadowing core libraries 57 | * [August 4, 2017](20170804.md) 58 | * Active development: 59 | * Better organization for docs 60 | * Void as a type 61 | * Updates to the core libraries 62 | * Deferred loading 63 | * [July 28, 2017](20170728.md) 64 | * Intro to the newsletters 65 | * 1.24 language changes: Function types, two void changes 66 | * The unified front end, and what that means for language changes 67 | * Active development: 68 | * Better organization for docs (focusing on 69 | [docs/language](https://github.com/dart-lang/sdk/tree/master/docs/language), with 70 | [docs/language/informal](https://github.com/dart-lang/sdk/tree/master/docs/language/informal) 71 | for specs that aren’t yet in the language spec) 72 | * Resolved part-of 73 | * Strong-mode clean zones 74 | * Void as a type 75 | * Enhanced type promotion 76 | * Updates to the core libraries 77 | -------------------------------------------------------------------------------- /resources/README.md: -------------------------------------------------------------------------------- 1 | This directory contains documents that aren't part of any particular language 2 | problem or solution but contain useful reference information for discussions. 3 | -------------------------------------------------------------------------------- /resources/type-system/normalization.md: -------------------------------------------------------------------------------- 1 | # Dart 2.0 Type Normalization 2 | 3 | leafp@google.com 4 | 5 | With union, intersection, and bottom types, there are types which are 6 | syntactically different, but are equal in the sense that they are mutual 7 | subtypes. This document defines a proposed normalization procedure for choosing 8 | a canonical representative of equivalence classes of types. Such a procedure 9 | might provide a basis for choosing between mutual subtypes when computing upper 10 | and lower bounds. It might also provide a more efficient implementation of type 11 | equality, since normal forms for types could be eagerly or lazy computed and 12 | cached. 13 | 14 | ## Types 15 | 16 | The syntactic set of types used in this draft are a slight simplification of 17 | full Dart types, as described in the subtyping 18 | document 19 | [here](https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md) 20 | 21 | We assume that type aliases are fully expanded, and that prefixed types are 22 | resolved to a canonical name. 23 | 24 | For convenience, we generally write function types with all named parameters in 25 | an unspecified canonical order, and similarly for the named fields of record 26 | types. In all cases unless otherwise specifically called out, order of named 27 | parameters and fields is semantically irrelevant: any two types with the same 28 | named parameters (named fields, respectively) are considered the same type. 29 | 30 | 31 | ## Normalization 32 | 33 | The **NORM** relation defines the canonical representative of classes of 34 | equivalent types. In the absence of legacy (*) types, it should be the case 35 | that for any two types which are mutual subtypes, their normal forms are 36 | syntactically identical up to identification of top types (`dynamic`, `void`, 37 | `Object?`). 38 | 39 | This is based on the following equations: 40 | - `T?? == T?` 41 | - `T?* == T?` 42 | - `T*? == T?` 43 | - `T** == T*` 44 | - `Null? == Null` 45 | - `Never? == Null` 46 | - `dynamic? == dynamic` 47 | - `void? == void` 48 | - `dynamic* == dynamic` 49 | - `void* == void` 50 | - `FutureOr == T` if `Future <: T` 51 | - `FutureOr == Future` if `T <: Future` 52 | - `X extend Never == Never` 53 | - `X & T == T` if `T <: X` 54 | - `X & T == X` if `X <: T` 55 | 56 | 57 | Applying these equations recursively and making a canonical choice when multiple 58 | equations apply gives us something like the following: 59 | 60 | - **NORM**(`T`) = `T` if `T` is primitive 61 | - **NORM**(`FutureOr`) = 62 | - let `S` be **NORM**(`T`) 63 | - if `S` is a top type then `S` 64 | - if `S` is `Object` then `S` 65 | - if `S` is `Object*` then `S` 66 | - if `S` is `Never` then `Future` 67 | - if `S` is `Null` then `Future?` 68 | - else `FutureOr` 69 | - **NORM**(`T?`) = 70 | - let `S` be **NORM**(`T`) 71 | - if `S` is a top type then `S` 72 | - if `S` is `Never` then `Null` 73 | - if `S` is `Never*` then `Null` 74 | - if `S` is `Null` then `Null` 75 | - if `S` is `FutureOr` and `R` is nullable then `S` 76 | - if `S` is `FutureOr*` and `R` is nullable then `FutureOr` 77 | - if `S` is `R?` then `R?` 78 | - if `S` is `R*` then `R?` 79 | - else `S?` 80 | - **NORM**(`T*`) = 81 | - let `S` be **NORM**(`T`) 82 | - if `S` is a top type then `S` 83 | - if `S` is `Null` then `Null` 84 | - if `S` is `R?` then `R?` 85 | - if `S` is `R*` then `R*` 86 | - else `S*` 87 | - **NORM**(`X extends T`) = 88 | - if `T` is `Never` then `Never` 89 | - if `T` is a type variable `Y` and **NORM**(`Y`) is `Never` then `Never` 90 | - else `X extends T` 91 | - **NORM**(`X & T`) = 92 | - let `S` be **NORM**(`T`) 93 | - if `S` is `Never` then `Never` 94 | - if `S` is a top type then `X` 95 | - if `S` is `X` then `X` 96 | - if **NORM(B)** is a subtype of S where `B` is the bound of `X` then `X` 97 | - else `X & S` 98 | - **NORM**(`C`) = `C` where `Ri` is **NORM**(`Ti`) 99 | - **NORM**(`R Function(S)`) = `R1 Function(S1)` 100 | - where `R1` = **NORM**(`R`) 101 | - and `B1` = **NORM**(`B`) 102 | - and `S1` = **NORM**(`S`) 103 | - **NORM**(`(S0, ..., Sn, {T0 d0, ..., Tm dm})`) = `(S0', ..., Sn', {T0' d0, ..., Tm' dm})` 104 | - where `Si'` = **NORM**(`Si`) 105 | - and `Ti'` = **NORM**(`Ti`) 106 | 107 | Note that there is currently no place in the type system where normalization can 108 | apply to intersection types (promoted types). The rule is included here for 109 | completeness. 110 | -------------------------------------------------------------------------------- /resources/type-system/strict-casts.md: -------------------------------------------------------------------------------- 1 | # Strict casts static analysis option 2 | 3 | This document specifies the "Strict casts" mode enabled with a static 4 | analysis option, new in Dart 2.16. As a static analysis option, we only intend 5 | to implement this feature in the Dart Analyzer. Under this feature, any 6 | implicit cast is reported as an analyzer "Hint" (a warning). 7 | 8 | Note that under the null safe type system, the only expressions which may be 9 | implicitly cast are those with a static type of `dynamic`. These are exactly 10 | the implicit casts reported in the strict casts mode. 11 | 12 | ## Enabling strict casts 13 | 14 | To enable strict casts, set the `strict-casts` option to `true`, under 15 | the Analyzer's `language` section: 16 | 17 | ```yaml 18 | analyzer: 19 | language: 20 | strict-casts: true 21 | ``` 22 | 23 | ## Motivation 24 | 25 | Static analysis can provide many benefits which require meaningful static 26 | types. For example, when a value of one type is _not assignable_ to a variable 27 | of another type, the error is reported by static analysis. However, when a 28 | value has a static type of `dynamic`, no error is reported. Such a value is 29 | always assignable, because a cast is implicitly inserted at runtime, which may 30 | fail. For example: 31 | 32 | ```dart 33 | import 'dart:convert'; 34 | void main() { 35 | var decoded = jsonDecode(/* some JSON */); 36 | if (decoded['foo']) { 37 | print('Got foo.'); 38 | } 39 | } 40 | ``` 41 | 42 | The expression used in an if-statement's condition must have a static type of 43 | `bool`. Without the strict casts mode, an expression with a static type of 44 | `dynamic` (such as the example's `decoded['foo']`) is allowed, due to the 45 | implicit cast to `bool` which will occur at runtime. The strict casts mode aims 46 | to warn about such code during static analysis. 47 | 48 | Note that another way to root out implicit casts from the `dynamic` type is to 49 | ban all use of the `dynamic` type. However, there are many common APIs which 50 | return `dynamic`-typed values, such as the `dart:convert` library's 51 | JSON-decoding functions (referenced in the example above). The strict casts 52 | mode allows the use of such APIs, requiring only that such `dynamic`-typed 53 | values are _explicitly_ cast before using them in a position where a value of 54 | non-`dynamic` type is expected. 55 | 56 | ## Differences from "no implicit casts" mode 57 | 58 | The strict casts mode is very similar to another static analysis mode supported 59 | by the Dart analyzer: "no implicit casts," now deprecated in favor of the 60 | strict casts mode. The new mode reports all of the same implicit casts which 61 | the "no implicit casts" mode does, and it also reports three more cases, 62 | detailed below. 63 | 64 | ### for-in loop iteration 65 | 66 | A value with a static type of `dynamic` which is used as the iterator 67 | expression in a for-in loop is reported. For example: 68 | 69 | ```dart 70 | void foo(dynamic arg) { 71 | for (var value in arg) { /* ... */ } 72 | } 73 | ``` 74 | 75 | ### spread expression 76 | 77 | A value with a static type of `dynamic` which is used as the expression in a 78 | spread is reported. For example: 79 | 80 | ```dart 81 | void foo(dynamic arg) { 82 | [...arg]; 83 | } 84 | ``` 85 | 86 | ### yield-each expression 87 | 88 | A value with a static type of `dynamic` which is used as the expression in a 89 | yield-each expression is reported. For example: 90 | 91 | ```dart 92 | Stream foo(dynamic arg) async* { 93 | yield* arg; 94 | } 95 | ``` 96 | -------------------------------------------------------------------------------- /resources/type-system/strict-raw-types.md: -------------------------------------------------------------------------------- 1 | # Strict raw types static analysis option 2 | 3 | This document specifies the "Strict raw types" mode enabled with a static 4 | analysis option. As a static analysis option, we only intend to implement this 5 | feature in the Dart Analyzer. Under this feature, a type with omitted type 6 | argument(s) is defined as a "raw type." Dart fills in such type arguments with 7 | their bounds, or `dynamic` if there are no bounds. 8 | 9 | ## Enabling strict raw types 10 | 11 | To enable strict raw types, set the `strict-raw-types` option to `true`, under 12 | the Analyzer's `language` section: 13 | 14 | ```yaml 15 | analyzer: 16 | language: 17 | strict-raw-types: true 18 | ``` 19 | 20 | ## Motivation 21 | 22 | It is possible to write Dart code that passes all static type analysis and 23 | compile-time checks that is guaranteed to result in runtime errors. Common 24 | examples include runtime type errors, and no-such-method errors. Developers are 25 | often surprised to see such errors at runtime, which look like they should be 26 | caught at compile time. 27 | 28 | The strict raw types mode aims to highlight such code during static analysis. 29 | We can look at some common examples: 30 | 31 | ```dart 32 | void main() { 33 | List a = [1, 2, 3]; 34 | } 35 | ``` 36 | 37 | Developers often think that inference fills in the type of `a` from the right 38 | side of the assignment. It may look like `a` has the type `List`. But Dart 39 | fills in omitted type arguments, like `E` on `List`, with `dynamic` (or the 40 | corresponding type parameter's bound); `List a;` is purely a shorthand for 41 | `List a;`. Inference then flows from `a` onto the expression on the 42 | right side of the assignment. This is more obvious in another example: 43 | 44 | ```dart 45 | void main() { 46 | List a = [1, 2, 3]..forEach((e) => print(e.length)); 47 | var b = [4, 5, 6]..forEach((e) => print(e.length)); 48 | } 49 | ``` 50 | 51 | The first statement does not result in any static analysis errors, since the 52 | type of the list is inferred to be `List`. Instead, the code results 53 | in a runtime no-such-method error, when the `length` getter is called on an 54 | `int`. 55 | 56 | The second statement, however, allows the type of the list to be inferred from 57 | its elements, as `List`, which results in a static analysis type error, 58 | which notes that the getter `length` is not defined on `int`. 59 | 60 | Raw types can also lead to unintended dynamic dispatch: 61 | 62 | ```dart 63 | void main() { 64 | List a = [1, 2, 3]; 65 | a.forEach((e) => print(e.isEven)); 66 | } 67 | ``` 68 | 69 | The developer likely does not realize that the parameter `e` of the callback is 70 | `dynamic`, and that the call to `isEven` is a dynamic dispatch. 71 | 72 | Reporting strict raw types encourages developers to fill in omitted type 73 | arguments, hopefully with something other than `dynamic`. In cases where the 74 | only good type is `dynamic`, then including it as an explicit type argument 75 | avoids the raw type, and makes the dynamic behavior more explicit in the code. 76 | 77 | ## Conditions for a raw type Hint 78 | 79 | Any raw type results in a raw type Hint, except under the following conditions: 80 | 81 | * the raw type is on the right side of an `as` or an `is` expression 82 | * the raw type is defined by a class, mixin, or typedef annotated with the 83 | `optionalTypeArgs` annotation from the meta package. 84 | 85 | ## Examples 86 | 87 | This section is non-normative. It does not represent an exhaustive selection of 88 | conditions for a raw type Hint. 89 | 90 | ```dart 91 | import 'package:meta/meta.dart'; 92 | 93 | List l1 = [1, 2, 3]; // Hint 94 | List l2 = [1, 2, 3]; // Hint 95 | final f1 = Future.value(7); // OK 96 | 97 | fn1(Map map) => print(map); // Hint 98 | Map fn2() => {}; // Hint 99 | 100 | class C1 { 101 | List l3 = [1, 2, 3]; // Hint 102 | print([] is Set); // OK 103 | 104 | m(Map map) => print(map); // Hint 105 | } 106 | 107 | class C2 {} 108 | 109 | class C3 extends C2 {} // Hint 110 | class C4 implements C2 {} // Hint 111 | class C5 with C2 {} // Hint 112 | 113 | typedef Callback = void Function(T); 114 | 115 | Callback = (int n) => print(n); // Hint 116 | 117 | @optionalTypeArgs 118 | class C6 {} 119 | 120 | C6 a; // OK 121 | List b; // OK 122 | C6 c; // Hint 123 | 124 | class C7 extends C6 {} // OK 125 | ``` 126 | -------------------------------------------------------------------------------- /resources/variance/showWidening.sml: -------------------------------------------------------------------------------- 1 | (* Run this using `sml showWidening.sml` to get a printout of the systematic 2 | * iteration over all combinations of a small set of cases: Declare a class 3 | * `C` with a single type argument and a single member which is a getter `g` 4 | * or a method `m` (thus covering a covariant and a contravariant placement 5 | * of a type in a member signature). Next, declare a variable `c` whose type 6 | * annotation is `C<... T>` where `T` is a type which is not modeled in more 7 | * detail (any type would do), and `...` stands for a use-site variance 8 | * modifier (absent, `out`, `inout`, or `in`). Finally, the printout shows 9 | * the return type of the getter respectively the parameter type of the 10 | * method, indicating how the declaration-site and use-site variance 11 | * annotations give rise to an 'effective' member signature. 12 | *) 13 | 14 | use "typeModel.sml"; 15 | use "widen.sml"; 16 | open List; 17 | 18 | (* ---------- Validation *) 19 | 20 | fun checkConfig (D_LEGACY, _, U_IN, _, _) = false 21 | | checkConfig (D_OUT, _, U_IN, _, _) = false 22 | | checkConfig (D_IN, _, U_OUT, _, _) = false 23 | | checkConfig (_, _, _, _, _) = true; 24 | 25 | fun checkCovariantConfig c = 26 | let fun f (D_LEGACY, _, _, _, _) = true 27 | | f (D_OUT, X, _, _, T) = occursOnlyCovariantly X T 28 | | f (D_INOUT, _, _, _, _) = true 29 | | f (D_IN, X, _, _, T) = occursOnlyContravariantly X T 30 | in checkConfig c andalso f c 31 | end; 32 | 33 | fun checkContravariantConfig c = 34 | let fun f (D_LEGACY, _, _, _, _) = true 35 | | f (D_OUT, X, _, _, T) = occursOnlyContravariantly X T 36 | | f (D_INOUT, _, _, _, _) = true 37 | | f (D_IN, X, _, _, T) = occursOnlyCovariantly X T 38 | in checkConfig c andalso f c 39 | end; 40 | 41 | (* ---------- Auxiliary testing functions *) 42 | 43 | val concat = String.concat; 44 | 45 | fun resultToString NONE = "-" 46 | | resultToString (SOME true) = "true" 47 | | resultToString (SOME false) = "false"; 48 | 49 | fun boolToString true = "true" 50 | | boolToString false = "false"; 51 | 52 | fun classOfConfig c member comment = 53 | let val (d, X, u, T, _) = c 54 | val receiverClassString = 55 | case d of D_LEGACY => "Cl" 56 | | D_OUT => "Co" 57 | | D_INOUT => "Ci" 58 | | D_IN => "Con" 59 | val typeParametersString = 60 | case d of D_LEGACY => concat ["<", X, ">"] 61 | | D_OUT => concat [""] 62 | | D_INOUT => concat [""] 63 | | D_IN => concat [""] 64 | val typeArgumentsString = 65 | case u of U_NONE => "" 66 | | U_OUT => "" 67 | | U_INOUT => "" 68 | | U_IN => "" 69 | | U_STAR => "<*>" 70 | in concat [ 71 | "class ", receiverClassString, typeParametersString, 72 | " {\n ", member, "\n}\n", 73 | receiverClassString, 74 | typeArgumentsString, 75 | " c; // ", comment, "\n\n" 76 | ] 77 | end; 78 | 79 | (* ---------- Look at the outcome from `widen`, `narrow` *) 80 | 81 | fun showGetter (c as (d, X, u, T, S)) = 82 | let val ok = checkCovariantConfig c 83 | val resultString = 84 | if ok then 85 | let val (widenResult, widened) = widen c 86 | in concat [ 87 | "c.g ", 88 | if widened then "widened" else "ok", 89 | ": ", 90 | typeToString widenResult 91 | ] 92 | end 93 | else "Impossible" 94 | val (_, _, _, _, t) = c 95 | val member = concat [typeToString t, " get g => ...;"] 96 | in print (classOfConfig c member resultString) 97 | end; 98 | 99 | fun showMethod (c as (d, X, u, T, S)) = 100 | let val ok = checkContravariantConfig c 101 | val resultString = 102 | if ok then 103 | let val (narrowResult, narrowed) = narrow c 104 | in concat ["c.m(_) ", 105 | if narrowed then "narrowed" else "ok", 106 | ": ", 107 | typeToString narrowResult 108 | ] 109 | end 110 | else "Impossible" 111 | val (_, _, _, _, t) = c 112 | val member = concat ["void m(", typeToString t, " arg) {}"] 113 | in print (classOfConfig c member resultString) 114 | end; 115 | 116 | val _ = print "---------- Show code plus {widen,narrow} outcome.\n"; 117 | val _ = map showGetter allConfigs; 118 | val _ = map showMethod allConfigs; 119 | -------------------------------------------------------------------------------- /resources/warnings.md: -------------------------------------------------------------------------------- 1 | # Dart Warnings 2 | 3 | When Dart was first designed, the intent was that Dart applications would be 4 | deployed and run from unprocessed source code on end user machines. That meant 5 | that a heavyweight compilation process involving complex type checking and type 6 | inference could slow application startup. Thus the type system was optional, and 7 | type errors were warnings. 8 | 9 | The move to a mandatory static type system in Dart 2.0 turned most of the 10 | warnings related to the type system into full compile errors. But there were a 11 | few specified diagnostics that remained warnings. Further, many language 12 | proposals define additional warnings (for example, unreachable cases in switch 13 | statements in Dart 3.0). 14 | 15 | It has been a source of confusion on the team as to whether every Dart tool is 16 | required to report all of those warnings, and whether tools are prohibited from 17 | reporting any warnings not defined by the language. 18 | 19 | This document, along with [a corresponding update to the language spec][spec 20 | change] clarifies that. 21 | 22 | [spec change]: https://github.com/dart-lang/language/pull/3570 23 | 24 | ## Specifying warnings 25 | 26 | After Dart 2.0 change most static warnings to type errors, there were few 27 | warnings left in the spec. Because of that, we have sometimes considered 28 | removing all warnings from the spec and leaving it entirely up to implementation 29 | teams to define them and decide what to report and when. 30 | 31 | However, when writing feature specifications for new language features, we often 32 | find ourselves wanting to suggest new warnings. This is *not* because we want to 33 | force every Dart implementation to report every one of these warnings. It's 34 | because it's important to think holistically about the entire user experience 35 | when defining a new language feature. The tooling experience—warnings, lints, 36 | migration tools, quick fixes etc.—around a feature can make the difference 37 | between a good feature and a bad feature. 38 | 39 | Putting warnings (and lints, quick fixes, etc.) in feature proposals helps 40 | ensure the language team does that due diligence. At the same time, we don't 41 | want to discard the expertise of the implementation teams about what makes the 42 | best user experience and diagnostics for their tool. We're just trying to do 43 | good, thorough design. 44 | 45 | ## Reporting warnings 46 | 47 | Given a set of specified warnings, what obligations do Dart implementations have 48 | to implement them? In principle, it would be good if all of our tools behaved 49 | the same and they all reported all warnings. That way users get a consistent 50 | experience. 51 | 52 | But the reality is that we have two very different static analysis 53 | implementations: analyzer and common front end (CFE). Requiring both of them to 54 | report all of the same warnings would be a large and continuous engineering 55 | effort for relatively little benefit. Most warnings are seen by users and 56 | addressed by them in their IDE. As long as analyzer reports them, most of the 57 | user benefit is provided. The CFE isn't usually invoked until the user wants to 58 | generate code for a runnable program. If they choose to do that, they are 59 | implicitly ignoring warnings anyway, so having the CFE report them adds only 60 | marginal value. 61 | 62 | Also, some warnings are specific to certain tools. For example, a web compiler 63 | might report warnings on `is int` and `is double` since those may not behave as 64 | expected in JavaScript where the same representation is used for all numbers. It 65 | would be strange and confusing if a compiler *not* targeting the web reported that 66 | warning when it wouldn't be relevant on the platform the user is compiling for. 67 | 68 | Consider that the reason these diagnostics being warnings and not errors is 69 | specifically to allow variation in how they how they are reported to and handled 70 | by users. If there's a diagnostic that we really feel should always be presented 71 | to all users and they should definitely handle it... it should probably be an 72 | error. 73 | 74 | ## Warning reporting requirements 75 | 76 | Given all of the above, the position of the language team on warnings is: 77 | 78 | * The language specification and feature specifications for new features may 79 | suggest new warnings that the language team believes will help the user 80 | experience. 81 | 82 | * A conforming Dart implementation is free to report any, all, some, or none 83 | of those specified warnings. 84 | 85 | * Further, a Dart implementation may choose to report its own warnings that 86 | aren't part of the language spec or any feature proposal. 87 | 88 | *In other words, both the language team and implementation teams may add to the 89 | set of all possible warnings, and the implementation teams can decide which of 90 | those warnings make sense for their tools to report.* 91 | 92 | *In practice, we expect the analyzer to report them all (and let us know if we 93 | specify any that they believe aren't helpful). Going forward, it's likely the 94 | CFE will stop reporting any of them.* 95 | -------------------------------------------------------------------------------- /specification/.gitignore: -------------------------------------------------------------------------------- 1 | dartLangSpec*.aux 2 | dartLangSpec*.idx 3 | dartLangSpec*.ilg 4 | dartLangSpec*.ind 5 | dartLangSpec*.log 6 | dartLangSpec*.out 7 | dartLangSpec*.pdf 8 | dartLangSpec*.toc 9 | dartLangSpec-terse.tex 10 | *-hash.tex 11 | *-list.txt 12 | .dart_tool/ 13 | .packages 14 | firebase/ 15 | -------------------------------------------------------------------------------- /specification/Makefile: -------------------------------------------------------------------------------- 1 | NAME=dartLangSpec 2 | SPEC=$(NAME).tex 3 | HASH=$(NAME)-hash.tex 4 | LIST=$(NAME)-list.txt 5 | TERSE_SPEC=$(NAME)-terse.tex 6 | TERSE_IDX=$(NAME)-terse.idx 7 | HASHER=scripts/addlatexhash.dart 8 | 9 | pdf: 10 | pdflatex $(SPEC) 11 | makeindex $(NAME).idx 12 | pdflatex $(SPEC) 13 | makeindex $(NAME).idx 14 | pdflatex $(SPEC) 15 | pdflatex $(SPEC) 16 | 17 | pdfhash: hash_and_list 18 | pdflatex $(HASH) 19 | makeindex $(NAME)-hash.idx 20 | pdflatex $(HASH) 21 | makeindex $(NAME)-hash.idx 22 | pdflatex $(HASH) 23 | pdflatex $(HASH) 24 | 25 | dvi: 26 | latex $(SPEC) 27 | makeindex $(NAME).idx 28 | latex $(SPEC) 29 | makeindex $(NAME).idx 30 | latex $(SPEC) 31 | latex $(SPEC) 32 | 33 | dvihash: hash_and_list 34 | latex $(HASH) 35 | makeindex $(NAME)-hash.idx 36 | latex $(HASH) 37 | makeindex $(NAME)-hash.idx 38 | latex $(HASH) 39 | latex $(HASH) 40 | 41 | hash_and_list: 42 | dart $(HASHER) $(SPEC) $(HASH) $(LIST) 43 | 44 | terse: 45 | dart scripts/simplify_specification.dart 46 | 47 | tersepdf: 48 | pdflatex $(TERSE_SPEC) 49 | makeindex $(TERSE_IDX) 50 | pdflatex $(TERSE_SPEC) 51 | makeindex $(TERSE_IDX) 52 | pdflatex $(TERSE_SPEC) 53 | pdflatex $(TERSE_SPEC) 54 | 55 | help: 56 | @echo "Goals:" 57 | @echo " pdf, dvi: generate the pdf/dvi file containing the spec" 58 | @echo " pdfhash, dvihash: ditto, with location markers filled in" 59 | @echo " cleanish: remove [pdf]latex generated intermediate files" 60 | @echo " clean: remove all generated files" 61 | 62 | cleanish: 63 | rm -f *.aux *.log *.toc *.out *.idx *.ilg *.ind 64 | 65 | clean: cleanish 66 | rm -f *.dvi *.pdf $(HASH) $(LIST) 67 | -------------------------------------------------------------------------------- /specification/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "firebase", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "redirects": [ 10 | { 11 | "source": "/DartLangSpecDraft.pdf", 12 | "destination": "https://storage.googleapis.com/dart-specification/DartLangSpecDraft.pdf", 13 | "type": 302 14 | }, 15 | { 16 | "source": "/pr/:pr/DartLangSpecDraft.pdf", 17 | "destination": "https://storage.googleapis.com/dart-specification/pr/:pr/DartLangSpecDraft.pdf", 18 | "type": 301 19 | }, 20 | { 21 | "source": "**", 22 | "destination": "https://dart.dev/resources/language/spec", 23 | "type": 302 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /specification/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: scripts 2 | publish_to: none 3 | environment: 4 | sdk: ">=3.7.0 <4.0.0" 5 | dependencies: 6 | convert: ^3.0.1 7 | crypto: ^3.0.1 8 | -------------------------------------------------------------------------------- /specification/scripts/build_pdf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S bash --norc 2 | 3 | set -ex 4 | 5 | apt-get update -qq 6 | apt-get install -y --no-install-recommends \ 7 | build-essential \ 8 | texlive-latex-base \ 9 | texlive-latex-extra \ 10 | texlive-fonts-recommended \ 11 | lmodern 12 | cd specification 13 | make 14 | mkdir -p artifacts 15 | if [ "$BRANCH_NAME" == "main" ]; then 16 | cp dartLangSpec.pdf artifacts/DartLangSpecDraft.pdf 17 | elif [ "$_PR_NUMBER" != "" ]; then 18 | mkdir -p artifacts/pr/$_PR_NUMBER 19 | cp dartLangSpec.pdf artifacts/pr/$_PR_NUMBER/DartLangSpecDraft.pdf 20 | fi 21 | 22 | -------------------------------------------------------------------------------- /templates/implementation_meta_issue.txt: -------------------------------------------------------------------------------- 1 | Title: Implementation tracking issue for 2 | 3 | Assignee: 4 | Labels: 5 | Projects: 6 | 7 | Body: 8 | 9 | This issue is for tracking implementation of . 10 | 11 | The implementation plan for this issue is . 12 | 13 | ## TODO: 14 | 15 | - [ ] Discussion and feedback 16 | - [ ] Implementation team sign off (this issue): 17 | - [ ] Issue for implementation in dart2js: 18 | - [ ] Issue for implementation in the VM: 19 | - [ ] Issue for implementation in DDC: 20 | - [ ] Issue for implementation in CFE: 21 | - [ ] Issue for implementation in Analyzer: 22 | - [ ] Issue for implementation in IntelliJ: 23 | - [ ] Issue for implementation in [Github syntax highlighting](https://github.com/dart-lang/dart-syntax-highlight/): 24 | - [ ] Issue for copying Github grammar for use with VS Code: 25 | - [ ] Issue for implementation in Grok: 26 | - [ ] Issue for implementation in Dartfmt: 27 | - [ ] Issue for implementation in Dartdoc: 28 | - [ ] Issue for [highlight.js support](https://github.com/highlightjs/highlight.js) (api.dart.dev, api.pub.dev, Dartdoc): 29 | - [ ] Issue for implementation in build systems and Angular compiler: 30 | - [ ] Issue for VM Service support: 31 | - [ ] Issue for web debugging support: 32 | - [ ] Issue for [CodeMirror support](https://github.com/codemirror/CodeMirror/) (Cider, DartPad): 33 | - [ ] Issue for language tests: 34 | - [ ] Issue for documentation: 35 | - [ ] Issue for specification: 36 | - [ ] Issue for code cleanup: 37 | -------------------------------------------------------------------------------- /tools/corpus/.gitignore: -------------------------------------------------------------------------------- 1 | # Don't commit the downloaded files. 2 | download/ 3 | out/ 4 | -------------------------------------------------------------------------------- /tools/corpus/README.md: -------------------------------------------------------------------------------- 1 | This directory contains a package with scripts for downloading corpora of open 2 | source Dart code for automated analysis. There are a few scripts for 3 | downloading from various places: 4 | 5 | * `clone_flutter_apps.dart`: Clones GitHub repositories linked to from 6 | [github.com/tortuvshin/open-source-flutter-apps](https://github.com/tortuvshin/open-source-flutter-apps), which is a registry of open source Flutter apps. 7 | Downloads them to `download/apps`. 8 | 9 | * `clone_widgets.apps.dart`: Clones GitHub repositories referenced by 10 | [itsallwidgets.com](https://itsallwidgets.com/), which is a collection of 11 | open source Flutter apps and widgets. Downloads them to `download/widgets`. 12 | 13 | * `download_packages.dart`: Downloads recent packages from 14 | [pub.dev](https://pub.dev/). Downloads to `download/pub`. 15 | 16 | Once a corpus is downloaded, there is another script that copies over just the 17 | `.dart` files while discardinging "uninteresting" files like generated ones: 18 | 19 | * `copy_corpus.dart`: Copies `.dart` files from one of the download 20 | directories. Pass `apps`, `widgets`, `pub`, etc. Can also copy sources from 21 | the Dart SDK repo (`dart`) or Flutter repo (`flutter`). For that to work, 22 | those repos must be in directories next to the language repo. 23 | 24 | You can pass `--sample=` to take a random sample of a corpus. For 25 | example, `--sample=5` will copy over only 5% of the files, chosen randomly. 26 | -------------------------------------------------------------------------------- /tools/corpus/scripts/bin/clone_flutter_apps.dart: -------------------------------------------------------------------------------- 1 | import 'package:corpus/utils.dart'; 2 | 3 | /// Match URIs that point to GitHub repos. Look for a trailing ")" (after an 4 | /// allowed trailing "/") in order to only find Markdown link URIs that are 5 | /// directly to repos and not to paths within them like the images in the 6 | /// header. 7 | final _gitHubRepoPattern = 8 | RegExp(r'https://github.com/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/?\)'); 9 | 10 | const _readmeUri = 11 | 'https://raw.githubusercontent.com/tortuvshin/open-source-flutter-apps/' 12 | 'refs/heads/master/README.md'; 13 | 14 | /// Clones the GitHub repos listed on: 15 | /// 16 | /// https://github.com/tortuvshin/open-source-flutter-apps 17 | /// 18 | /// Downloads them to downloads/apps. 19 | void main(List arguments) async { 20 | clean('download/apps'); 21 | 22 | print('Getting README.md...'); 23 | var readme = await httpGet(_readmeUri); 24 | 25 | // Find all the repo URLs and remove the duplicates. 26 | var repoPaths = _gitHubRepoPattern 27 | .allMatches(readme) 28 | .map((match) => (user: match[1]!, repo: match[2]!)) 29 | .toSet() 30 | .toList(); 31 | 32 | // Skip the reference to the repo itself. 33 | repoPaths.remove((user: 'tortuvshin', repo: 'open-source-flutter-apps')); 34 | 35 | var downloader = Downloader(totalResources: repoPaths.length, concurrency: 5); 36 | for (var (:user, :repo) in repoPaths) { 37 | downloader.cloneGitHubRepo('apps', user, repo); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/corpus/scripts/bin/clone_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:corpus/utils.dart'; 2 | 3 | /// Match URIs that point to GitHub repos. 4 | final _gitHubRepoPattern = 5 | RegExp(r'https://github.com/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)'); 6 | 7 | /// Download open source apps from itsallwidgets.com. 8 | void main(List arguments) async { 9 | clean("download/widgets"); 10 | 11 | print('Getting page feed...'); 12 | var feed = 13 | await httpGetJson('https://itsallwidgets.com/feed?open_source=true'); 14 | 15 | var repos = <({String user, String repo})>{}; 16 | for (var entry in (feed as List)) { 17 | var entryMap = entry as Map; 18 | if (entryMap['type'] != 'app') continue; 19 | 20 | var repo = entryMap['repo_url'] as String?; 21 | if (repo == null) continue; 22 | 23 | // Only know how to download from GitHub. There are a couple of BitBucket 24 | // ones in there. 25 | if (_gitHubRepoPattern.firstMatch(repo) case var match?) { 26 | repos.add((user: match[1]!, repo: match[2]!)); 27 | } 28 | } 29 | 30 | var downloader = Downloader(totalResources: repos.length, concurrency: 10); 31 | for (var (:user, :repo) in repos) { 32 | downloader.cloneGitHubRepo('widgets', user, repo); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tools/corpus/scripts/bin/copy_corpus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:math'; 3 | 4 | import 'package:args/args.dart'; 5 | import 'package:path/path.dart' as p; 6 | 7 | /// What percentage of files should be copied over. Used to take a random 8 | /// sample of a corpus. 9 | int _samplePercent = 100; 10 | 11 | final _random = Random(); 12 | 13 | const _ignoreDirs = [ 14 | 'pkg/dev_compiler/gen/', 15 | 'tests/co19/', 16 | 'third_party/observatory_pub_packages/', 17 | 'tools/sdks/', 18 | 'out/', 19 | 'xcodebuild/', 20 | 21 | // Redundant stuff in Flutter. 22 | 'bin/cache/', 23 | 24 | // Redundant packages that are in the SDK. 25 | 'analyzer-', 26 | 'compiler_unsupported-', 27 | 'dev_compiler-', 28 | ]; 29 | 30 | // Note! Assumes the Dart SDK and Flutter repos have been cloned in 31 | // directories next to the corpus repo. Also assumes this script has been run 32 | // from the root directory of this repo. 33 | const _corpora = [ 34 | ('apps', 'download/apps'), 35 | ('dart', '../../../dart/sdk'), 36 | ('flutter', '../../../flutter'), 37 | ('pub', 'download/pub'), 38 | ('widgets', 'download/widgets'), 39 | ]; 40 | 41 | final generatedSuffixes = ['.g.dart', '.freezed.dart']; 42 | 43 | void main(List arguments) async { 44 | var argParser = ArgParser(); 45 | argParser.addFlag('omit-slow'); 46 | argParser.addOption('sample', abbr: 's', defaultsTo: '100'); 47 | 48 | var argResults = argParser.parse(arguments); 49 | _samplePercent = int.parse(argResults['sample']); 50 | 51 | for (var (name, directory) in _corpora) { 52 | if (arguments.contains(name)) await copyDir(directory, name); 53 | } 54 | } 55 | 56 | Future copyDir(String fromDirectory, String toDirectory) async { 57 | // If we're taking a random sample, put that in a separate directory. 58 | if (_samplePercent != 100) { 59 | toDirectory += '-$_samplePercent'; 60 | } 61 | 62 | var i = 0; 63 | var inDir = Directory(fromDirectory); 64 | 65 | await inDir.list(recursive: true, followLinks: false).listen((entry) async { 66 | var relative = p.relative(entry.path, from: inDir.path); 67 | 68 | if (entry is Link) return; 69 | if (entry is! File || !entry.path.endsWith('.dart')) return; 70 | 71 | // Skip redundant stuff. 72 | for (var ignore in _ignoreDirs) { 73 | if (relative.startsWith(ignore)) return; 74 | } 75 | 76 | if (_random.nextInt(100) >= _samplePercent) return; 77 | 78 | // If the path is in a subdirectory starting with '.', ignore it. 79 | var parts = p.split(relative); 80 | if (parts.any((part) => part.startsWith('.'))) return; 81 | 82 | var outPath = p.join('out', toDirectory, relative); 83 | 84 | var outDir = Directory(p.dirname(outPath)); 85 | if (!await outDir.exists()) await outDir.create(recursive: true); 86 | 87 | await entry.copy(outPath); 88 | 89 | i++; 90 | if (i % 100 == 0) print(relative); 91 | }).asFuture(); 92 | } 93 | -------------------------------------------------------------------------------- /tools/corpus/scripts/bin/download_packages.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:corpus/utils.dart'; 4 | 5 | const _totalPackages = 2000; 6 | 7 | void main(List arguments) async { 8 | clean('download/pub'); 9 | 10 | // Iterate through the pages (which are in most recent order) until we get 11 | // enough packages. 12 | var packagePage = 'http://pub.dartlang.org/api/packages'; 13 | var downloaded = 1; 14 | 15 | var downloader = Downloader(totalResources: _totalPackages); 16 | for (;;) { 17 | downloader.log('Getting index page $downloaded...'); 18 | var packages = await httpGetJson(packagePage); 19 | 20 | for (var package in packages['packages']) { 21 | downloader.withResource((logger) async { 22 | var name = package['name'] as String; 23 | var version = package['latest']['version'] as String; 24 | var archiveUrl = package['latest']['archive_url'] as String; 25 | 26 | try { 27 | logger.begin('Downloading $archiveUrl...'); 28 | var archiveBytes = await httpGetBytes(archiveUrl); 29 | var tarFile = 'download/pub/$name-$version.tar.gz'; 30 | await File(tarFile).writeAsBytes(archiveBytes); 31 | 32 | logger.log('Extracting $tarFile...'); 33 | var outputDir = 'download/pub/$name-$version'; 34 | await Directory(outputDir).create(recursive: true); 35 | var result = 36 | await Process.run('tar', ['-xf', tarFile, '-C', outputDir]); 37 | 38 | if (result.exitCode != 0) { 39 | logger.end('Could not extract $tarFile:\n${result.stderr}'); 40 | } else { 41 | await File(tarFile).delete(); 42 | logger.end('Finished $outputDir'); 43 | } 44 | } catch (error) { 45 | logger.end('Error downloading $archiveUrl:\n$error'); 46 | } 47 | }); 48 | 49 | downloaded++; 50 | if (downloaded >= _totalPackages) return; 51 | } 52 | 53 | var nextUrl = packages['next_url']; 54 | if (nextUrl is! String) break; 55 | packagePage = nextUrl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tools/corpus/scripts/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: corpus 2 | environment: 3 | sdk: '^3.0.0' 4 | dependencies: 5 | args: '^2.6.0' 6 | http: '^1.2.2' 7 | path: '^1.9.1' 8 | pool: '^1.5.1' 9 | -------------------------------------------------------------------------------- /tools/plaintext_grammar.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | /// Reads the "dartLangSpec.tex" and prints out all of the grammar rules it 4 | /// contains as plaintext. 5 | 6 | /// Matches Tex keyword references like: 7 | /// 8 | /// \LATE 9 | /// \FINAL{} 10 | final keywordRegExp = RegExp(r'\\([A-Z]+)(\{\})?'); 11 | 12 | /// Matches non-terminals like: 13 | /// 14 | /// 15 | final ruleRegExp = RegExp(r'<(\w+)>'); 16 | 17 | void main(List arguments) { 18 | if (arguments.isEmpty) { 19 | print("Usage: dart plaintext_grammar.dart "); 20 | exit(1); 21 | } 22 | 23 | var specFile = File(arguments[0]); 24 | 25 | var inGrammar = false; 26 | for (var line in specFile.readAsLinesSync()) { 27 | line = line.trimRight(); 28 | 29 | if (line == r'\begin{grammar}') { 30 | inGrammar = true; 31 | } else if (line == r'\end{grammar}') { 32 | print(''); 33 | inGrammar = false; 34 | } else if (inGrammar) { 35 | line = line 36 | .replaceAll('`', "'") 37 | .replaceAll(r'\alt', '|') 38 | .replaceAll(r' \gnewline{}', '') 39 | .replaceAll(r'\gtilde{}', '~') 40 | .replaceAll(r'\_', '_') 41 | .replaceAll(r'\{', '{') 42 | .replaceAll(r'\}', '}') 43 | .replaceAll(r'\&', '&') 44 | .replaceAll(r'\%', '%') 45 | .replaceAll(r'\gtgtgt', '>>>') 46 | .replaceAll(r'\gtgt', '>>') 47 | .replaceAll(r'\ltltlt', '<<<') 48 | .replaceAll(r'\ltlt', '<<') 49 | .replaceAll(r'\\b', r'\b') 50 | .replaceAll(r'\\f', r'\f') 51 | .replaceAll(r'\\n', r'\n') 52 | .replaceAll(r'\\r', r'\r') 53 | .replaceAll(r'\\t', r'\t') 54 | .replaceAll(r'\\u', r'\u') 55 | .replaceAll(r'\\v', r'\v') 56 | .replaceAll(r'\\x', r'\x') 57 | .replaceAll(r'\sqsqsq', r"\'\'\'") 58 | .replaceAll(r'\sqsq', r"\'\'") 59 | .replaceAll(r'\sq', r"\'") 60 | .replaceAll(r'\\', r'\') 61 | .replaceAll(r'\FUNCTION{}', "'Function'") 62 | .replaceAllMapped( 63 | keywordRegExp, (match) => "'${match[1]!.toLowerCase()}'") 64 | .replaceAllMapped(ruleRegExp, (match) => match[1]!); 65 | print(line); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /working/0107 - implicit-constructors/feature-brainstorm.md: -------------------------------------------------------------------------------- 1 | # Implicit Constructors 2 | 3 | Author: kevmoo@google.com 4 | 5 | Proposed solution to [type conversion problem (#107)](https://github.com/dart-lang/language/issues/107). 6 | Discussion about this proposal should go in [Issue #108](https://github.com/dart-lang/language/issues/108). 7 | 8 | ## Motivation 9 | 10 | Every place in `pkg:http` with a `url` parameter types it as `dynamic`. 11 | 12 | ```dart 13 | Future get(url, {Map headers}) => ... 14 | 15 | void doWork() async { 16 | await get('http://example.com'); 17 | await get(Uri.parse('http://example.com')); 18 | await get(42); // statically fine, but causes a runtime error 19 | } 20 | ``` 21 | 22 | This is to support a common use case: devs often want to pass either `Uri` 23 | *or* `String` to such methods. In the end, all `String` values are "upgraded" 24 | to `Uri` before use. To support the desired flexibility, the user risks 25 | runtime errors if something other than `String` or `Uri` are provided. 26 | 27 | Flutter avoids this issue, by being explicit about types everywhere. 28 | 29 | ```dart 30 | // Flutter 31 | void giveMeABorder(BorderRadiusGeometry value) {} 32 | 33 | void doWork() { 34 | giveMeABorder(const BorderRadius.all( 35 | Radius.circular(18), 36 | )); 37 | 38 | // User would like to write this, but... 39 | giveMeABorder(18); // static error 40 | } 41 | ``` 42 | 43 | The existing request(s) for union types – 44 | https://github.com/dart-lang/sdk/issues/4938 and 45 | https://github.com/dart-lang/language/issues/83 46 | – could be an option here, but it would require updating all parameters 47 | and setters to specify the supported types. 48 | 49 | An alternative: implicit constructors. 50 | 51 | ## Syntax 52 | 53 | *This is all PM spit-balling at the moment...* 54 | 55 | * Introduce a new keyword – `implicit` – that can be applied to a constructor or 56 | factory. 57 | 58 | ```dart 59 | class Uri { 60 | // Note: parse is currently a static function on Uri, not a constructor. 61 | implicit Uri.parse(String uri) => ... 62 | } 63 | 64 | class BorderRadiusGeometry { 65 | implicit factory BorderRadiusGeometry.fromDouble(double radius) => 66 | BorderRadius.all(Radius.circular(18)); 67 | } 68 | 69 | class Widget { 70 | implicit factory Widget.fromString(String text) => Text(text); 71 | } 72 | 73 | // NOTE - for both Widget and BorderRadiusGeometry, you really want a 74 | // `const implicit factory`. Supporting `const factory` seems like a necessary 75 | // precursor. 76 | ``` 77 | 78 | * When evaluating an assignment to type `T`, if the provided value `P` is 79 | not of type `T`, then look for an implicit constructor/factory on `T` that 80 | supports an instance of `P`. If it exists, use it. 81 | 82 | ## Other implementations 83 | 84 | * C# - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit 85 | * Scala - https://docs.scala-lang.org/tour/implicit-conversions.html 86 | * Leaf has warned about Scala's support for cascading implicit conversions 87 | (e.g. int -> Duration -> Time). Dart should avoid this! 88 | -------------------------------------------------------------------------------- /working/0323-null-aware-elements/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/future-releases/0323-null-aware-elements/feature-specification.md 4 | -------------------------------------------------------------------------------- /working/0546-patterns/exhaustiveness.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/exhaustiveness.md 4 | -------------------------------------------------------------------------------- /working/0546-patterns/goals-and-constraints.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/goals-and-constraints.md 4 | -------------------------------------------------------------------------------- /working/0546-patterns/patterns-feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/feature-specification.md 4 | -------------------------------------------------------------------------------- /working/0546-patterns/why-two-kinds-of-patterns.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/why-two-kinds-of-patterns.md 4 | -------------------------------------------------------------------------------- /working/0649 - Import shorthand/proposal.md: -------------------------------------------------------------------------------- 1 | This 'Import Shorthand Syntax' document [has moved] to the archive. 2 | It has has been succeeded by the [Unquoted imports] document. 3 | 4 | [has moved]: https://github.com/dart-lang/language/blob/main/archive/0649%20-%20Import%20shorthand/proposal.md 5 | [Unquoted imports]: https://github.com/dart-lang/language/blob/main/accepted/future-releases/unquoted-imports/feature-specification.md 6 | -------------------------------------------------------------------------------- /working/0731 - horizontal inference/feature-specification.md: -------------------------------------------------------------------------------- 1 | # Horizontal Inference 2 | 3 | **MOVED TO ACCEPTED** 4 | 5 | Further development happens in the [accepted folder](../../accepted/2.18/horizontal-inference/feature-specification.md). 6 | -------------------------------------------------------------------------------- /working/1855 - super parameters/proposal.md: -------------------------------------------------------------------------------- 1 | # Dart Super-Initializer Parameters 2 | 3 | Author: lrn@google.com
Version: 1.3 4 | 5 | This proposal has been accepted. This document only serves as a reference to the [most recent version][url]. 6 | 7 | [url]: https://github.com/dart-lang/language/blob/master/accepted/2.17/super-parameters/feature-specification.md 8 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "fields": [ 4 | { 5 | "name": "x", 6 | "type": "int" 7 | }, 8 | { 9 | "name": "y", 10 | "type": "int" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "fields": [ 4 | { 5 | "name": "x", 6 | "type": "int" 7 | }, 8 | { 9 | "name": "y", 10 | "type": "int", 11 | "isOptional": true, 12 | "isNamed": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "fields": [ 4 | { 5 | "name": "x", 6 | "type": "int" 7 | }, 8 | { 9 | "name": "y", 10 | "type": "int", 11 | "isOptional": true, 12 | "defaultValue": "0" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "fields": [ 4 | { 5 | "name": "x", 6 | "type": "int" 7 | }, 8 | { 9 | "name": "y", 10 | "type": "int", 11 | "isNamed": true, 12 | "defaultValue": "0" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int", 8 | "isFinal": true 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isFinal": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int", 8 | "isFinal": true 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isFinal": true, 14 | "isOptional": true, 15 | "isNamed": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int", 8 | "isFinal": true 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isFinal": true, 14 | "isOptional": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int", 8 | "isFinal": true 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isFinal": true, 14 | "isNamed": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/generic_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/generic_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "isNamed": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/generic_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/generic_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isNamed": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int", 8 | "isFinal": true 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "isConst": true, 5 | "fields": [ 6 | { 7 | "name":"x", 8 | "type": "int", 9 | "isFinal": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_generic_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "typeParameters": "", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_named_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "constructorName": "_", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_named_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "isConst": true, 5 | "constructorName": "_", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_subtyped_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "superinterfaces": "implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_subtyped_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "isConst": true, 5 | "superinterfaces": "implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_subtyped_generic_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "typeParameters": "", 5 | "superinterfaces": "implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/inline_subtyped_generic_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "isExtensionType": true, 3 | "name": "Point", 4 | "isConst": true, 5 | "typeParameters": "", 6 | "superinterfaces": "implements B, C", 7 | "fields": [ 8 | { 9 | "name": "x", 10 | "type": "int", 11 | "isFinal": true 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "isNamed": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isNamed": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "constructorName": "_", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "constructorName": "_", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isOptional": true, 16 | "isNamed": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "constructorName": "_", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isOptional": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "constructorName": "_", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isNamed": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isOptional": true, 14 | "isNamed": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isOptional": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isNamed": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isOptional": true, 17 | "isNamed": true, 18 | "defaultValue": "0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isOptional": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isNamed": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int" 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int" 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isOptional": true, 15 | "isNamed": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int" 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isOptional": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int" 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isNamed": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "typeParameters": "", 6 | "superinterfaces": "extends A with M implements B, C", 7 | "fields": [ 8 | { 9 | "name": "x", 10 | "type": "int", 11 | "isFinal": true 12 | }, 13 | { 14 | "name": "y", 15 | "type": "int", 16 | "isFinal": true 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "typeParameters": "", 6 | "superinterfaces": "extends A with M implements B, C", 7 | "fields": [ 8 | { 9 | "name": "x", 10 | "type": "int", 11 | "isFinal": true 12 | }, 13 | { 14 | "name": "y", 15 | "type": "int", 16 | "isFinal": true, 17 | "isOptional": true, 18 | "isNamed": true, 19 | "defaultValue": "0" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "typeParameters": "", 6 | "superinterfaces": "extends A with M implements B, C", 7 | "fields": [ 8 | { 9 | "name": "x", 10 | "type": "int", 11 | "isFinal": true 12 | }, 13 | { 14 | "name": "y", 15 | "type": "int", 16 | "isFinal": true, 17 | "isOptional": true, 18 | "defaultValue": "0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "constructorName": "_", 4 | "isConst": true, 5 | "typeParameters": "", 6 | "superinterfaces": "extends A with M implements B, C", 7 | "fields": [ 8 | { 9 | "name": "x", 10 | "type": "int", 11 | "isFinal": true 12 | }, 13 | { 14 | "name": "y", 15 | "type": "int", 16 | "isFinal": true, 17 | "isNamed": true, 18 | "defaultValue": "0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "superinterfaces": "extends A with M implements B, C", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "superinterfaces": "extends A with M implements B, C", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "isNamed": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "superinterfaces": "extends A with M implements B, C", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isOptional": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "superinterfaces": "extends A with M implements B, C", 4 | "fields": [ 5 | { 6 | "name": "x", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "y", 11 | "type": "int", 12 | "isNamed": true, 13 | "defaultValue": "0" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isOptional": true, 16 | "isNamed": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isOptional": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int", 9 | "isFinal": true 10 | }, 11 | { 12 | "name": "y", 13 | "type": "int", 14 | "isFinal": true, 15 | "isNamed": true, 16 | "defaultValue": "0" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isOptional": true, 14 | "isNamed": true, 15 | "defaultValue": "0" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isOptional": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "typeParameters": "", 4 | "superinterfaces": "extends A with M implements B, C", 5 | "fields": [ 6 | { 7 | "name": "x", 8 | "type": "int" 9 | }, 10 | { 11 | "name": "y", 12 | "type": "int", 13 | "isNamed": true, 14 | "defaultValue": "0" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_const_class.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_const_class_namedpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isOptional": true, 17 | "isNamed": true, 18 | "defaultValue": "0" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_const_class_optpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isOptional": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/2364 - primary constructors/scripts/subtyped_generic_const_class_requiredpar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Point", 3 | "isConst": true, 4 | "typeParameters": "", 5 | "superinterfaces": "extends A with M implements B, C", 6 | "fields": [ 7 | { 8 | "name": "x", 9 | "type": "int", 10 | "isFinal": true 11 | }, 12 | { 13 | "name": "y", 14 | "type": "int", 15 | "isFinal": true, 16 | "isNamed": true, 17 | "defaultValue": "0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /working/README.md: -------------------------------------------------------------------------------- 1 | # Working directory 2 | 3 | This directory holds work in progress artifacts in any stage from rough 4 | brainstorming documents to "out-for-implementation" proposals. Don't take 5 | anything in here too seriously. 6 | -------------------------------------------------------------------------------- /working/base-interface-final/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/class-modifiers/feature-specification.md 4 | -------------------------------------------------------------------------------- /working/digit-separators/feature-specification.md: -------------------------------------------------------------------------------- 1 | # Digit Separators 2 | 3 | This document [has moved]. 4 | 5 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/digit-separators/feature-specification.md 6 | -------------------------------------------------------------------------------- /working/macros/host-notes.md: -------------------------------------------------------------------------------- 1 | # Macro Host Notes 2 | 3 | Notes about macro host (analyzer, CFE) implementations. 4 | 5 | Some related discussion 6 | [on issue 55784](https://github.com/dart-lang/sdk/issues/55784). 7 | 8 | ## Analyzer 9 | 10 | 1. Build library cycles. Use imports and exports to form library cycles. Sort 11 | them topologically. 12 | 2. With all dependency library cycles loaded (which means that we can ask them 13 | for elements with all types ready), take the next library cycle. 14 | 3. Parse all user-written Dart files, create `LibraryBuilder` objects. 15 | 4. Build `Element`s for all declarations - classes, methods, etc. Just 16 | elements, types are not known yet. 17 | 5. Create the `LibraryMacroApplier` instance, fill `LibraryBuilder`s with 18 | `_MacroApplication`s. The order of the macro applications is defined by the 19 | specification. 20 | 6. Run the types phase. Iterate over `LibraryBuilder`s, and run the types phase 21 | for macro applications. We get Dart code as output. Add library 22 | augmentations from these Dart code strings. Build elements for these library 23 | augmentations, just like (4). Look for more macro applications, just like 24 | (5). 25 | 7. Build export scopes for `LibraryBuilder`s. This includes any user-written 26 | declarations, handling re-exports. 27 | 8. Resolve `TypeAnnotation`s in all `LibraryBuilder`s. 28 | 9. Run the declarations phase. Like (6), but not only build elements, and find 29 | new macro applications, but also resolve type annotations like (8). If new 30 | declarations are added, rebuild export scopes. 31 | 10. Run many other element linking steps - build synthetic constructors, enum 32 | constants, resolve constants, resolve metadata, perform type inference, etc. 33 | 11. Run the definitions phase. Like (9), still produce new library 34 | augmentations. 35 | 12. Dispose all macro applications, so free resources in the remote isolate. 36 | 13. Merge all macro results into single Dart code. Discard all transitory 37 | library augmentations, add the new, final one. Do not create new elements, 38 | not like (6) or (9), instead merge `ClassElement`s, update offsets, etc. 39 | These elements have everything ready in them - types, resolution for 40 | constants, etc. We don’t want to redo this work. And we cannot create new 41 | elements - there are already references to these elements in other parts of 42 | the element model. 43 | 44 | ## CFE 45 | 46 | TODO 47 | -------------------------------------------------------------------------------- /working/sealed-types/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/sealed-types/feature-specification.md 4 | -------------------------------------------------------------------------------- /working/unquoted-imports/feature-specification.md: -------------------------------------------------------------------------------- 1 | This document [has moved]. 2 | 3 | [has moved]: https://github.com/dart-lang/language/blob/main/accepted/future-releases/unquoted-imports/feature-specification.md 4 | -------------------------------------------------------------------------------- /working/wildcards/feature-specification.md: -------------------------------------------------------------------------------- 1 | # Wildcard Variables 2 | 3 | The feature is accepted and the accepted specification has been 4 | [moved](../../accepted/future-releases/wildcard-variables/feature-specification.md) 5 | to the accepted features folder. 6 | --------------------------------------------------------------------------------