Version 2.10.0-50.0.dev
Merge commit 'f190a4ae276dbebaa7aa261da74c13f9d1d6434d' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 01fc714..d2d1a31 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -93,7 +93,7 @@
import 'util/experiment_environment_getter.dart' show getExperimentEnvironment;
-import 'util/textual_outline.dart' show textualOutline;
+import 'util/textual_outline_v2.dart' show textualOutline;
import 'fasta_codes.dart'
show
diff --git a/pkg/front_end/lib/src/fasta/util/textual_outline.dart b/pkg/front_end/lib/src/fasta/util/textual_outline.dart
deleted file mode 100644
index e165729..0000000
--- a/pkg/front_end/lib/src/fasta/util/textual_outline.dart
+++ /dev/null
@@ -1,579 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:typed_data' show Uint8List;
-
-import 'dart:io' show File;
-
-import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart'
- show ClassMemberParser;
-
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
- show ErrorToken, LanguageVersionToken, Scanner;
-
-import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'
- show Utf8BytesScanner;
-
-import '../../fasta/source/directive_listener.dart' show DirectiveListener;
-
-import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
-
-class _TextualOutlineState {
- bool prevTokenKnown = false;
- Token currentElementEnd;
- List<String> currentChunk = new List<String>();
- List<String> outputLines = new List<String>();
-
- final bool performModelling;
- final bool addMarkerForUnknownForTest;
- String indent = "";
- _TextualOutlineState(this.performModelling, this.addMarkerForUnknownForTest);
-}
-
-// TODO(jensj): Better support for show/hide on imports/exports.
-
-String textualOutline(List<int> rawBytes,
- {bool throwOnUnexpected: false,
- bool performModelling: false,
- bool addMarkerForUnknownForTest: false}) {
- // TODO(jensj): We need to specify the scanner settings to match that of the
- // compiler!
- Uint8List bytes = new Uint8List(rawBytes.length + 1);
- bytes.setRange(0, rawBytes.length, rawBytes);
-
- // Idea:
- // * Chunks are entities, e.g. whole classes, whole procedures etc.
- // * It could also be an "unknown" batch of tokens.
- // * currentChunk is a temporary buffer where we add chunks in a "run".
- // * Depending on whether we know what the previous token (and thus chunk) is
- // or not, and what the current token (and thus chunk) is, we either flush
- // the currentChunk buffer or not.
- // * The idea being, that if we add 3 chunks we know and then are about to add
- // one we don't know, we can sort the 3 chunks we do know and output them.
- // But when we go from unknown to known, we don't sort before outputting.
-
- _TextualOutlineState state =
- new _TextualOutlineState(performModelling, addMarkerForUnknownForTest);
-
- TokenPrinter tokenPrinter = new TokenPrinter();
-
- Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, includeComments: false,
- languageVersionChanged:
- (Scanner scanner, LanguageVersionToken languageVersion) {
- flush(state, isSortable: false, isKnown: false);
- state.prevTokenKnown = false;
- state.outputLines
- .add("// @dart = ${languageVersion.major}.${languageVersion.minor}");
- });
- Token firstToken = scanner.tokenize();
- if (firstToken == null) {
- if (throwOnUnexpected) throw "firstToken is null";
- return null;
- }
-
- TextualOutlineListener listener = new TextualOutlineListener();
- ClassMemberParser classMemberParser = new ClassMemberParser(listener);
- classMemberParser.parseUnit(firstToken);
-
- Token token = firstToken;
- while (token != null) {
- if (token is ErrorToken) {
- return null;
- }
- if (token.isEof) break;
-
- if (listener.classStartToFinish.containsKey(token)) {
- if (state.prevTokenKnown) {
- // TODO: Assert this instead.
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- } else if (!tokenPrinter.isEmpty) {
- // We're ending a streak of unknown: Output, and flush,
- // but it's not sortable.
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: false);
- }
-
- Token currentClassEnd = listener.classStartToFinish[token];
- String classContent = _textualizeClass(
- listener, token, currentClassEnd, state,
- throwOnUnexpected: throwOnUnexpected);
- if (classContent == null) return null;
- state.currentChunk.add(classContent);
- token = currentClassEnd.next;
- state.prevTokenKnown = true;
- assert(tokenPrinter.isEmpty);
- continue;
- }
-
- bool isImportExport =
- listener.importExportsStartToFinish.containsKey(token);
- bool isKnownUnsortable = isImportExport ||
- listener.unsortableElementStartToFinish.containsKey(token);
-
- if (isKnownUnsortable) {
- // We know about imports/exports, and internally they can be sorted,
- // but the import/export block should be thought of as unknown, i.e.
- // it should not moved around.
- // We also know about other (e.g. library and parts) - those cannot be
- // sorted though.
- if (state.prevTokenKnown) {
- // TODO: Assert this instead.
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- flush(state, isSortable: true, isKnown: true);
- } else {
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: false);
- }
- if (isImportExport) {
- TextualizedImportExport importResult =
- _textualizeImportsAndExports(listener, token, state);
- if (importResult == null) return null;
- state.currentChunk.add(importResult.text);
- token = importResult.token;
- } else {
- Token endToken = listener.unsortableElementStartToFinish[token];
- while (token != endToken) {
- tokenPrinter.print(token);
- token = token.next;
- }
- tokenPrinter.print(endToken);
- token = token.next;
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- }
- state.prevTokenKnown = true;
- flush(state, isSortable: false, isKnown: true);
- assert(tokenPrinter.isEmpty);
- continue;
- }
-
- token = _textualizeNonClassEntriesInsideLoop(
- listener, token, state, throwOnUnexpected, tokenPrinter);
- if (token == null) return null;
- }
- _textualizeAfterLoop(state, tokenPrinter);
- return state.outputLines.join("\n\n");
-}
-
-Token _textualizeNonClassEntriesInsideLoop(
- TextualOutlineListener listener,
- Token token,
- _TextualOutlineState state,
- bool throwOnUnexpected,
- TokenPrinter tokenPrinter) {
- if (listener.elementStartToFinish.containsKey(token)) {
- if (state.currentElementEnd != null) {
- if (throwOnUnexpected) throw "Element in element";
- return null;
- }
- if (state.prevTokenKnown) {
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- } else if (!tokenPrinter.isEmpty) {
- // We're ending a streak of unknown: Output, and flush,
- // but it's not sortable.
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: false);
- }
- state.currentElementEnd = listener.elementStartToFinish[token];
- state.prevTokenKnown = true;
- } else if (state.currentElementEnd == null &&
- listener.metadataStartToFinish.containsKey(token)) {
- if (state.prevTokenKnown) {
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- } else if (!tokenPrinter.isEmpty) {
- // We're ending a streak of unknown: Output, and flush,
- // but it's not sortable.
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: false);
- }
- state.currentElementEnd = listener.metadataStartToFinish[token];
- state.prevTokenKnown = true;
- }
-
- if (state.currentElementEnd == null && state.prevTokenKnown) {
- // We're ending a streak of known stuff.
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- flush(state, isSortable: true, isKnown: true);
- state.prevTokenKnown = false;
- } else {
- if (state.currentElementEnd == null) {
- if (state.prevTokenKnown) {
- // known -> unknown.
- throw "This case was apparently not handled above.";
- } else {
- // OK: Streak of unknown.
- }
- } else {
- if (state.prevTokenKnown) {
- // OK: Streak of known.
- } else {
- // unknown -> known: This should have been flushed above.
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- }
- }
- }
-
- tokenPrinter.print(token);
-
- if (token == state.currentElementEnd) {
- state.currentElementEnd = null;
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- }
-
- if (token.endGroup != null &&
- listener.nonClassEndOffsets.contains(token.endGroup.offset)) {
- token = token.endGroup;
- tokenPrinter.nextTokenIsEndGroup = true;
- } else {
- token = token.next;
- }
- return token;
-}
-
-void _textualizeAfterLoop(
- _TextualOutlineState state, TokenPrinter tokenPrinter) {
- // We're done, so we're logically at an unknown token.
- if (state.prevTokenKnown) {
- // We're ending a streak of known stuff.
- if (!tokenPrinter.isEmpty) {
- throw new StateError("Expected empty, was '${tokenPrinter.content}'");
- }
- flush(state, isSortable: true, isKnown: true);
- state.prevTokenKnown = false;
- } else {
- // Streak of unknown.
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: false);
- state.prevTokenKnown = false;
- }
-}
-
-void flush(_TextualOutlineState state, {bool isSortable, bool isKnown}) {
- assert(isSortable != null);
- assert(isKnown != null);
- if (state.currentChunk.isEmpty) return;
- if (isSortable) {
- state.currentChunk = mergeAndSort(state.currentChunk, state.indent,
- isModelling: state.performModelling);
- }
- if (state.addMarkerForUnknownForTest && !isKnown) {
- state.outputLines.add("---- unknown chunk starts ----");
- }
- if (state.indent == "") {
- state.outputLines.addAll(state.currentChunk);
- } else {
- for (int i = 0; i < state.currentChunk.length; i++) {
- state.outputLines.add("${state.indent}${state.currentChunk[i]}");
- }
- }
- if (state.addMarkerForUnknownForTest && !isKnown) {
- state.outputLines.add("---- unknown chunk ends ----");
- }
- state.currentChunk.clear();
-}
-
-List<String> mergeAndSort(List<String> data, String indent,
- {bool isModelling}) {
- assert(isModelling != null);
- // If not modelling, don't sort.
- if (!isModelling) return data;
-
- bool hasAnnotations = false;
- for (int i = 0; i < data.length - 1; i++) {
- String element = data[i];
- if (element.startsWith("@")) {
- hasAnnotations = true;
- break;
- }
- }
- if (!hasAnnotations) {
- data.sort();
- return data;
- }
-
- // There's annotations: Merge them with the owner.
- List<String> merged = new List<String>();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < data.length; i++) {
- String element = data[i];
- if (element.startsWith("@")) {
- if (sb.length > 0) sb.write(indent);
- sb.writeln(element);
- } else {
- if (sb.length > 0) sb.write(indent);
- sb.write(element);
- merged.add(sb.toString());
- sb.clear();
- }
- }
- if (sb.length > 0) {
- merged.add(sb.toString());
- sb.clear();
- }
-
- merged.sort();
- return merged;
-}
-
-class TokenPrinter {
- bool nextTokenIsEndGroup = false;
- int _endOfLast = -1;
- StringBuffer _sb = new StringBuffer();
-
- String get content => _sb.toString();
-
- bool get isEmpty => _sb.isEmpty;
-
- void clear() {
- _endOfLast = -1;
- _sb.clear();
- }
-
- void addAndClearIfHasContent(List<String> list) {
- if (_sb.length > 0) {
- list.add(_sb.toString());
- clear();
- }
- }
-
- void print(Token token) {
- if (_sb.isNotEmpty && token.offset > _endOfLast && !nextTokenIsEndGroup) {
- _sb.write(" ");
- }
-
- _sb.write(token.lexeme);
- _endOfLast = token.end;
- nextTokenIsEndGroup = false;
- }
-
- String toString() {
- throw new UnsupportedError("toString");
- }
-}
-
-String _textualizeClass(TextualOutlineListener listener, Token beginToken,
- Token endToken, _TextualOutlineState originalState,
- {bool throwOnUnexpected: false}) {
- Token token = beginToken;
- TokenPrinter tokenPrinter = new TokenPrinter();
- // Class header.
- while (token != endToken) {
- tokenPrinter.print(token);
- if (token.endGroup == endToken) {
- token = token.next;
- break;
- }
- token = token.next;
- }
- _TextualOutlineState state = new _TextualOutlineState(
- originalState.performModelling, originalState.addMarkerForUnknownForTest);
- if (token == endToken) {
- // This for instance happens on named mixins, e.g.
- // class C<T> = Object with A<Function(T)>;
- // or when the class has no content, e.g.
- // class C { }
- // either way, output the end token right away to avoid a weird line break.
- tokenPrinter.nextTokenIsEndGroup = true;
- tokenPrinter.print(token);
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: true);
- } else {
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: true);
-
- state.indent = " ";
- while (token != endToken) {
- token = _textualizeNonClassEntriesInsideLoop(
- listener, token, state, throwOnUnexpected, tokenPrinter);
- if (token == null) return null;
- }
- _textualizeAfterLoop(state, tokenPrinter);
-
- state.indent = "";
- tokenPrinter.nextTokenIsEndGroup = true;
- tokenPrinter.print(token);
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- flush(state, isSortable: false, isKnown: true);
- }
- return state.outputLines.join("\n");
-}
-
-class TextualizedImportExport {
- final String text;
- final Token token;
-
- TextualizedImportExport(this.text, this.token);
-}
-
-TextualizedImportExport _textualizeImportsAndExports(
- TextualOutlineListener listener,
- Token beginToken,
- _TextualOutlineState originalState) {
- TokenPrinter tokenPrinter = new TokenPrinter();
- Token token = beginToken;
- Token thisImportEnd = listener.importExportsStartToFinish[token];
- _TextualOutlineState state = new _TextualOutlineState(
- originalState.performModelling, originalState.addMarkerForUnknownForTest);
- // TODO(jensj): Sort show and hide entries.
- while (thisImportEnd != null) {
- while (token != thisImportEnd) {
- tokenPrinter.print(token);
- token = token.next;
- }
- tokenPrinter.print(thisImportEnd);
- token = token.next;
- tokenPrinter.addAndClearIfHasContent(state.currentChunk);
- thisImportEnd = listener.importExportsStartToFinish[token];
- }
-
- // End of imports. Sort them and return the sorted text.
- flush(state, isSortable: true, isKnown: true);
- return new TextualizedImportExport(state.outputLines.join("\n"), token);
-}
-
-main(List<String> args) {
- File f = new File(args[0]);
- String outline = textualOutline(f.readAsBytesSync(),
- throwOnUnexpected: true, performModelling: true);
- if (args.length > 1 && args[1] == "--overwrite") {
- f.writeAsStringSync(outline);
- } else {
- print(outline);
- }
-}
-
-class TextualOutlineListener extends DirectiveListener {
- Set<int> nonClassEndOffsets = new Set<int>();
- Map<Token, Token> classStartToFinish = {};
- Map<Token, Token> elementStartToFinish = {};
- Map<Token, Token> metadataStartToFinish = {};
- Map<Token, Token> importExportsStartToFinish = {};
- Map<Token, Token> unsortableElementStartToFinish = {};
-
- @override
- void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
- Token beginInitializers, Token endToken) {
- nonClassEndOffsets.add(endToken.offset);
- elementStartToFinish[beginToken] = endToken;
- }
-
- @override
- void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
- nonClassEndOffsets.add(endToken.offset);
- elementStartToFinish[beginToken] = endToken;
- }
-
- @override
- void endClassFactoryMethod(
- Token beginToken, Token factoryKeyword, Token endToken) {
- nonClassEndOffsets.add(endToken.offset);
- elementStartToFinish[beginToken] = endToken;
- }
-
- @override
- void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
- // Allow native functions.
- }
-
- @override
- void endClassFields(
- Token abstractToken,
- Token externalToken,
- Token staticToken,
- Token covariantToken,
- Token lateToken,
- Token varFinalOrConst,
- int count,
- Token beginToken,
- Token endToken) {
- elementStartToFinish[beginToken] = endToken;
- }
-
- @override
- void endTopLevelFields(
- Token externalToken,
- Token staticToken,
- Token covariantToken,
- Token lateToken,
- Token varFinalOrConst,
- int count,
- Token beginToken,
- Token endToken) {
- elementStartToFinish[beginToken] = endToken;
- }
-
- void endFunctionTypeAlias(
- Token typedefKeyword, Token equals, Token endToken) {
- elementStartToFinish[typedefKeyword] = endToken;
- }
-
- void endEnum(Token enumKeyword, Token leftBrace, int count) {
- elementStartToFinish[enumKeyword] = leftBrace.endGroup;
- }
-
- @override
- void endLibraryName(Token libraryKeyword, Token semicolon) {
- unsortableElementStartToFinish[libraryKeyword] = semicolon;
- }
-
- @override
- void endPart(Token partKeyword, Token semicolon) {
- unsortableElementStartToFinish[partKeyword] = semicolon;
- }
-
- @override
- void endPartOf(
- Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
- unsortableElementStartToFinish[partKeyword] = semicolon;
- }
-
- @override
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
- // Metadata's endToken is the one *after* the actual end of the metadata.
- metadataStartToFinish[beginToken] = endToken.previous;
- }
-
- @override
- void endClassDeclaration(Token beginToken, Token endToken) {
- classStartToFinish[beginToken] = endToken;
- }
-
- @override
- void endMixinDeclaration(Token mixinKeyword, Token endToken) {
- classStartToFinish[mixinKeyword] = endToken;
- }
-
- @override
- void endExtensionDeclaration(
- Token extensionKeyword, Token onKeyword, Token endToken) {
- classStartToFinish[extensionKeyword] = endToken;
- }
-
- @override
- void endNamedMixinApplication(Token beginToken, Token classKeyword,
- Token equals, Token implementsKeyword, Token endToken) {
- classStartToFinish[beginToken] = endToken;
- }
-
- @override
- void endImport(Token importKeyword, Token semicolon) {
- importExportsStartToFinish[importKeyword] = semicolon;
- }
-
- @override
- void endExport(Token exportKeyword, Token semicolon) {
- importExportsStartToFinish[exportKeyword] = semicolon;
- }
-}
diff --git a/pkg/front_end/lib/src/fasta/util/textual_outline_v2.dart b/pkg/front_end/lib/src/fasta/util/textual_outline_v2.dart
new file mode 100644
index 0000000..d808874
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/textual_outline_v2.dart
@@ -0,0 +1,686 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data' show Uint8List;
+
+import 'dart:io' show File;
+
+import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart'
+ show ClassMemberParser;
+
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
+ show ErrorToken, LanguageVersionToken, Scanner;
+
+import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'
+ show Utf8BytesScanner;
+
+import '../../fasta/source/directive_listener.dart' show DirectiveListener;
+
+import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
+
+abstract class _Chunk implements Comparable<_Chunk> {
+ final int originalPosition;
+
+ List<_MetadataChunk> metadata;
+
+ _Chunk(this.originalPosition);
+
+ void printOn(StringBuffer sb, String indent);
+
+ void printMetadata(StringBuffer sb, String indent) {
+ if (metadata != null) {
+ for (_MetadataChunk m in metadata) {
+ m.printMetadataOn(sb, indent);
+ }
+ }
+ }
+
+ void internalMergeAndSort();
+
+ @override
+ int compareTo(_Chunk other) {
+ // Generally we compare according to the original position.
+ if (originalPosition < other.originalPosition) return -1;
+ return 1;
+ }
+}
+
+class _LanguageVersionChunk extends _Chunk {
+ final int major;
+ final int minor;
+
+ _LanguageVersionChunk(int originalPosition, this.major, this.minor)
+ : super(originalPosition);
+
+ @override
+ void printOn(StringBuffer sb, String indent) {
+ if (sb.isNotEmpty) {
+ sb.write("\n\n");
+ }
+ printMetadata(sb, indent);
+ sb.write("// @dart = ${major}.${minor}");
+ }
+
+ @override
+ void internalMergeAndSort() {
+ // Cannot be sorted.
+ }
+}
+
+abstract class _TokenChunk extends _Chunk {
+ final Token startToken;
+ final Token endToken;
+
+ _TokenChunk(int originalPosition, this.startToken, this.endToken)
+ : super(originalPosition);
+
+ void printOn(StringBuffer sb, String indent) {
+ int endOfLast = startToken.end;
+ if (sb.isNotEmpty) {
+ sb.write("\n");
+ if (indent.isEmpty && this is! _SingleImportExportChunk) {
+ // Hack to imitate v1.
+ sb.write("\n");
+ }
+ }
+ printMetadata(sb, indent);
+ sb.write(indent);
+
+ Token token = startToken;
+ Token afterEnd = endToken.next;
+ while (token != afterEnd) {
+ if (token.offset > endOfLast) {
+ sb.write(" ");
+ }
+
+ sb.write(token.lexeme);
+ endOfLast = token.end;
+ token = token.next;
+ }
+ }
+
+ @override
+ void internalMergeAndSort() {
+ // Generally cannot be sorted.
+ }
+}
+
+abstract class _SortableChunk extends _TokenChunk {
+ _SortableChunk(int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+
+ @override
+ int compareTo(_Chunk o) {
+ if (o is! _SortableChunk) return super.compareTo(o);
+
+ _SortableChunk other = o;
+
+ // Compare lexemes from startToken and at most the next 10 tokens.
+ // For valid code this should be more than enough. Note that this won't
+ // sort as a text-sort would as for instance "C<Foo>" and "C2<Foo>" will
+ // say "C" < "C2" where a text-sort would say "C<" > "C2". This doesn't
+ // really matter as long as the sorting is consistent (i.e. the textual
+ // outline always sorts like this).
+ Token thisToken = startToken;
+ Token otherToken = other.startToken;
+ int steps = 0;
+ while (thisToken.lexeme == otherToken.lexeme) {
+ if (steps++ > 10) break;
+ thisToken = thisToken.next;
+ otherToken = otherToken.next;
+ }
+ if (thisToken.lexeme == otherToken.lexeme) return super.compareTo(o);
+ return thisToken.lexeme.compareTo(otherToken.lexeme);
+ }
+}
+
+class _ImportExportChunk extends _Chunk {
+ final List<_SingleImportExportChunk> content =
+ new List<_SingleImportExportChunk>();
+
+ _ImportExportChunk(int originalPosition) : super(originalPosition);
+
+ @override
+ void printOn(StringBuffer sb, String indent) {
+ if (sb.isNotEmpty) {
+ sb.write("\n");
+ }
+ printMetadata(sb, indent);
+
+ for (_SingleImportExportChunk chunk in content) {
+ chunk.printOn(sb, indent);
+ }
+ }
+
+ @override
+ void internalMergeAndSort() {
+ content.sort();
+ }
+}
+
+class _SingleImportExportChunk extends _SortableChunk {
+ _SingleImportExportChunk(
+ int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+}
+
+class _KnownUnsortableChunk extends _TokenChunk {
+ _KnownUnsortableChunk(int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+}
+
+class _ClassChunk extends _SortableChunk {
+ List<_Chunk> content = new List<_Chunk>();
+ Token headerEnd;
+ Token footerStart;
+
+ _ClassChunk(int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+
+ void printOn(StringBuffer sb, String indent) {
+ int endOfLast = startToken.end;
+ if (sb.isNotEmpty) {
+ sb.write("\n\n");
+ sb.write(indent);
+ }
+
+ printMetadata(sb, indent);
+
+ // Header.
+ Token token = startToken;
+ Token afterEnd = headerEnd.next;
+ while (token != afterEnd) {
+ if (token.offset > endOfLast) {
+ sb.write(" ");
+ }
+
+ sb.write(token.lexeme);
+ endOfLast = token.end;
+
+ token = token.next;
+ }
+
+ // Content.
+ for (_Chunk chunk in content) {
+ chunk.printOn(sb, " $indent");
+ }
+
+ // Footer.
+ if (footerStart != null) {
+ if (content.isNotEmpty) {
+ sb.write("\n");
+ sb.write(indent);
+ }
+ endOfLast = footerStart.end;
+ token = footerStart;
+ afterEnd = endToken.next;
+ while (token != afterEnd) {
+ if (token.offset > endOfLast) {
+ sb.write(" ");
+ }
+
+ sb.write(token.lexeme);
+ endOfLast = token.end;
+
+ token = token.next;
+ }
+ }
+ }
+
+ @override
+ void internalMergeAndSort() {
+ content = _mergeAndSort(content);
+ }
+}
+
+class _ProcedureEtcChunk extends _SortableChunk {
+ final Set<int> nonClassEndOffsets;
+ _ProcedureEtcChunk(int originalPosition, Token startToken, Token endToken,
+ this.nonClassEndOffsets)
+ : super(originalPosition, startToken, endToken);
+
+ void printOn(StringBuffer sb, String indent) {
+ int endOfLast = startToken.end;
+ if (sb.isNotEmpty) {
+ sb.write("\n");
+ if (indent.isEmpty) {
+ // Hack to imitate v1.
+ sb.write("\n");
+ }
+ }
+ printMetadata(sb, indent);
+ sb.write(indent);
+
+ Token token = startToken;
+ Token afterEnd = endToken.next;
+ bool nextTokenIsEndGroup = false;
+ while (token != afterEnd) {
+ if (token.offset > endOfLast && !nextTokenIsEndGroup) {
+ sb.write(" ");
+ }
+
+ sb.write(token.lexeme);
+ endOfLast = token.end;
+
+ if (token.endGroup != null &&
+ nonClassEndOffsets.contains(token.endGroup.offset)) {
+ token = token.endGroup;
+ nextTokenIsEndGroup = true;
+ } else {
+ token = token.next;
+ nextTokenIsEndGroup = false;
+ }
+ }
+ }
+}
+
+class _MetadataChunk extends _TokenChunk {
+ _MetadataChunk(int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+
+ void printMetadataOn(StringBuffer sb, String indent) {
+ int endOfLast = startToken.end;
+ sb.write(indent);
+ Token token = startToken;
+ Token afterEnd = endToken.next;
+ while (token != afterEnd) {
+ if (token.offset > endOfLast) {
+ sb.write(" ");
+ }
+
+ sb.write(token.lexeme);
+ endOfLast = token.end;
+ token = token.next;
+ }
+ sb.write("\n");
+ }
+}
+
+class _UnknownChunk extends _TokenChunk {
+ _UnknownChunk(int originalPosition, Token startToken, Token endToken)
+ : super(originalPosition, startToken, endToken);
+}
+
+class _UnknownTokenBuilder {
+ Token start;
+ Token interimEnd;
+}
+
+class BoxedInt {
+ int value;
+ BoxedInt(this.value);
+}
+
+// TODO(jensj): Better support for show/hide on imports/exports.
+
+String textualOutline(List<int> rawBytes,
+ {bool throwOnUnexpected: false,
+ bool performModelling: false,
+ bool addMarkerForUnknownForTest: false}) {
+ // TODO(jensj): We need to specify the scanner settings to match that of the
+ // compiler!
+ Uint8List bytes = new Uint8List(rawBytes.length + 1);
+ bytes.setRange(0, rawBytes.length, rawBytes);
+
+ List<_Chunk> parsedChunks = new List<_Chunk>();
+
+ BoxedInt originalPosition = new BoxedInt(0);
+
+ Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, includeComments: false,
+ languageVersionChanged:
+ (Scanner scanner, LanguageVersionToken languageVersion) {
+ parsedChunks.add(new _LanguageVersionChunk(originalPosition.value++,
+ languageVersion.major, languageVersion.minor));
+ });
+ Token firstToken = scanner.tokenize();
+ if (firstToken == null) {
+ if (throwOnUnexpected) throw "firstToken is null";
+ return null;
+ }
+
+ TextualOutlineListener listener = new TextualOutlineListener();
+ ClassMemberParser classMemberParser = new ClassMemberParser(listener);
+ classMemberParser.parseUnit(firstToken);
+
+ Token nextToken = firstToken;
+ _UnknownTokenBuilder currentUnknown = new _UnknownTokenBuilder();
+ while (nextToken != null) {
+ if (nextToken is ErrorToken) {
+ return null;
+ }
+ if (nextToken.isEof) break;
+
+ nextToken = _textualizeTokens(
+ listener, nextToken, currentUnknown, parsedChunks, originalPosition);
+ }
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ if (nextToken == null) return null;
+
+ if (performModelling) {
+ parsedChunks = _mergeAndSort(parsedChunks);
+ }
+
+ StringBuffer sb = new StringBuffer();
+ for (_Chunk chunk in parsedChunks) {
+ chunk.printOn(sb, "");
+ }
+
+ return sb.toString();
+}
+
+List<_Chunk> _mergeAndSort(List<_Chunk> chunks) {
+ // TODO(jensj): Only put into new list of there's metadata.
+ List<_Chunk> result =
+ new List<_Chunk>.filled(chunks.length, null, growable: true);
+ List<_MetadataChunk> metadataChunks;
+ int outSize = 0;
+ for (_Chunk chunk in chunks) {
+ if (chunk is _MetadataChunk) {
+ metadataChunks ??= new List<_MetadataChunk>();
+ metadataChunks.add(chunk);
+ } else {
+ chunk.metadata = metadataChunks;
+ metadataChunks = null;
+ chunk.internalMergeAndSort();
+ result[outSize++] = chunk;
+ }
+ }
+ if (metadataChunks != null) {
+ for (_MetadataChunk metadata in metadataChunks) {
+ result[outSize++] = metadata;
+ }
+ }
+ result.length = outSize;
+
+ result.sort();
+ return result;
+}
+
+/// Parses a chunk of tokens and returns the next - unparsed - token or null
+/// on error.
+Token _textualizeTokens(
+ TextualOutlineListener listener,
+ Token token,
+ _UnknownTokenBuilder currentUnknown,
+ List<_Chunk> parsedChunks,
+ BoxedInt originalPosition) {
+ Token classEndToken = listener.classStartToFinish[token];
+ if (classEndToken != null) {
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ _ClassChunk classChunk =
+ new _ClassChunk(originalPosition.value++, token, classEndToken);
+ parsedChunks.add(classChunk);
+ return _textualizeClass(listener, classChunk, originalPosition);
+ }
+
+ Token isImportExportEndToken = listener.importExportsStartToFinish[token];
+ if (isImportExportEndToken != null) {
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ _ImportExportChunk importExportChunk =
+ new _ImportExportChunk(originalPosition.value++);
+ parsedChunks.add(importExportChunk);
+ return _textualizeImportExports(listener, token, importExportChunk);
+ }
+
+ Token isKnownUnsortableEndToken =
+ listener.unsortableElementStartToFinish[token];
+ if (isKnownUnsortableEndToken != null) {
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ Token beginToken = token;
+ parsedChunks.add(new _KnownUnsortableChunk(
+ originalPosition.value++, beginToken, isKnownUnsortableEndToken));
+ return isKnownUnsortableEndToken.next;
+ }
+
+ Token elementEndToken = listener.elementStartToFinish[token];
+ if (elementEndToken != null) {
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ Token beginToken = token;
+ parsedChunks.add(new _ProcedureEtcChunk(originalPosition.value++,
+ beginToken, elementEndToken, listener.nonClassEndOffsets));
+ return elementEndToken.next;
+ }
+
+ Token metadataEndToken = listener.metadataStartToFinish[token];
+ if (metadataEndToken != null) {
+ outputUnknownChunk(currentUnknown, parsedChunks, originalPosition);
+
+ Token beginToken = token;
+ parsedChunks.add(new _MetadataChunk(
+ originalPosition.value++, beginToken, metadataEndToken));
+ return metadataEndToken.next;
+ }
+
+ // This token --- and whatever else tokens until we reach a start token we
+ // know is an unknown chunk. We don't yet know the end.
+ if (currentUnknown.start == null) {
+ // Start of unknown chunk.
+ currentUnknown.start = token;
+ currentUnknown.interimEnd = token;
+ } else {
+ // Continued unknown chunk.
+ currentUnknown.interimEnd = token;
+ }
+ return token.next;
+}
+
+Token _textualizeImportExports(TextualOutlineListener listener, Token token,
+ _ImportExportChunk importExportChunk) {
+ int originalPosition = 0;
+ Token endToken = listener.importExportsStartToFinish[token];
+ while (endToken != null) {
+ importExportChunk.content
+ .add(new _SingleImportExportChunk(originalPosition++, token, endToken));
+ token = endToken.next;
+ endToken = listener.importExportsStartToFinish[token];
+ }
+
+ return token;
+}
+
+Token _textualizeClass(TextualOutlineListener listener, _ClassChunk classChunk,
+ BoxedInt originalPosition) {
+ Token token = classChunk.startToken;
+ // Class header.
+ while (token != classChunk.endToken) {
+ if (token.endGroup == classChunk.endToken) {
+ break;
+ }
+ token = token.next;
+ }
+ classChunk.headerEnd = token;
+
+ if (token == classChunk.endToken) {
+ // This for instance happens on named mixins, e.g.
+ // class C<T> = Object with A<Function(T)>;
+ // or when the class has no content, e.g.
+ // class C { }
+ // either way, output the end token right away to avoid a weird line break.
+ } else {
+ token = token.next;
+ // "Normal" class with (possibly) content.
+ _UnknownTokenBuilder currentUnknown = new _UnknownTokenBuilder();
+ while (token != classChunk.endToken) {
+ token = _textualizeTokens(listener, token, currentUnknown,
+ classChunk.content, originalPosition);
+ }
+ outputUnknownChunk(currentUnknown, classChunk.content, originalPosition);
+ classChunk.footerStart = classChunk.endToken;
+ }
+
+ return classChunk.endToken.next;
+}
+
+/// Outputs an unknown chunk if one has been started.
+///
+/// Resets the given builder.
+void outputUnknownChunk(_UnknownTokenBuilder _currentUnknown,
+ List<_Chunk> parsedChunks, BoxedInt originalPosition) {
+ if (_currentUnknown.start == null) return;
+ parsedChunks.add(new _UnknownChunk(
+ originalPosition.value++,
+ _currentUnknown.start,
+ _currentUnknown.interimEnd,
+ ));
+ _currentUnknown.start = null;
+ _currentUnknown.interimEnd = null;
+}
+
+main(List<String> args) {
+ File f = new File(args[0]);
+ Uint8List data = f.readAsBytesSync();
+ String outline =
+ textualOutline(data, throwOnUnexpected: true, performModelling: true);
+ if (args.length > 1 && args[1] == "--overwrite") {
+ f.writeAsStringSync(outline);
+ } else if (args.length > 1 && args[1] == "--benchmark") {
+ Stopwatch stopwatch = new Stopwatch()..start();
+ for (int i = 0; i < 100; i++) {
+ String outline2 =
+ textualOutline(data, throwOnUnexpected: true, performModelling: true);
+ if (outline2 != outline) throw "Not the same result every time";
+ }
+ stopwatch.stop();
+ print("First 100 took ${stopwatch.elapsedMilliseconds} ms");
+ stopwatch = new Stopwatch()..start();
+ for (int i = 0; i < 10000; i++) {
+ String outline2 =
+ textualOutline(data, throwOnUnexpected: true, performModelling: true);
+ if (outline2 != outline) throw "Not the same result every time";
+ }
+ stopwatch.stop();
+ print("Next 10,000 took ${stopwatch.elapsedMilliseconds} ms");
+ } else {
+ print(outline);
+ }
+}
+
+class TextualOutlineListener extends DirectiveListener {
+ Set<int> nonClassEndOffsets = new Set<int>();
+ Map<Token, Token> classStartToFinish = {};
+ Map<Token, Token> elementStartToFinish = {};
+ Map<Token, Token> metadataStartToFinish = {};
+ Map<Token, Token> importExportsStartToFinish = {};
+ Map<Token, Token> unsortableElementStartToFinish = {};
+
+ @override
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ nonClassEndOffsets.add(endToken.offset);
+ elementStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+ nonClassEndOffsets.add(endToken.offset);
+ elementStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void endClassFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ nonClassEndOffsets.add(endToken.offset);
+ elementStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
+ // Allow native functions.
+ }
+
+ @override
+ void endClassFields(
+ Token abstractToken,
+ Token externalToken,
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ elementStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void endTopLevelFields(
+ Token externalToken,
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ elementStartToFinish[beginToken] = endToken;
+ }
+
+ void endFunctionTypeAlias(
+ Token typedefKeyword, Token equals, Token endToken) {
+ elementStartToFinish[typedefKeyword] = endToken;
+ }
+
+ void endEnum(Token enumKeyword, Token leftBrace, int count) {
+ elementStartToFinish[enumKeyword] = leftBrace.endGroup;
+ }
+
+ @override
+ void endLibraryName(Token libraryKeyword, Token semicolon) {
+ unsortableElementStartToFinish[libraryKeyword] = semicolon;
+ }
+
+ @override
+ void endPart(Token partKeyword, Token semicolon) {
+ unsortableElementStartToFinish[partKeyword] = semicolon;
+ }
+
+ @override
+ void endPartOf(
+ Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
+ unsortableElementStartToFinish[partKeyword] = semicolon;
+ }
+
+ @override
+ void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+ // Metadata's endToken is the one *after* the actual end of the metadata.
+ metadataStartToFinish[beginToken] = endToken.previous;
+ }
+
+ @override
+ void endClassDeclaration(Token beginToken, Token endToken) {
+ classStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void endMixinDeclaration(Token mixinKeyword, Token endToken) {
+ classStartToFinish[mixinKeyword] = endToken;
+ }
+
+ @override
+ void endExtensionDeclaration(
+ Token extensionKeyword, Token onKeyword, Token endToken) {
+ classStartToFinish[extensionKeyword] = endToken;
+ }
+
+ @override
+ void endNamedMixinApplication(Token beginToken, Token classKeyword,
+ Token equals, Token implementsKeyword, Token endToken) {
+ classStartToFinish[beginToken] = endToken;
+ }
+
+ @override
+ void endImport(Token importKeyword, Token semicolon) {
+ importExportsStartToFinish[importKeyword] = semicolon;
+ }
+
+ @override
+ void endExport(Token exportKeyword, Token semicolon) {
+ importExportsStartToFinish[exportKeyword] = semicolon;
+ }
+}
diff --git a/pkg/front_end/test/fasta/textual_outline_suite.dart b/pkg/front_end/test/fasta/textual_outline_suite.dart
index db5dda5..c622db4 100644
--- a/pkg/front_end/test/fasta/textual_outline_suite.dart
+++ b/pkg/front_end/test/fasta/textual_outline_suite.dart
@@ -9,7 +9,7 @@
import 'package:dart_style/dart_style.dart' show DartFormatter;
-import 'package:front_end/src/fasta/util/textual_outline.dart';
+import 'package:front_end/src/fasta/util/textual_outline_v2.dart';
import 'package:testing/testing.dart'
show
Chain,
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 2c43748..32e6192 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -124,6 +124,7 @@
boolean
bother
boundness
+boxed
breadcrumbs
brianwilkerson
bs
@@ -425,6 +426,7 @@
fo
foo
foobar
+footer
foreign
formed
former
@@ -508,6 +510,7 @@
ids
iff
il
+imitate
immutability
impl
implementers
@@ -538,6 +541,7 @@
instanceof
instantiator
intentionally
+interim
interior
interleaved
intermediate
@@ -751,6 +755,7 @@
orphans
ors
os
+outputs
outputting
overlap
overloader
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index c74ced0..bf3dc81 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -508,6 +508,8 @@
resource
respected
response
+result1
+result2
retaining
retainingpath
retains
@@ -552,6 +554,7 @@
stashed
stat
stats
+stay
std
stdio
strip
@@ -625,6 +628,8 @@
uses8
usual
uuid
+v1
+v2
val
vars
verbatim
diff --git a/pkg/front_end/test/textual_outline_test.dart b/pkg/front_end/test/textual_outline_test.dart
index f95915f..59bf5eb 100644
--- a/pkg/front_end/test/textual_outline_test.dart
+++ b/pkg/front_end/test/textual_outline_test.dart
@@ -1,5 +1,5 @@
import "dart:convert";
-import "package:front_end/src/fasta/util/textual_outline.dart";
+import "package:front_end/src/fasta/util/textual_outline_v2.dart";
main() {
// Doesn't sort if not asked to perform modelling.
@@ -107,12 +107,12 @@
if (result !=
"""
@a
-@A(2)
-typedef void F1();
+@A(3)
+int f1, f2;
@a
-@A(3)
-int f1, f2;""") {
+@A(2)
+typedef void F1();""") {
throw "Unexpected result: $result";
}
@@ -131,12 +131,12 @@
if (result !=
"""
@a
-@A(2)
-typedef void F1();
+@A(3)
+int f1, f2;
@a
-@A(3)
-int f1, f2;""") {
+@A(2)
+typedef void F1();""") {
throw "Unexpected result: $result";
}
@@ -269,4 +269,72 @@
bar() {}""") {
throw "Unexpected result: $result";
}
+
+ // Ending metadata (not associated with anything) is still present.
+ // TODO: The extra metadata should actually stay at the bottom as it's not
+ // associated with anything and it will now basically be associated with foo.
+ result = textualOutline(utf8.encode("""
+@Object2()
+foo() {
+ // hello
+}
+
+@Object1()
+"""),
+ throwOnUnexpected: true,
+ performModelling: true,
+ addMarkerForUnknownForTest: true);
+ if (result !=
+ """
+@Object2()
+foo() {}
+
+@Object1()""") {
+ throw "Unexpected result: $result";
+ }
+
+ // Sorting of question mark types.
+ result = textualOutline(utf8.encode("""
+class Class1 {
+ Class1? get nullable1 => property1;
+ Class2? get property => null;
+ Class1 get nonNullable1 => property1;
+ Class2 get property1 => new Class1();
+}
+"""),
+ throwOnUnexpected: true,
+ performModelling: true,
+ addMarkerForUnknownForTest: true);
+ if (result !=
+ """
+class Class1 {
+ Class1? get nullable1 => property1;
+ Class1 get nonNullable1 => property1;
+ Class2? get property => null;
+ Class2 get property1 => new Class1();
+}""") {
+ throw "Unexpected result: $result";
+ }
+
+ // Sorting of various classes with numbers and less than.
+ result = textualOutline(utf8.encode("""
+class C2<V> = Super<V> with Mixin<V>;
+class C<V> extends Super<V> with Mixin<V> {}
+class D extends Super with Mixin {}
+class D2 = Super with Mixin;
+"""),
+ throwOnUnexpected: true,
+ performModelling: true,
+ addMarkerForUnknownForTest: true);
+ if (result !=
+ """
+class C<V> extends Super<V> with Mixin<V> {}
+
+class C2<V> = Super<V> with Mixin<V>;
+
+class D extends Super with Mixin {}
+
+class D2 = Super with Mixin;""") {
+ throw "Unexpected result: $result";
+ }
}
diff --git a/pkg/front_end/testcases/general/annotation_top.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/annotation_top.dart.textual_outline_modelled.expect
index faefe48..11150ed 100644
--- a/pkg/front_end/testcases/general/annotation_top.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/annotation_top.dart.textual_outline_modelled.expect
@@ -2,13 +2,15 @@
@A(1)
library test;
+class A {
+ const A(int value);
+}
+
@a
@A(2)
class C {}
-@a
-@A(2)
-typedef void F1();
+const Object a = const Object();
@a
@A(3)
int f1, f2;
@@ -16,11 +18,8 @@
@A(3)
typedef F2 = void Function();
@a
+@A(2)
+typedef void F1();
+@a
@A(4)
void main() {}
-
-class A {
- const A(int value);
-}
-
-const Object a = const Object();
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/ffi_sample.dart.textual_outline_modelled.expect
index f9d72da..2b9a9f6 100644
--- a/pkg/front_end/testcases/general/ffi_sample.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.textual_outline_modelled.expect
@@ -2,11 +2,11 @@
import 'dart:ffi';
class Coordinate extends Struct {
+ Pointer<Coordinate> next;
@Double()
double x;
@Double()
double y;
- Pointer<Coordinate> next;
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
}
diff --git a/pkg/front_end/testcases/general/generic_function_typedef.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/generic_function_typedef.dart.textual_outline_modelled.expect
index 5df2b1e..40fbff9 100644
--- a/pkg/front_end/testcases/general/generic_function_typedef.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/generic_function_typedef.dart.textual_outline_modelled.expect
@@ -24,9 +24,9 @@
typedef H4 = void Function(void Function<T extends num, S extends num>());
typedef H5 = void Function(void Function<T extends S, S extends num>());
typedef H6 = void Function(void Function<T extends num, S extends T>());
+void Function<T, S>() f3;
+void Function<T>() f1;
void Function<T extends S, S extends num>() f5;
void Function<T extends num, S extends T>() f6;
void Function<T extends num, S extends num>() f4;
void Function<T extends num>() f2;
-void Function<T, S>() f3;
-void Function<T>() f1;
diff --git a/pkg/front_end/testcases/general/infer_field_from_multiple.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/infer_field_from_multiple.dart.textual_outline_modelled.expect
index b2f2254..9e2619e 100644
--- a/pkg/front_end/testcases/general/infer_field_from_multiple.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/infer_field_from_multiple.dart.textual_outline_modelled.expect
@@ -62,6 +62,7 @@
this.field18);
int field12;
int field14;
+ var field1;
var field10;
var field11;
var field13 = 0;
@@ -69,7 +70,6 @@
var field16;
var field17;
var field18;
- var field1;
var field2;
var field3 = 0;
var field4 = 0;
@@ -102,6 +102,7 @@
this.field18);
T field12;
T field14;
+ var field1;
var field10;
var field11;
var field13 = null;
@@ -109,7 +110,6 @@
var field16;
var field17;
var field18;
- var field1;
var field2;
var field3 = 0;
var field4 = 0;
diff --git a/pkg/front_end/testcases/general/metadata_enum.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/metadata_enum.dart.textual_outline_modelled.expect
index 6cb51de..ab7b226 100644
--- a/pkg/front_end/testcases/general/metadata_enum.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/metadata_enum.dart.textual_outline_modelled.expect
@@ -1,4 +1,4 @@
+const a = null;
@a
enum E { E1, E2, E3 }
-const a = null;
main() {}
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/non_covariant_checks.dart.textual_outline_modelled.expect
index fc7f6db..8ac3b96 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart.textual_outline_modelled.expect
@@ -18,28 +18,28 @@
S Function<S extends T>() get getter12 => field12;
S Function<S extends T>(S) field14;
S Function<S extends T>(S) get getter14 => field14;
- T Function(T Function()) field7;
- T Function(T Function()) get getter7 => field7;
- T Function(T Function(T)) field11;
- T Function(T Function(T)) get getter11 => field11;
- T Function(T) field4;
- T Function(T) get getter4 => field4;
T Function() Function() field5;
T Function() Function() get getter5 => field5;
T Function() field2;
T Function() get getter2 => field2;
+ T Function(T) field4;
+ T Function(T) get getter4 => field4;
+ T Function(T Function()) field7;
+ T Function(T Function()) get getter7 => field7;
+ T Function(T Function(T)) field11;
+ T Function(T Function(T)) get getter11 => field11;
T Function(void Function(T)) field9;
T Function(void Function(T)) get getter9 => field9;
T field1;
T get getter1 => field1;
+ void Function(S Function<S extends T>()) field15;
+ void Function(S Function<S extends T>()) get getter15 => field15;
+ void Function(T) field3;
+ void Function(T) get getter3 => field3;
void Function(T Function()) field6;
void Function(T Function()) get getter6 => field6;
void Function(T Function(T)) field10;
void Function(T Function(T)) get getter10 => field10;
- void Function(T) field3;
- void Function(T) get getter3 => field3;
- void Function(S Function<S extends T>()) field15;
- void Function(S Function<S extends T>()) get getter15 => field15;
void Function(void Function(T)) field8;
void Function(void Function(T)) get getter8 => field8;
void Function<S extends T>(S) field13;
diff --git a/pkg/front_end/testcases/general/redirecting_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_factory.dart.textual_outline_modelled.expect
index ca2e3d3..3f02151 100644
--- a/pkg/front_end/testcases/general/redirecting_factory.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory.dart.textual_outline_modelled.expect
@@ -26,10 +26,10 @@
factory SimpleCase() = SimpleCaseImpl<A, B>;
}
-class SimpleCaseImpl2<Ai2, Bi2> implements SimpleCaseImpl<Ai2, Bi2> {}
-
class SimpleCaseImpl<Ai, Bi> implements SimpleCase<Ai, Bi> {
factory SimpleCaseImpl() = SimpleCaseImpl2<Ai, Bi>;
}
+class SimpleCaseImpl2<Ai2, Bi2> implements SimpleCaseImpl<Ai2, Bi2> {}
+
main() {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.textual_outline_modelled.expect
index 5455e6c..72b47ec 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.textual_outline_modelled.expect
@@ -1,7 +1,7 @@
class Foo {
+ Foo.named(p);
@forFactoryItself
factory Foo(@forParameter @anotherForParameter p) = Foo.named;
- Foo.named(p);
}
const anotherForParameter = 3;
diff --git a/pkg/front_end/testcases/general/type_literal_as_metadata.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/type_literal_as_metadata.dart.textual_outline_modelled.expect
index 4127317..54f0474 100644
--- a/pkg/front_end/testcases/general/type_literal_as_metadata.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/type_literal_as_metadata.dart.textual_outline_modelled.expect
@@ -1,8 +1,8 @@
-@A
-class B {}
-
class A {
const A();
}
+@A
+class B {}
+
main() {}
diff --git a/pkg/front_end/testcases/general/vm_type_ops.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/vm_type_ops.dart.textual_outline_modelled.expect
index 96d4e65..e28a446 100644
--- a/pkg/front_end/testcases/general/vm_type_ops.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/vm_type_ops.dart.textual_outline_modelled.expect
@@ -13,8 +13,8 @@
class D<P, Q> extends C<int, Q, P> {
D(tt) : foo = tt;
- Map<P, Q> foo4(w) {}
Map<P, Q> foo;
+ Map<P, Q> foo4(w) {}
foo2(y) {}
foo3<T1, T2>(z) {}
}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/annotation_top.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/annotation_top.dart.textual_outline_modelled.expect
index 093fb5b..1184734 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/annotation_top.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/annotation_top.dart.textual_outline_modelled.expect
@@ -3,13 +3,15 @@
@A(1)
library test;
+class A {
+ const A(int value);
+}
+
@a
@A(2)
class C {}
-@a
-@A(2)
-typedef void F1();
+const Object a = const Object();
@a
@A(3)
int f1, f2;
@@ -17,11 +19,8 @@
@A(3)
typedef F2 = void Function();
@a
+@A(2)
+typedef void F1();
+@a
@A(4)
void main() {}
-
-class A {
- const A(int value);
-}
-
-const Object a = const Object();
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
index ed74cca..a7af7c2 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.textual_outline_modelled.expect
@@ -3,11 +3,11 @@
import 'dart:ffi';
class Coordinate extends Struct {
+ Pointer<Coordinate> next;
@Double()
double x;
@Double()
double y;
- Pointer<Coordinate> next;
factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {}
}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/metadata_enum.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/metadata_enum.dart.textual_outline_modelled.expect
index 591a2e5..0bccd4a 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/metadata_enum.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/metadata_enum.dart.textual_outline_modelled.expect
@@ -1,5 +1,5 @@
// @dart = 2.6
+const a = null;
@a
enum E { E1, E2, E3 }
-const a = null;
main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/non_covariant_checks.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/non_covariant_checks.dart.textual_outline_modelled.expect
index 6969145..d3208cf 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/non_covariant_checks.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/non_covariant_checks.dart.textual_outline_modelled.expect
@@ -19,28 +19,28 @@
S Function<S extends T>() get getter12 => field12;
S Function<S extends T>(S) field14;
S Function<S extends T>(S) get getter14 => field14;
- T Function(T Function()) field7;
- T Function(T Function()) get getter7 => field7;
- T Function(T Function(T)) field11;
- T Function(T Function(T)) get getter11 => field11;
- T Function(T) field4;
- T Function(T) get getter4 => field4;
T Function() Function() field5;
T Function() Function() get getter5 => field5;
T Function() field2;
T Function() get getter2 => field2;
+ T Function(T) field4;
+ T Function(T) get getter4 => field4;
+ T Function(T Function()) field7;
+ T Function(T Function()) get getter7 => field7;
+ T Function(T Function(T)) field11;
+ T Function(T Function(T)) get getter11 => field11;
T Function(void Function(T)) field9;
T Function(void Function(T)) get getter9 => field9;
T field1;
T get getter1 => field1;
+ void Function(S Function<S extends T>()) field15;
+ void Function(S Function<S extends T>()) get getter15 => field15;
+ void Function(T) field3;
+ void Function(T) get getter3 => field3;
void Function(T Function()) field6;
void Function(T Function()) get getter6 => field6;
void Function(T Function(T)) field10;
void Function(T Function(T)) get getter10 => field10;
- void Function(T) field3;
- void Function(T) get getter3 => field3;
- void Function(S Function<S extends T>()) field15;
- void Function(S Function<S extends T>()) get getter15 => field15;
void Function(void Function(T)) field8;
void Function(void Function(T)) get getter8 => field8;
void Function<S extends T>(S) field13;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory.dart.textual_outline_modelled.expect
index 78d09fc..85db97c 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory.dart.textual_outline_modelled.expect
@@ -27,10 +27,10 @@
factory SimpleCase() = SimpleCaseImpl<A, B>;
}
-class SimpleCaseImpl2<Ai2, Bi2> implements SimpleCaseImpl<Ai2, Bi2> {}
-
class SimpleCaseImpl<Ai, Bi> implements SimpleCase<Ai, Bi> {
factory SimpleCaseImpl() = SimpleCaseImpl2<Ai, Bi>;
}
+class SimpleCaseImpl2<Ai2, Bi2> implements SimpleCaseImpl<Ai2, Bi2> {}
+
main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory_metadata.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory_metadata.dart.textual_outline_modelled.expect
index 465cd5b..0b5eb06 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory_metadata.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/redirecting_factory_metadata.dart.textual_outline_modelled.expect
@@ -1,8 +1,8 @@
// @dart = 2.6
class Foo {
+ Foo.named(p);
@forFactoryItself
factory Foo(@forParameter @anotherForParameter p) = Foo.named;
- Foo.named(p);
}
const anotherForParameter = 3;
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/type_literal_as_metadata.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/type_literal_as_metadata.dart.textual_outline_modelled.expect
index ed301d3..83562c7 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/type_literal_as_metadata.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/type_literal_as_metadata.dart.textual_outline_modelled.expect
@@ -1,9 +1,9 @@
// @dart = 2.6
-@A
-class B {}
-
class A {
const A();
}
+@A
+class B {}
+
main() {}
diff --git a/pkg/front_end/testcases/inference/downwards_inference_annotations_typedef.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/inference/downwards_inference_annotations_typedef.dart.textual_outline_modelled.expect
index 9b53595..7d31ff1 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_annotations_typedef.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_annotations_typedef.dart.textual_outline_modelled.expect
@@ -1,10 +1,9 @@
library test;
-@Foo(const [])
-typedef void F();
-
class Foo {
const Foo(List<String> l);
}
main() {}
+@Foo(const [])
+typedef void F();
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_3.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/inference/future_union_downwards_3.dart.textual_outline_modelled.expect
index 9307472..f86b37e 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_3.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_3.dart.textual_outline_modelled.expect
@@ -2,11 +2,11 @@
import 'dart:async';
-Future f;
Future<List<int>> g2() async {}
Future<List<int>> g3() async {}
Future<List<int>> t2 = f.then((_) => [3]);
Future<int> t1 = f.then((_) => new Future.value('hi'));
+Future f;
class MyFuture<T> implements Future<T> {
MyFuture() {}
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_4.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/inference/future_union_downwards_4.dart.textual_outline_modelled.expect
index 3d8b7c8..d0adb06 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_4.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_4.dart.textual_outline_modelled.expect
@@ -2,11 +2,11 @@
import 'dart:async';
-Future f;
Future<List<int>> g2() async {}
Future<List<int>> g3() async {}
Future<List<int>> t2 = f.then((_) => [3]);
Future<int> t1 = f.then((_) => new MyFuture.value('hi'));
+Future f;
class MyFuture<T> implements Future<T> {
MyFuture() {}
diff --git a/pkg/front_end/testcases/late_lowering/return_late.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/late_lowering/return_late.dart.textual_outline_modelled.expect
index e1ef11f..e7887f2 100644
--- a/pkg/front_end/testcases/late_lowering/return_late.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/late_lowering/return_late.dart.textual_outline_modelled.expect
@@ -5,6 +5,6 @@
}
expect(expected, actual) {}
-int returnNonNullable(int value) {}
int? returnNullable(int? value) {}
+int returnNonNullable(int value) {}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/constant_null_check.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/constant_null_check.dart.textual_outline_modelled.expect
index c4a2339..392f4f1 100644
--- a/pkg/front_end/testcases/nnbd/constant_null_check.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/constant_null_check.dart.textual_outline_modelled.expect
@@ -5,9 +5,9 @@
const Class e = const Class(a);
const Class f = const Class(c);
-const int b = a!;
const int? a = 42;
const int? c = null;
const int? d = c!;
+const int b = a!;
expect(expected, actual) {}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/function_types.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/function_types.dart.textual_outline_modelled.expect
index 8a2c7a1..0b0019c 100644
--- a/pkg/front_end/testcases/nnbd/function_types.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/function_types.dart.textual_outline_modelled.expect
@@ -1,5 +1,5 @@
-F bar() => foo;
F? baz() => foo;
+F bar() => foo;
Function()? foobar(Function()? x) => null;
class A<T> {}
@@ -10,6 +10,6 @@
main() {}
typedef F = void Function();
-void Function() hest() => foo;
void Function()? fisk() => foo;
+void Function() hest() => foo;
void foo() {}
diff --git a/pkg/front_end/testcases/nnbd/future_or_variables.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/future_or_variables.dart.textual_outline_modelled.expect
index ff98b1c..82b623e 100644
--- a/pkg/front_end/testcases/nnbd/future_or_variables.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/future_or_variables.dart.textual_outline_modelled.expect
@@ -1,16 +1,16 @@
import 'dart:async';
-FutureOr topLevelField1;
FutureOr<FutureOr> topLevelField3;
FutureOr<int?> topLevelField2;
+FutureOr topLevelField1;
class Class1 {
- FutureOr instanceField1;
FutureOr<FutureOr> instanceField3;
FutureOr<int?> instanceField2;
- static FutureOr staticField1;
+ FutureOr instanceField1;
static FutureOr<FutureOr> staticField3;
static FutureOr<int?> staticField2;
+ static FutureOr staticField1;
static void staticMethod1(
[FutureOr parameter1,
FutureOr<int?> parameter2,
@@ -33,9 +33,9 @@
Class2.constructor1(
this.instanceField1, this.instanceField2, this.instanceField3);
Class2.constructor2();
- FutureOr instanceField1;
FutureOr<FutureOr> instanceField3;
FutureOr<int?> instanceField2;
+ FutureOr instanceField1;
}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue41102.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue41102.dart.textual_outline_modelled.expect
index dee803a..35fb63f 100644
--- a/pkg/front_end/testcases/nnbd/issue41102.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/issue41102.dart.textual_outline_modelled.expect
@@ -24,6 +24,6 @@
final t = StreamTransformer.fromHandlers(
handleData: (data, sink) => Future.microtask(() => sink.add(data)),
handleDone: (sink) => Future.microtask(() => sink.close()));
-int Function()? s13;
int? s5;
+int Function()? s13;
void main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect
index 5cdcfec..26937e5 100644
--- a/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect
@@ -6,5 +6,5 @@
}
main() {}
-wrap2<R>(A<R> Function() f) {}
wrap<R>(R Function() f) {}
+wrap2<R>(A<R> Function() f) {}
diff --git a/pkg/front_end/testcases/nnbd/null_access.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/null_access.dart.textual_outline_modelled.expect
index 849bf32..0f1cebe 100644
--- a/pkg/front_end/testcases/nnbd/null_access.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/null_access.dart.textual_outline_modelled.expect
@@ -2,9 +2,9 @@
Class call() => this;
Class get nonNullableClass => this;
NullableIndexClass get nonNullableNullableIndexClass => NullableIndexClass();
+ int? nullableField;
int nonNullableField = 0;
int operator [](int key) => key;
- int? nullableField;
void operator []=(int key, int value) {}
}
diff --git a/pkg/front_end/testcases/nnbd/null_aware_chain.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/null_aware_chain.dart.textual_outline_modelled.expect
index f928776..156fbdd 100644
--- a/pkg/front_end/testcases/nnbd/null_aware_chain.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/null_aware_chain.dart.textual_outline_modelled.expect
@@ -1,8 +1,8 @@
class Class {
- Class get getter1 => this;
Class([this.field]);
Class? field;
Class? get getter2 => field;
+ Class get getter1 => this;
}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.textual_outline_modelled.expect
index 99a428a..aaf9215 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.textual_outline_modelled.expect
@@ -1,12 +1,12 @@
class Class1 {
- Class1 get nonNullable1 => property1;
- Class1 get property1 => new Class1();
- Class1 nonNullable1Method() => nonNullable1;
Class1? get nullable1 => property1;
Class1? get property => null;
Class1? operator +(int value) => nullable1;
Class1? operator -() => nullable1;
Class1? operator [](Class1? key) => nullable1;
+ Class1 get nonNullable1 => property1;
+ Class1 get property1 => new Class1();
+ Class1 nonNullable1Method() => nonNullable1;
Class2 get nonNullable2 => property2;
Class2 get property2 => new Class2();
void operator []=(Class1? key, Class1? value) {}
diff --git a/pkg/front_end/testcases/nnbd/override_checks.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/override_checks.dart.textual_outline_modelled.expect
index c0742df..7ba713a 100644
--- a/pkg/front_end/testcases/nnbd/override_checks.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/override_checks.dart.textual_outline_modelled.expect
@@ -7,8 +7,8 @@
}
class B2 extends B1 {
- num bar = 3.14;
num? get baz => null;
+ num bar = 3.14;
void hest(num value) {}
}
diff --git a/pkg/front_end/testcases/nnbd/redundant_type_casts.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/redundant_type_casts.dart.textual_outline_modelled.expect
index 268c668..f56a0d9 100644
--- a/pkg/front_end/testcases/nnbd/redundant_type_casts.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/redundant_type_casts.dart.textual_outline_modelled.expect
@@ -1,6 +1,6 @@
class A<T> {
- T get current => _current as T;
T? _current;
+ T get current => _current as T;
}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/return_late.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/return_late.dart.textual_outline_modelled.expect
index e1ef11f..e7887f2 100644
--- a/pkg/front_end/testcases/nnbd/return_late.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/return_late.dart.textual_outline_modelled.expect
@@ -5,6 +5,6 @@
}
expect(expected, actual) {}
-int returnNonNullable(int value) {}
int? returnNullable(int? value) {}
+int returnNonNullable(int value) {}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/return_null.dart.textual_outline_modelled.expect
index 5d7cbcb6..cc610a6 100644
--- a/pkg/front_end/testcases/nnbd/return_null.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/return_null.dart.textual_outline_modelled.expect
@@ -2,12 +2,12 @@
Enum caseReturn1(Enum e) {}
Enum caseReturn2(Enum e) {}
-Future returnAsync1() async {}
Future<int?> returnAsync6() async {}
Future<int?> returnAsync7() async {}
-FutureOr returnAsync2() async {}
+Future returnAsync1() async {}
FutureOr<int> returnAsync3() async {}
FutureOr<int?> returnAsync4() async {}
+FutureOr returnAsync2() async {}
Iterable yieldSync() sync* {}
Stream yieldAsync() async* {}
String returnExplicit() {}
diff --git a/pkg/front_end/testcases/nnbd/simple_never.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/simple_never.dart.textual_outline_modelled.expect
index a729e48..df6d2c7 100644
--- a/pkg/front_end/testcases/nnbd/simple_never.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/simple_never.dart.textual_outline_modelled.expect
@@ -1,3 +1,3 @@
-Never foo() {}
Never? bar() => null;
+Never foo() {}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.textual_outline_modelled.expect
index 6350615..a4acdf6 100644
--- a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.textual_outline_modelled.expect
@@ -1,8 +1,8 @@
Never never() => throw "Never";
class A<X extends Object, Y extends Object?> {
- X foo() => never();
X? bar() => null;
+ X foo() => never();
Y baz() => never();
}
diff --git a/pkg/front_end/testcases/nnbd_mixed/member_inheritance_from_opt_out.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/member_inheritance_from_opt_out.dart.textual_outline_modelled.expect
index 860366f..42c9fb7 100644
--- a/pkg/front_end/testcases/nnbd_mixed/member_inheritance_from_opt_out.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/member_inheritance_from_opt_out.dart.textual_outline_modelled.expect
@@ -3,18 +3,6 @@
import 'member_inheritance_from_opt_out_lib.dart';
abstract class Interface {
- int field1 = 0;
- int get field3;
- int get getter1;
- int get property1;
- int method1();
- int method3a(int a, int b);
- int method3b(int a, [int b]);
- int method3c([int a, int b]);
- int method5a(int a, {int b: 0});
- int method5b({int a: 0, int b: 0});
- int method5c({required int a, required int b});
- int property3 = 0;
int? field2;
int? get field4;
int? get getter2;
@@ -27,6 +15,18 @@
int? method6b({int? a, int? b});
int? method6c({required int? a, required int? b});
int? property4;
+ int field1 = 0;
+ int get field3;
+ int get getter1;
+ int get property1;
+ int method1();
+ int method3a(int a, int b);
+ int method3b(int a, [int b]);
+ int method3c([int a, int b]);
+ int method5a(int a, {int b: 0});
+ int method5b({int a: 0, int b: 0});
+ int method5c({required int a, required int b});
+ int property3 = 0;
void set field3(int value);
void set field4(int? value);
void set property1(int value);
@@ -40,18 +40,6 @@
class Class2a extends LegacyClass implements Interface {}
class Class2b extends LegacyClass implements Interface {
- int field1 = 0;
- int get field3 => 0;
- int get getter1 => 0;
- int get property1 => 0;
- int method1() => 0;
- int method3a(int a, int b) => 0;
- int method3b(int a, [int b = 42]) => 0;
- int method3c([int a = 42, int b = 42]) => 0;
- int method5a(int a, {int b: 0}) => 0;
- int method5b({int a: 0, int b: 0}) => 0;
- int method5c({required int a, required int b}) => 0;
- int property3 = 0;
int? field2;
int? get field4 => 0;
int? get getter2 => 0;
@@ -64,6 +52,18 @@
int? method6b({int? a, int? b}) => 0;
int? method6c({required int? a, required int? b}) => 0;
int? property4;
+ int field1 = 0;
+ int get field3 => 0;
+ int get getter1 => 0;
+ int get property1 => 0;
+ int method1() => 0;
+ int method3a(int a, int b) => 0;
+ int method3b(int a, [int b = 42]) => 0;
+ int method3c([int a = 42, int b = 42]) => 0;
+ int method5a(int a, {int b: 0}) => 0;
+ int method5b({int a: 0, int b: 0}) => 0;
+ int method5c({required int a, required int b}) => 0;
+ int property3 = 0;
void set field3(int value) {}
void set field4(int? value) {}
void set property1(int value) {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/messages_with_types_opt_in.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/messages_with_types_opt_in.dart.textual_outline_modelled.expect
index 0f30fad..c612c35 100644
--- a/pkg/front_end/testcases/nnbd_mixed/messages_with_types_opt_in.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/messages_with_types_opt_in.dart.textual_outline_modelled.expect
@@ -1,24 +1,24 @@
import 'messages_with_types_opt_out.dart';
class SubInIn extends SuperIn {
- String nonNullableSame() => "bar";
String? nullableSame() => "foo";
- T nonNullableBad<T>(T t) => t;
+ String nonNullableSame() => "bar";
T? nullableBad<T>(T t) => null;
+ T nonNullableBad<T>(T t) => t;
}
class SubOutIn extends SuperOut {
- String nonNullableSame() => "bar";
String? nullableSame() => "foo";
- T nonNullableBad<T>(T t) => t;
+ String nonNullableSame() => "bar";
T? nullableBad<T>(T t) => null;
+ T nonNullableBad<T>(T t) => t;
}
class SuperIn {
- String nonNullableSame() => "bar";
String? nullableSame() => "foo";
- int nonNullableBad<T>(T t) => 2;
+ String nonNullableSame() => "bar";
int? nullableBad<T>(T t) => 1;
+ int nonNullableBad<T>(T t) => 2;
}
double nonNullableVar = 4.0;
diff --git a/pkg/front_end/testcases/rasta/generic_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/rasta/generic_factory.dart.textual_outline_modelled.expect
index 0bec190..449bfaf 100644
--- a/pkg/front_end/testcases/rasta/generic_factory.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/rasta/generic_factory.dart.textual_outline_modelled.expect
@@ -11,14 +11,14 @@
factory B.b() = C<C2>;
}
+class C<U> extends B<U> {
+ C() : super.internal();
+}
+
class C1 {}
class C2 {}
class C3 {}
-class C<U> extends B<U> {
- C() : super.internal();
-}
-
main() {}
diff --git a/pkg/front_end/testcases/rasta/super_mixin.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/rasta/super_mixin.dart.textual_outline_modelled.expect
index 831a329..526090a 100644
--- a/pkg/front_end/testcases/rasta/super_mixin.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/rasta/super_mixin.dart.textual_outline_modelled.expect
@@ -1,9 +1,9 @@
import "mixin_library.dart" show Mixin;
-class C2<V> = Super<V> with Mixin<V>;
-
class C<V> extends Super<V> with Mixin<V> {}
+class C2<V> = Super<V> with Mixin<V>;
+
class D extends Super with Mixin {}
class D2 = Super with Mixin;
diff --git a/pkg/front_end/testcases/regress/issue_36793.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/regress/issue_36793.dart.textual_outline_modelled.expect
index aefe023..b3d1993 100644
--- a/pkg/front_end/testcases/regress/issue_36793.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/regress/issue_36793.dart.textual_outline_modelled.expect
@@ -1,6 +1,6 @@
+const int y = 42;
@y
int x = 1;
@y
int x = 2;
-const int y = 42;
main() {}
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect
index 9b4d462..bc846e0 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect
@@ -1,14 +1,13 @@
@valueClass
class A {}
-@valueClass
-class F = B with C;
-
class B {}
class C {}
class D = A with B;
class E = B with A;
+@valueClass
+class F = B with C;
const String valueClass = "valueClass";
main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect
index 89b6414..e50bc0f 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect
@@ -1,9 +1,9 @@
-@valueClass
-class Cat extends Animal {}
-
class Animal {
final int numLegs;
}
+@valueClass
+class Cat extends Animal {}
+
const String valueClass = "valueClass";
main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect
index 9ee23d7..d7e499c 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect
@@ -1,9 +1,9 @@
-@valueClass
-class Cat extends Animal {}
-
class Animal {
int numLegs;
}
+@valueClass
+class Cat extends Animal {}
+
const String valueClass = "valueClass";
main() {}
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect
index ebcb028..650aa4b 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect
@@ -1,9 +1,9 @@
-@valueClass
-class Cat implements Animal {
+class Animal {
final int numLegs;
}
-class Animal {
+@valueClass
+class Cat implements Animal {
final int numLegs;
}
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index e0a2ce2..b0ee0ae 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -2344,6 +2344,8 @@
* Delivery can be delayed if other previously added events are
* still pending delivery, if the subscription is paused,
* or if the subscription isn't listening yet.
+ * If it's necessary to know whether the "done" event has been delievered,
+ * [done] future will complete when that has happend.
*/
void closeSync();
}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 942f4a7..52e5ca3 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -1122,15 +1122,22 @@
_MultiStreamController() : super(null, null, null, null);
void addSync(T data) {
- _subscription._add(data);
+ if (!_mayAddEvent) throw _badEventState();
+ if (hasListener) _subscription._add(data);
}
void addErrorSync(Object error, [StackTrace? stackTrace]) {
- _subscription._addError(error, stackTrace ?? StackTrace.empty);
+ if (!_mayAddEvent) throw _badEventState();
+ if (hasListener) {
+ _subscription._addError(error, stackTrace ?? StackTrace.empty);
+ }
}
void closeSync() {
- _subscription._close();
+ if (isClosed) return;
+ if (!_mayAddEvent) throw _badEventState();
+ _state |= _StreamController._STATE_CLOSED;
+ if (hasListener) _subscription._close();
}
Stream<T> get stream {
diff --git a/tests/lib/async/stream_multi_test.dart b/tests/lib/async/stream_multi_test.dart
index e57c4f4..b2beb44 100644
--- a/tests/lib/async/stream_multi_test.dart
+++ b/tests/lib/async/stream_multi_test.dart
@@ -44,6 +44,7 @@
testStreamsIndependent();
asyncTest(testStreamNonOverlap);
asyncTest(testRepeatLatest);
+ asyncTest(testIncorrectUse);
asyncEnd();
}
@@ -138,3 +139,79 @@
var l3 = await f3;
Expect.listEquals([2, 3], l3);
}
+
+// Test that errors are thrown when required,
+// and use after cancel is ignored.
+Future<void> testIncorrectUse() async {
+ {
+ var lock = Completer();
+ var lock2 = Completer();
+ var stream = Stream.multi((c) async {
+ c.add(2);
+ await lock.future;
+ Expect.isTrue(!c.hasListener);
+ c.add(2);
+ c.addError("Error");
+ c.close();
+ // No adding after close.
+ Expect.throws<StateError>(() => c.add(3));
+ Expect.throws<StateError>(() => c.addSync(3));
+ Expect.throws<StateError>(() => c.addError("E"));
+ Expect.throws<StateError>(() => c.addErrorSync("E"));
+ Expect.throws<StateError>(() => c.addStream(Stream.empty()));
+ lock2.complete();
+ });
+ await for (var v in stream) {
+ Expect.equals(2, v);
+ break; // Cancels subscription.
+ }
+ lock.complete();
+ await lock2.future;
+ }
+
+ {
+ var lock = Completer();
+ var lock2 = Completer();
+ var stream = Stream.multi((c) async {
+ c.add(2);
+ await lock.future;
+ Expect.isTrue(!c.hasListener);
+ c.addSync(2);
+ c.addErrorSync("Error");
+ c.closeSync();
+ // No adding after close.
+ Expect.throws<StateError>(() => c.add(3));
+ Expect.throws<StateError>(() => c.addSync(3));
+ Expect.throws<StateError>(() => c.addError("E"));
+ Expect.throws<StateError>(() => c.addErrorSync("E"));
+ Expect.throws<StateError>(() => c.addStream(Stream.empty()));
+ lock2.complete();
+ });
+ await for (var v in stream) {
+ Expect.equals(2, v);
+ break; // Cancels subscription.
+ }
+ lock.complete();
+ await lock2.future;
+ }
+
+ {
+ var stream = Stream.multi((c) async {
+ var c2 = StreamController();
+ c.addStream(c2.stream);
+ // Now adding stream, cannot add events at the same time (for now!).
+ Expect.throws<StateError>(() => c.add(1));
+ Expect.throws<StateError>(() => c.addSync(1));
+ Expect.throws<StateError>(() => c.addError("Error"));
+ Expect.throws<StateError>(() => c.addErrorSync("Error"));
+ Expect.throws<StateError>(() => c.close());
+ Expect.throws<StateError>(() => c.closeSync());
+ await c2.close();
+ c.add(42);
+ c.close();
+ });
+ await for (var v in stream) {
+ Expect.equals(42, v);
+ }
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index f256226..87839ca 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 49
+PRERELEASE 50
PRERELEASE_PATCH 0
\ No newline at end of file