Merge commit '7fd78ed5b606e64d30ec201de9adce6fdf8856ba' into analyzer

This commit is contained in:
Paul Berry 2018-10-22 13:07:09 -07:00
commit 5665636983
180 changed files with 8732 additions and 2099 deletions

View file

@ -32,6 +32,7 @@ dart2js_tools:pkg/dart2js_tools/lib
dart_internal:pkg/dart_internal/lib
dart_style:third_party/pkg_tested/dart_style/lib
dartdoc:third_party/pkg/dartdoc/lib
dartfix:pkg/dartfix/lib
dev_compiler:pkg/dev_compiler/lib
diagnostic:pkg/diagnostic/lib
expect:pkg/expect/lib

View file

@ -7779,16 +7779,17 @@ If $r$ is \TRUE, then the value of $c$ is the result of evaluating the expressio
Otherwise the value of $c$ is the result of evaluating the expression $e_3$.
\LMHash{}
If all of the following hold:
If $e_1$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $e_2$,
unless any of the following are true:
\begin{itemize}
\item $e_1$ shows that a local variable $v$ has type $T$.
\item $v$ is not potentially mutated in $e_2$ or within a function.
\item If the variable $v$ is accessed by a function in $e_2$ then
$v$ is not potentially mutated anywhere in the scope of $v$.
\item $v$ is potentially mutated in $e_2$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $e_2$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
then the type of $v$ is known to be $T$ in $e_2$.
\LMHash{}
It is a compile-time error if the static type of $e_1$ may not be assigned to \code{bool}.
The static type of $c$ is the least upper bound (\ref{leastUpperBounds}) of the static type of $e_2$ and the static type of $e_3$.
@ -7853,18 +7854,30 @@ shows that a local variable $v$ has type $T$
if both of the following conditions hold:
\begin{itemize}
\item Either $e_1$ shows that $v$ has type $T$ or $e_2$ shows that $v$ has type $T$.
\item $v$ is not mutated in $e_2$ or within a function.
\item $v$ is not mutated in $e_2$ or within a function other than the one where $v$ is declared.
\end{itemize}
\LMHash{}
Furthermore, if all of the following hold:
If $e_1$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $e_2$,
unless any of the following are true:
\begin{itemize}
\item $e_1$ shows that $v$ has type $T$.
\item $v$ is not mutated in either $e_1$, $e_2$ or within a function.
\item If $v$ is accessed by a function in $e_2$ then
$v$ is not potentially mutated anywhere in the scope of $v$.
%% The first item here is unnecessary for soundness,
%% and is retained mainly for backwards compatibility.
%% If $e_1$ shows that $v$ has type $T$, then any assignment
%% in $e_1$ does not invalidate that.
%% Removing the line is visible in the semantics, though, because:
%% num x;
%% (x ??= 42) != null && x is int & x.toRadixString(16) != ""
%% is allowed without the line, and disallowed with.
%% At time of writing, the analyzer disallows the code.
\item $v$ is potentially mutated in $e_1$,
\item $v$ is potentially mutated in $e_2$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $e_2$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
then the type of $v$ is known to be $T$ in $e_2$.
\LMHash{}
It is a compile-time error if the static type of $e_1$ may not be assigned to \code{bool} or if the static type of $e_2$ may not be assigned to \code{bool}.
@ -9023,14 +9036,16 @@ If $o$ is \TRUE{}, then the block statement $s_1$ is executed, otherwise the blo
It is a compile-time error if the type of the expression $b$ may not be assigned to \code{bool}.
\LMHash{}
If:
If $b$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $s_2$,
unless any of the following are true
\begin{itemize}
\item $b$ shows that a local variable $v$ has type $T$.
\item $v$ is not potentially mutated in $s_1$ or within a function.
\item If $v$ is accessed by a function in $s_1$ then
$v$ is not potentially mutated anywhere in the scope of $v$.
\item $v$ is potentially mutated in $s_1$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $s_1$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
then the type of $v$ is known to be $T$ in $s_1$.
\LMHash{}
An if statement of the form \code{\IF{} ($e$) $s$} is equivalent to the if statement \code{\IF{} ($e$) $s$ \ELSE{} \{\}}.

View file

@ -3586,7 +3586,7 @@ class MessageType {
}
class NotificationMessage implements Message {
NotificationMessage(this.method, this.jsonrpc) {
NotificationMessage(this.method, this.params, this.jsonrpc) {
if (method == null) {
throw 'method is required but was not provided';
}
@ -3596,8 +3596,14 @@ class NotificationMessage implements Message {
}
factory NotificationMessage.fromJson(Map<String, dynamic> json) {
final method = json['method'];
final params = (json['params'] is List &&
(json['params'].length == 0 ||
json['params'].every((item) => true)))
? new Either2<List<dynamic>, dynamic>.t1(
json['params']?.map((item) => item)?.cast<dynamic>()?.toList())
: (json['params']);
final jsonrpc = json['jsonrpc'];
return new NotificationMessage(method, jsonrpc);
return new NotificationMessage(method, params, jsonrpc);
}
final String jsonrpc;
@ -3605,9 +3611,15 @@ class NotificationMessage implements Message {
/// The method to be invoked.
final String method;
/// The notification's params.
final Either2<List<dynamic>, dynamic> params;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
__result['method'] = method ?? (throw 'method is required but was not set');
if (params != null) {
__result['params'] = params;
}
__result['jsonrpc'] =
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
@ -4140,7 +4152,7 @@ class RenameRegistrationOptions implements TextDocumentRegistrationOptions {
}
class RequestMessage implements Message {
RequestMessage(this.id, this.method, this.jsonrpc) {
RequestMessage(this.id, this.method, this.params, this.jsonrpc) {
if (id == null) {
throw 'id is required but was not provided';
}
@ -4158,8 +4170,14 @@ class RequestMessage implements Message {
? new Either2<num, String>.t2(json['id'])
: (throw '''${json['id']} was not one of (number, string)'''));
final method = json['method'];
final params = (json['params'] is List &&
(json['params'].length == 0 ||
json['params'].every((item) => true)))
? new Either2<List<dynamic>, dynamic>.t1(
json['params']?.map((item) => item)?.cast<dynamic>()?.toList())
: (json['params']);
final jsonrpc = json['jsonrpc'];
return new RequestMessage(id, method, jsonrpc);
return new RequestMessage(id, method, params, jsonrpc);
}
/// The request id.
@ -4169,10 +4187,16 @@ class RequestMessage implements Message {
/// The method to be invoked.
final String method;
/// The method's params.
final Either2<List<dynamic>, dynamic> params;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
__result['id'] = id ?? (throw 'id is required but was not set');
__result['method'] = method ?? (throw 'method is required but was not set');
if (params != null) {
__result['params'] = params;
}
__result['jsonrpc'] =
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;
@ -4225,8 +4249,55 @@ class ResourceOperationKind {
bool operator ==(o) => o is ResourceOperationKind && o._value == _value;
}
class ResponseError<D> {
ResponseError(this.code, this.message, this.data) {
if (code == null) {
throw 'code is required but was not provided';
}
if (message == null) {
throw 'message is required but was not provided';
}
}
factory ResponseError.fromJson(Map<String, dynamic> json) {
final code = json['code'];
final message = json['message'];
final data = json['data'];
return new ResponseError<D>(code, message, data);
}
/// A number indicating the error type that occurred.
final num code;
/// A Primitive or Structured value that contains
/// additional information about the error. Can be
/// omitted.
final D data;
/// A string providing a short description of the error.
final String message;
Map<String, dynamic> toJson() {
Map<String, dynamic> __result = {};
__result['code'] = code ?? (throw 'code is required but was not set');
__result['message'] =
message ?? (throw 'message is required but was not set');
if (data != null) {
__result['data'] = data;
}
return __result;
}
static bool canParse(Object obj) {
return obj is Map<String, dynamic> &&
obj.containsKey('code') &&
obj['code'] is num &&
obj.containsKey('message') &&
obj['message'] is String;
}
}
class ResponseMessage implements Message {
ResponseMessage(this.id, this.result, this.jsonrpc) {
ResponseMessage(this.id, this.result, this.error, this.jsonrpc) {
if (jsonrpc == null) {
throw 'jsonrpc is required but was not provided';
}
@ -4238,10 +4309,14 @@ class ResponseMessage implements Message {
? new Either2<num, String>.t2(json['id'])
: (throw '''${json['id']} was not one of (number, string)'''));
final result = json['result'];
final error = json['error'];
final jsonrpc = json['jsonrpc'];
return new ResponseMessage(id, result, jsonrpc);
return new ResponseMessage(id, result, error, jsonrpc);
}
/// The error object in case a request fails.
final ResponseError<dynamic> error;
/// The request id.
final Either2<num, String> id;
final String jsonrpc;
@ -4256,6 +4331,9 @@ class ResponseMessage implements Message {
if (result != null) {
__result['result'] = result;
}
if (error != null) {
__result['error'] = error;
}
__result['jsonrpc'] =
jsonrpc ?? (throw 'jsonrpc is required but was not set');
return __result;

View file

@ -518,11 +518,6 @@ class AnalysisDomainHandler extends AbstractRequestHandler {
options.lint = newOptions.generateLints;
});
}
if (newOptions.enableSuperMixins != null) {
updaters.add((engine.AnalysisOptionsImpl options) {
options.enableSuperMixins = newOptions.enableSuperMixins;
});
}
server.updateOptions(updaters);
return new AnalysisUpdateOptionsResult().toResponse(request.id);
}

View file

@ -388,7 +388,6 @@ class ContextsPage extends DiagnosticPageWithNav {
b.write(
writeOption('Analyze function bodies', options.analyzeFunctionBodies));
b.write(writeOption('Enable super mixins', options.enableSuperMixins));
b.write(writeOption('Generate dart2js hints', options.dart2jsHint));
b.write(writeOption(
'Generate errors in implicit files', options.generateImplicitErrors));

View file

@ -229,12 +229,18 @@ InstanceCreationExpression identifyNewExpression(AstNode node) {
/**
* Attempt to find and return the closest expression that encloses the [node]
* and is a Flutter `Widget`. Return `null` if nothing found.
* and is an independent Flutter `Widget`. Return `null` if nothing found.
*/
Expression identifyWidgetExpression(AstNode node) {
for (; node != null; node = node.parent) {
if (isWidgetExpression(node)) {
return node;
var parent = node.parent;
if (parent is ArgumentList ||
parent is ListLiteral ||
parent is NamedExpression && parent.expression == node ||
parent is Statement) {
return node;
}
}
if (node is ArgumentList || node is Statement || node is FunctionBody) {
return null;

View file

@ -13,8 +13,10 @@ import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/context/context_root.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult;
import 'package:analyzer/src/generated/sdk.dart';
@ -24,8 +26,6 @@ import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/summary/summary_file_builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/util/glob.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:linter/src/rules.dart';
import 'package:linter/src/rules/avoid_as.dart';
import 'package:path/path.dart' as path;
@ -1807,8 +1807,6 @@ abstract class ContextManagerWithOptionsTest extends ContextManagerTest {
embedded_libs:
"dart:foobar": "../sdk_ext/entry.dart"
analyzer:
language:
enableSuperMixins: true
errors:
unused_local_variable: false
linter:
@ -1823,7 +1821,6 @@ linter:
// Verify options were set.
expect(errorProcessors, hasLength(1));
expect(lints, hasLength(1));
expect(analysisOptions.enableSuperMixins, isTrue);
// Remove options.
deleteOptionsFile();
@ -1832,7 +1829,6 @@ linter:
// Verify defaults restored.
expect(errorProcessors, isEmpty);
expect(lints, isEmpty);
expect(analysisOptions.enableSuperMixins, isFalse);
}
@failingTest
@ -1859,8 +1855,6 @@ test_pack:lib/''');
// Setup analysis options
newFile('$projPath/$optionsFileName', content: r'''
analyzer:
language:
enableSuperMixins: true
errors:
unused_local_variable: false
linter:
@ -1873,7 +1867,6 @@ linter:
await pumpEventQueue();
// Verify options were set.
expect(analysisOptions.enableSuperMixins, isTrue);
expect(errorProcessors, hasLength(2));
expect(lints, hasLength(2));
@ -1882,7 +1875,6 @@ linter:
await pumpEventQueue();
// Verify defaults restored.
expect(analysisOptions.enableSuperMixins, isFalse);
expect(lints, hasLength(1));
expect(lints.first, const TypeMatcher<AvoidAs>());
expect(errorProcessors, hasLength(1));
@ -1903,8 +1895,6 @@ include: other_options.yaml
''');
newFile('$projPath/other_options.yaml', content: r'''
analyzer:
language:
enableSuperMixins: true
errors:
unused_local_variable: false
linter:
@ -1915,7 +1905,6 @@ linter:
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
await pumpEventQueue();
// Verify options were set.
expect(analysisOptions.enableSuperMixins, isTrue);
expect(errorProcessors, hasLength(1));
expect(lints, hasLength(1));
expect(lints[0].name, 'camel_case_types');
@ -1933,8 +1922,6 @@ linter:
String booLibPosixPath = '/my/pkg/boo/lib';
newFile('$booLibPosixPath/other_options.yaml', content: r'''
analyzer:
language:
enableSuperMixins: true
errors:
unused_local_variable: false
linter:
@ -1951,7 +1938,6 @@ include: package:boo/other_options.yaml
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
await pumpEventQueue();
// Verify options were set.
expect(analysisOptions.enableSuperMixins, isTrue);
expect(errorProcessors, hasLength(1));
expect(lints, hasLength(1));
expect(lints[0].name, 'camel_case_types');
@ -2009,8 +1995,6 @@ embedded_libs:
"dart:foobar": "../sdk_ext/entry.dart"
analyzer:
strong-mode: true
language:
enableSuperMixins: true
errors:
missing_return: false
linter:
@ -2026,8 +2010,6 @@ test_pack:lib/''');
analyzer:
exclude:
- 'test/**'
language:
enableSuperMixins: true
errors:
unused_local_variable: false
linter:
@ -2046,12 +2028,8 @@ linter:
// Verify options.
// * from `_embedder.yaml`:
// TODO(brianwilkerson) Figure out what to use in place of 'strongMode' and
// why 'enableSuperMixins' is assumed to come from two different sources.
// TODO(brianwilkerson) Figure out what to use in place of 'strongMode'.
// expect(analysisOptions.strongMode, isTrue);
expect(analysisOptions.enableSuperMixins, isTrue);
// * from analysis options:
expect(analysisOptions.enableSuperMixins, isTrue);
// * verify tests are excluded
expect(

View file

@ -5014,6 +5014,60 @@ class FakeFlutter {\r
}
}
test_flutterWrapWidget_OK_prefixedIdentifier_identifier() async {
addFlutterPackage();
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
return foo./*caret*/bar;
}
''');
_setCaretLocation();
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
return widget(child: foo./*caret*/bar);
}
''');
}
test_flutterWrapWidget_OK_prefixedIdentifier_prefix() async {
addFlutterPackage();
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
return /*caret*/foo.bar;
}
''');
_setCaretLocation();
await assertHasAssist(DartAssistKind.FLUTTER_WRAP_GENERIC, '''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
return /*caret*/widget(child: foo.bar);
}
''');
}
test_flutterWrapWidget_OK_singleLine1() async {
addFlutterPackage();
await resolveTestUnit('''

View file

@ -90,22 +90,7 @@ var w = new Foo();
expect(getWidgetPresentationText(w), isNull);
}
test_identifyWidgetExpression_identifier() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main() {
var text = new Text('abc');
text;
}
''');
{
Expression expression = findNodeAtString("text;");
expect(identifyWidgetExpression(expression), expression);
}
}
test_identifyWidgetExpression_instanceCreation() async {
test_identifyWidgetExpression_node_instanceCreation() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
@ -155,7 +140,7 @@ class MyWidget extends StatelessWidget {
}
}
test_identifyWidgetExpression_invocation() async {
test_identifyWidgetExpression_node_invocation() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
@ -185,7 +170,7 @@ Text createText(String txt) => new Text(txt);
}
}
test_identifyWidgetExpression_namedExpression() async {
test_identifyWidgetExpression_node_namedExpression() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
@ -199,6 +184,50 @@ Text createEmptyText() => new Text('');
expect(identifyWidgetExpression(childExpression), isNull);
}
test_identifyWidgetExpression_node_prefixedIdentifier_identifier() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
foo.bar; // ref
}
''');
SimpleIdentifier bar = findNodeAtString('bar; // ref');
expect(identifyWidgetExpression(bar), bar.parent);
}
test_identifyWidgetExpression_node_prefixedIdentifier_prefix() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
abstract class Foo extends Widget {
Widget bar;
}
main(Foo foo) {
foo.bar; // ref
}
''');
SimpleIdentifier foo = findNodeAtString('foo.bar');
expect(identifyWidgetExpression(foo), foo.parent);
}
test_identifyWidgetExpression_node_simpleIdentifier() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main(Widget widget) {
widget; // ref
}
''');
Expression expression = findNodeAtString('widget; // ref');
expect(identifyWidgetExpression(expression), expression);
}
test_identifyWidgetExpression_null() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
@ -222,6 +251,72 @@ Text createEmptyText() => new Text('');
}
}
test_identifyWidgetExpression_parent_argumentList() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main() {
var text = new Text('abc');
useWidget(text); // ref
}
void useWidget(Widget w) {}
''');
Expression expression = findNodeAtString("text); // ref");
expect(identifyWidgetExpression(expression), expression);
}
test_identifyWidgetExpression_parent_expressionStatement() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main(Widget widget) {
widget; // ref
}
''');
Expression expression = findNodeAtString("widget; // ref");
expect(identifyWidgetExpression(expression), expression);
}
test_identifyWidgetExpression_parent_listLiteral() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main(Widget widget) {
return [widget]; // ref
}
''');
Expression expression = findNodeAtString("widget]; // ref");
expect(identifyWidgetExpression(expression), expression);
}
test_identifyWidgetExpression_parent_namedExpression() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main() {
var text = new Text('abc');
useWidget(child: text); // ref
}
void useWidget({Widget child}) {}
''');
Expression expression = findNodeAtString("text); // ref");
expect(identifyWidgetExpression(expression), expression);
}
test_identifyWidgetExpression_parent_returnStatement() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
main(Widget widget) {
return widget; // ref
}
''');
Expression expression = findNodeAtString("widget; // ref");
expect(identifyWidgetExpression(expression), expression);
}
test_isWidget() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';

View file

@ -0,0 +1,48 @@
// Copyright (c) 2018, 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 'package:test/test.dart';
import '../../../tool/lsp_spec/codegen_dart.dart';
main() {
group('mapType', () {
test('handles basic types', () {
expect(mapType(['string']), equals('String'));
expect(mapType(['boolean']), equals('bool'));
expect(mapType(['any']), equals('dynamic'));
expect(mapType(['object']), equals('dynamic'));
expect(mapType(['int']), equals('int'));
expect(mapType(['num']), equals('num'));
});
test('handles union types', () {
expect(mapType(['string', 'int']), equals('Either2<String, int>'));
expect(mapType(['string | int']), equals('Either2<String, int>'));
});
test('handles arrays', () {
expect(mapType(['string[]']), equals('List<String>'));
expect(mapType(['Array<string>']), equals('List<String>'));
});
test('handles types with args', () {
expect(mapType(['Class<string[]>']), equals('Class<List<String>>'));
expect(mapType(['Array<string | num>']),
equals('List<Either2<String, num>>'));
});
test('handles complex nested types', () {
expect(
mapType([
'Array<string>',
'any[]',
'Response<A>',
'Request<Array<string | num>>'
]),
equals(
'Either4<List<String>, List<dynamic>, Response<A>, Request<List<Either2<String, num>>>>'));
});
});
}

View file

@ -18,7 +18,8 @@ main() {
});
test('returns correct output for union types', () {
final message = new RequestMessage(new Either2.t1(1), "test", "test");
final message =
new RequestMessage(new Either2.t1(1), "test", null, "test");
String output = json.encode(message.toJson());
expect(output, equals('{"id":1,"method":"test","jsonrpc":"test"}'));
});

View file

@ -64,6 +64,48 @@ export interface SomeOptions {
});
});
test('parses an interface with type args', () {
final String input = '''
interface ResponseError<D> {
data?: D;
}
''';
final List<ApiItem> output = extractTypes(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
final Interface interface = output[0];
expect(interface.members, hasLength(1));
final Field field = interface.members.first;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('data'));
expect(field.allowsUndefined, true);
expect(field.allowsNull, false);
expect(field.types, equals(['D']));
});
test('parses an interface with Arrays in Array<T> format', () {
final String input = '''
export interface RequestMessage {
/**
* The method's params.
*/
params?: Array<any> | object;
}
''';
final List<ApiItem> output = extractTypes(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
final Interface interface = output[0];
expect(interface.members, hasLength(1));
final Field field = interface.members.first;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('params'));
expect(field.comment, equals('''The method's params.'''));
expect(field.allowsUndefined, true);
expect(field.allowsNull, false);
expect(field.types, equals(['Array<any>', 'object']));
});
test('flags nullable undefined values', () {
final String input = '''
export interface A {

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:dart_style/dart_style.dart';
import 'package:meta/meta.dart';
import 'typescript.dart';
@ -28,6 +29,10 @@ String generateDartForTypes(List<ApiItem> types) {
return formattedCode.trim() + '\n'; // Ensure a single trailing newline.
}
List<String> _extractTypesFromUnion(String type) {
return type.split('|').map((t) => t.trim()).toList();
}
String _formatCode(String code) {
try {
code = formatter.format(code);
@ -100,12 +105,14 @@ String _makeValidIdentifier(String identifier) {
}
/// Maps a TypeScript type on to a Dart type, including following TypeAliases.
String _mapType(List<String> types) {
@visibleForTesting
String mapType(List<String> types) {
const mapping = <String, String>{
'boolean': 'bool',
'string': 'String',
'number': 'num',
'any': 'dynamic',
'object': 'dynamic',
// Special cases that are hard to parse or anonymous types.
'{ [uri: string]: TextEdit[]; }': 'Map<String, List<TextEdit>>',
'{ language: string; value: string }': 'MarkedStringWithLanguage'
@ -114,21 +121,38 @@ String _mapType(List<String> types) {
throw 'Unions of more than 4 types are not supported.';
}
if (types.length >= 2) {
final typeArgs = types.map((t) => _mapType([t])).join(', ');
final typeArgs = types.map((t) => mapType([t])).join(', ');
return 'Either${types.length}<$typeArgs>';
}
final type = types.first;
if (type.endsWith('[]')) {
return 'List<${_mapType([type.substring(0, type.length - 2)])}>';
return 'List<${mapType([type.substring(0, type.length - 2)])}>';
} else if (type.startsWith('Array<') && type.endsWith('>')) {
return 'List<${mapType([type.substring(6, type.length - 1)])}>';
} else if (type.contains('<')) {
// For types with type args, we need to map the type and each type arg.
final declaredType = _stripTypeArgs(type);
final typeArgs = type
.substring(declaredType.length + 1, type.length - 1)
.split(',')
.map((t) => t.trim());
return '${mapType([
declaredType
])}<${typeArgs.map((t) => mapType([t])).join(', ')}>';
} else if (type.contains('|')) {
// It's possible we ended up with nested unions that the parsing.
// TODO(dantup): This is now partly done during parsing and partly done
// here. Maybe consider removing from typescript.dart and just carrying a
// String through so the logic is all in one place in this function?
return mapType(_extractTypesFromUnion(type));
} else if (_typeAliases.containsKey(type)) {
return mapType([_typeAliases[type].baseType]);
} else if (mapping.containsKey(type)) {
return mapType([mapping[type]]);
} else {
return type;
}
if (_typeAliases.containsKey(type)) {
return _mapType([_typeAliases[type].baseType]);
}
if (mapping.containsKey(type)) {
return _mapType([mapping[type]]);
}
return type;
}
String _rewriteCommentReference(String comment) {
@ -144,6 +168,10 @@ String _rewriteCommentReference(String comment) {
});
}
String _stripTypeArgs(String typeName) => typeName.contains('<')
? typeName.substring(0, typeName.indexOf('<'))
: typeName;
Iterable<String> _wrapLines(List<String> lines, int maxLength) sync* {
lines = lines.map((l) => l.trimRight()).toList();
for (var line in lines) {
@ -170,15 +198,15 @@ void _writeCanParseMethod(IndentableStringBuffer buffer, Interface interface) {
buffer
..writeIndentedln('static bool canParse(Object obj) {')
..indent()
..writeIndentedln('return obj is Map<String, dynamic>');
..writeIndented('return obj is Map<String, dynamic>');
// In order to consider this valid for parsing, all fields that may not be
// undefined must be present and also type check for the correct type.
final requiredFields =
_getAllFields(interface).where((f) => !f.allowsUndefined);
for (var field in requiredFields) {
buffer.write("&& obj.containsKey('${field.name}') && ");
buffer.write(" && obj.containsKey('${field.name}') && ");
_writeTypeCheckCondition(
buffer, "obj['${field.name}']", _mapType(field.types));
buffer, "obj['${field.name}']", mapType(field.types));
}
buffer
..writeln(';')
@ -197,7 +225,7 @@ void _writeConstructor(IndentableStringBuffer buffer, Interface interface) {
return;
}
buffer
..writeIndented('${interface.name}(')
..writeIndented('${_stripTypeArgs(interface.name)}(')
..write(allFields.map((field) => 'this.${field.name}').join(', '))
..write(')');
final fieldsWithValidation =
@ -289,13 +317,13 @@ void _writeField(IndentableStringBuffer buffer, Field field) {
_writeDocCommentsAndAnnotations(buffer, field);
buffer
..writeIndented('final ')
..write(_mapType(field.types))
..write(mapType(field.types))
..writeln(' ${field.name};');
}
void _writeFromJsonCode(
IndentableStringBuffer buffer, List<String> types, String valueCode) {
final type = _mapType(types);
final type = mapType(types);
if (_isLiteral(type)) {
buffer.write("$valueCode");
} else if (_isSpecType(type)) {
@ -316,22 +344,33 @@ void _writeFromJsonCode(
void _writeFromJsonCodeForUnion(
IndentableStringBuffer buffer, List<String> types, String valueCode) {
final unionTypeName = _mapType(types);
final unionTypeName = mapType(types);
// Write a check against each type, eg.:
// x is y ? new Either.tx(x) : (...)
var hasIncompleteCondition = false;
var unclosedParens = 0;
for (var i = 0; i < types.length; i++) {
final dartType = _mapType([types[i]]);
final dartType = mapType([types[i]]);
_writeTypeCheckCondition(buffer, valueCode, dartType);
buffer.write(' ? new $unionTypeName.t${i + 1}(');
_writeFromJsonCode(buffer, [dartType], valueCode); // Call recursively!
buffer.write(') : (');
if (dartType != 'dynamic') {
_writeTypeCheckCondition(buffer, valueCode, dartType);
buffer.write(' ? new $unionTypeName.t${i + 1}(');
_writeFromJsonCode(buffer, [dartType], valueCode); // Call recursively!
buffer.write(') : (');
hasIncompleteCondition = true;
unclosedParens++;
} else {
_writeFromJsonCode(buffer, [dartType], valueCode);
hasIncompleteCondition = false;
}
}
// Fill the final parens with a throw because if we fell through all of the
// cases then the value we had didn't match any of the types in the union.
buffer
.write("throw '''\${$valueCode} was not one of (${types.join(', ')})'''");
buffer.write(')' * types.length);
if (hasIncompleteCondition) {
buffer.write(
"throw '''\${$valueCode} was not one of (${types.join(', ')})'''");
}
buffer.write(')' * unclosedParens);
}
void _writeFromJsonConstructor(
@ -342,7 +381,7 @@ void _writeFromJsonConstructor(
}
buffer
..writeIndentedln(
'factory ${interface.name}.fromJson(Map<String, dynamic> json) {')
'factory ${_stripTypeArgs(interface.name)}.fromJson(Map<String, dynamic> json) {')
..indent();
for (final field in allFields) {
buffer.writeIndented('final ${field.name} = ');
@ -354,7 +393,7 @@ void _writeFromJsonConstructor(
..write(allFields.map((field) => '${field.name}').join(', '))
..writeln(');')
..outdent()
..write('}');
..writeIndented('}');
}
void _writeInterface(IndentableStringBuffer buffer, Interface interface) {
@ -488,12 +527,17 @@ void _writeTypeCheckCondition(
} else if (_isSpecType(dartType)) {
buffer.write('$dartType.canParse($valueCode)');
} else if (_isList(dartType)) {
// TODO(dantup): If we're happy to assume we never have two lists in a union
// we could simplify this to '$valueCode is List'.
buffer.write(
'($valueCode is List && ($valueCode.length == 0 || $valueCode.every((item) => ');
_writeTypeCheckCondition(buffer, 'item', _getListType(dartType));
buffer.write(')))');
final listType = _getListType(dartType);
buffer.write('($valueCode is List');
if (dartType != 'dynamic') {
// TODO(dantup): If we're happy to assume we never have two lists in a union
// we could skip this bit.
buffer
.write(' && ($valueCode.length == 0 || $valueCode.every((item) => ');
_writeTypeCheckCondition(buffer, 'item', listType);
buffer.write('))');
}
buffer.write(')');
} else if (_isUnion(dartType)) {
// To type check a union, we just recursively check against each of its types.
final unionTypes = _getUnionTypes(dartType);
@ -502,7 +546,7 @@ void _writeTypeCheckCondition(
if (i != 0) {
buffer.write(' || ');
}
_writeTypeCheckCondition(buffer, valueCode, _mapType([unionTypes[i]]));
_writeTypeCheckCondition(buffer, valueCode, mapType([unionTypes[i]]));
}
buffer.write(')');
} else {

View file

@ -159,8 +159,8 @@ class Field extends Member {
: super(name, comment);
static List<Field> extractFrom(String interfaceName, String code) {
final RegExp _fieldPattern = new RegExp(
_comment + r'([\w\[\]]+\??)\s*:\s*([\w\[\] \|\{\}\(\):;]+)\s*(?:;|$)');
final RegExp _fieldPattern = new RegExp(_comment +
r'([\w\[\]]+\??)\s*:\s*([\w\[\] \|\{\}\(\)<>:;]+)\s*(?:;|$)');
final fields = _fieldPattern.allMatches(code).where((m) {
// Skip over the indexer in FormattingOptions since we don't need this
@ -220,7 +220,7 @@ class Interface extends ApiItem {
static List<Interface> extractFrom(String code) {
final RegExp _interfacePattern = new RegExp(_comment +
r'(?:export\s+)?(?:interface|class)\s+(\w+)(?:\s+extends\s+([\w, ]+?))?\s*' +
r'(?:export\s+)?(?:interface|class)\s+([\w<>]+)(?:\s+extends\s+([\w, ]+?))?\s*' +
_blockBody);
final interfaces = _interfacePattern.allMatches(code).map((match) {

View file

@ -7,8 +7,9 @@ code is modeled by the [AST][ast].
Generally speaking, an element represents something that is declared in the
code, such as a class, method, or variable. Elements can be explicitly declared,
such as the class defined by a class declaration, or implicitly declared, such
as the default constructor defined for concrete classes that do not have any
explicit constructor declarations.
as the default constructor defined for classes that do not have any explicit
constructor declarations. Elements that are implicitly declared are referred to
as _synthetic_ elements.
There are a few elements that represent entities that are not declared. For
example, there is an element representing a compilation unit (`.dart` file) and
@ -45,7 +46,7 @@ ask the analysis session for the compilation unit representing that file.
```dart
analyzeSingleFile(AnalysisSession session, String path) async {
UnitElementResult result = await session.UnitElementResult(path);
UnitElementResult result = await session.getUnitElement(path);
CompilationUnitElement element = result.element;
}
```

View file

@ -48,11 +48,13 @@ const List<ErrorCode> errorCodeValues = const [
AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE,
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES,
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITHOUT_VALUES,
AnalysisOptionsWarningCode.UNSUPPORTED_VALUE,
AnalysisOptionsWarningCode.SPEC_MODE_REMOVED,
AnalysisOptionsHintCode.DEPRECATED_ANALYSIS_OPTIONS_FILE_NAME,
AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED,
AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED,
AnalysisOptionsHintCode.SUPER_MIXINS_SETTING_DEPRECATED,
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,

View file

@ -48,6 +48,60 @@ class AnalysisOptionsErrorCode extends ErrorCode {
ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
}
class AnalysisOptionsHintCode extends ErrorCode {
/**
* An error code indicating the analysis options file name is deprecated and
* the file should be renamed.
*
* Parameters:
* 0: the uri of the file which should be renamed
*/
static const AnalysisOptionsHintCode DEPRECATED_ANALYSIS_OPTIONS_FILE_NAME =
const AnalysisOptionsHintCode(
'DEPRECATED_ANALYSIS_OPTIONS_FILE_NAME',
"The name of the analysis options file {0} is deprecated;"
" consider renaming it to analysis_options.yaml.");
/**
* An error code indicating that the enablePreviewDart2 setting is deprecated.
*/
static const AnalysisOptionsHintCode PREVIEW_DART_2_SETTING_DEPRECATED =
const AnalysisOptionsHintCode('PREVIEW_DART_2_SETTING_DEPRECATED',
"The 'enablePreviewDart2' setting is deprecated.",
correction: "It is no longer necessary to explicitly enable Dart 2.");
/**
* An error code indicating that strong-mode: true is deprecated.
*/
static const AnalysisOptionsHintCode STRONG_MODE_SETTING_DEPRECATED =
const AnalysisOptionsHintCode('STRONG_MODE_SETTING_DEPRECATED',
"The 'strong-mode: true' setting is deprecated.",
correction:
"It is no longer necessary to explicitly enable strong mode.");
/**
* An error code indicating that the enablePreviewDart2 setting is deprecated.
*/
static const AnalysisOptionsHintCode SUPER_MIXINS_SETTING_DEPRECATED =
const AnalysisOptionsHintCode('SUPER_MIXINS_SETTING_DEPRECATED',
"The 'enableSuperMixins' setting is deprecated.",
correction:
"Support has been added to the language for 'mixin' based mixins.");
/**
* Initialize a newly created hint code to have the given [name].
*/
const AnalysisOptionsHintCode(String name, String message,
{String correction})
: super.temporary(name, message, correction: correction);
@override
ErrorSeverity get errorSeverity => ErrorSeverity.INFO;
@override
ErrorType get type => ErrorType.HINT;
}
/**
* The error codes used for warnings in analysis options files. The convention
* for this class is for the name of the error code to indicate the problem that
@ -86,6 +140,26 @@ class AnalysisOptionsWarningCode extends ErrorCode {
const AnalysisOptionsWarningCode('INCLUDED_FILE_WARNING',
"Warning in the included options file {0}({1}..{2}): {3}");
/**
* An error code indicating an invalid format for an options file section.
*
* Parameters:
* 0: the section name
*/
static const AnalysisOptionsWarningCode INVALID_SECTION_FORMAT =
const AnalysisOptionsWarningCode(
'INVALID_SECTION_FORMAT', "Invalid format for the '{0}' section.");
/**
* An error code indicating that strong-mode: false is has been removed.
*/
static const AnalysisOptionsWarningCode SPEC_MODE_REMOVED =
const AnalysisOptionsWarningCode('SPEC_MODE_REMOVED',
"The option 'strong-mode: false' is no longer supported.",
correction:
"It's recommended to remove the 'strong-mode:' setting (and make "
"your code Dart 2 compliant).");
/**
* An error code indicating that an unrecognized error code is being used to
* specify an error filter.
@ -126,6 +200,20 @@ class AnalysisOptionsWarningCode extends ErrorCode {
"The option '{1}' isn't supported by '{0}'.",
correction: "Try using one of the supported options: {2}.");
/**
* An error code indicating that a plugin is being configured with an
* unsupported option and legal options are provided.
*
* Parameters:
* 0: the plugin name
* 1: the unsupported option key
*/
static const AnalysisOptionsWarningCode UNSUPPORTED_OPTION_WITHOUT_VALUES =
const AnalysisOptionsWarningCode(
'UNSUPPORTED_OPTION_WITHOUT_VALUES',
"The option '{1}' isn't supported by '{0}'.",
);
/**
* An error code indicating that an option entry is being configured with an
* unsupported value.
@ -140,26 +228,6 @@ class AnalysisOptionsWarningCode extends ErrorCode {
'UNSUPPORTED_VALUE', "The value '{1}' isn't supported by '{0}'.",
correction: "Try using one of the supported options: {2}.");
/**
* An error code indicating an invalid format for an options file section.
*
* Parameters:
* 0: the section name
*/
static const AnalysisOptionsWarningCode INVALID_SECTION_FORMAT =
const AnalysisOptionsWarningCode(
'INVALID_SECTION_FORMAT', "Invalid format for the '{0}' section.");
/**
* An error code indicating that strong-mode: false is has been removed.
*/
static const AnalysisOptionsWarningCode SPEC_MODE_REMOVED =
const AnalysisOptionsWarningCode('SPEC_MODE_REMOVED',
"The option 'strong-mode: false' is no longer supported.",
correction:
"It's recommended to remove the 'strong-mode:' setting (and make "
"your code Dart 2 compliant).");
/**
* Initialize a newly created warning code to have the given [name].
*/
@ -173,48 +241,3 @@ class AnalysisOptionsWarningCode extends ErrorCode {
@override
ErrorType get type => ErrorType.STATIC_WARNING;
}
class AnalysisOptionsHintCode extends ErrorCode {
/**
* An error code indicating the analysis options file name is deprecated and
* the file should be renamed.
*
* Parameters:
* 0: the uri of the file which should be renamed
*/
static const AnalysisOptionsHintCode DEPRECATED_ANALYSIS_OPTIONS_FILE_NAME =
const AnalysisOptionsHintCode(
'DEPRECATED_ANALYSIS_OPTIONS_FILE_NAME',
"The name of the analysis options file {0} is deprecated;"
" consider renaming it to analysis_options.yaml.");
/**
* An error code indicating that the enablePreviewDart2 setting is deprecated.
*/
static const AnalysisOptionsHintCode PREVIEW_DART_2_SETTING_DEPRECATED =
const AnalysisOptionsHintCode('PREVIEW_DART_2_SETTING_DEPRECATED',
"The 'enablePreviewDart2' setting is deprecated.",
correction: "It is no longer necessary to explicitly enable Dart 2.");
/**
* An error code indicating that strong-mode: true is deprecated.
*/
static const AnalysisOptionsHintCode STRONG_MODE_SETTING_DEPRECATED =
const AnalysisOptionsHintCode('STRONG_MODE_SETTING_DEPRECATED',
"The 'strong-mode: true' setting is deprecated.",
correction:
"It is no longer necessary to explicitly enable strong mode.");
/**
* Initialize a newly created hint code to have the given [name].
*/
const AnalysisOptionsHintCode(String name, String message,
{String correction})
: super.temporary(name, message, correction: correction);
@override
ErrorSeverity get errorSeverity => ErrorSeverity.INFO;
@override
ErrorType get type => ErrorType.HINT;
}

View file

@ -18,6 +18,7 @@ const String bazelAnalysisOptionsPath =
const String declarationCastsFlag = 'declaration-casts';
const String defineVariableOption = 'D';
const String enableInitializingFormalAccessFlag = 'initializing-formal-access';
@deprecated
const String enableSuperMixinFlag = 'supermixin';
const String flutterAnalysisOptionsPath =
'package:flutter/analysis_options_user.yaml';
@ -42,10 +43,6 @@ void applyAnalysisOptionFlags(AnalysisOptionsImpl options, ArgResults args,
}
}
if (args.wasParsed(enableSuperMixinFlag)) {
options.enableSuperMixins = args[enableSuperMixinFlag];
verbose('$enableSuperMixinFlag = ${options.enableSuperMixins}');
}
if (args.wasParsed(implicitCastsFlag)) {
options.implicitCasts = args[implicitCastsFlag];
verbose('$implicitCastsFlag = ${options.implicitCasts}');
@ -201,11 +198,6 @@ void defineAnalysisArguments(ArgParser parser, {bool hide: true, ddc: false}) {
defaultsTo: false,
negatable: false,
hide: hide || ddc);
parser.addFlag(enableSuperMixinFlag,
help: 'Relax restrictions on mixins (DEP 34).',
defaultsTo: false,
negatable: false,
hide: hide);
if (!ddc) {
parser.addFlag(lintsFlag,
help: 'Show lint results.', defaultsTo: false, negatable: true);

View file

@ -291,7 +291,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
((options is AnalysisOptionsImpl)
? this._options.implicitDynamic != options.implicitDynamic
: false) ||
this._options.enableSuperMixins != options.enableSuperMixins ||
!_samePatchPaths(this._options.patchPaths, options.patchPaths);
this._options.analyzeFunctionBodiesPredicate =
options.analyzeFunctionBodiesPredicate;
@ -300,7 +299,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
this._options.dart2jsHint = options.dart2jsHint;
this._options.enableLazyAssignmentOperators =
options.enableLazyAssignmentOperators;
this._options.enableSuperMixins = options.enableSuperMixins;
this._options.enableTiming = options.enableTiming;
this._options.enabledPluginNames = options.enabledPluginNames;
this._options.errorProcessors = options.errorProcessors;

View file

@ -328,11 +328,7 @@ class LibraryAnalyzer {
// Use the ErrorVerifier to compute errors.
//
ErrorVerifier errorVerifier = new ErrorVerifier(
errorReporter,
_libraryElement,
_typeProvider,
_inheritance,
_analysisOptions.enableSuperMixins);
errorReporter, _libraryElement, _typeProvider, _inheritance, false);
unit.accept(errorVerifier);
}

View file

@ -745,13 +745,11 @@ class ClassElementImpl extends AbstractClassElementImpl
@override
bool get isValidMixin {
if (!context.analysisOptions.enableSuperMixins) {
if (hasReferenceToSuper) {
return false;
}
if (!supertype.isObject) {
return false;
}
if (hasReferenceToSuper) {
return false;
}
if (!supertype.isObject) {
return false;
}
for (ConstructorElement constructor in constructors) {
if (!constructor.isSynthetic && !constructor.isFactory) {

View file

@ -1856,16 +1856,6 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
}
}
if (forSuperInvocation) {
bool inOldStyleSuperMixin = inMixin &&
type.superclass != null &&
!type.superclass.isObject &&
element.context.analysisOptions.enableSuperMixins;
if (inOldStyleSuperMixin) {
acceptAbstract = true;
}
}
if (!inMixin || acceptAbstract) {
var mixins = type.mixins;
startMixinIndex ??= mixins.length;

View file

@ -135,14 +135,9 @@ class ParserErrorCode extends ErrorCode {
* 0: the label that was duplicated
*/
static const ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT =
const ParserErrorCode('DUPLICATE_LABEL_IN_SWITCH_STATEMENT',
"The label '{0}' was already used in this switch statement.",
correction: "Try choosing a different name for this label.");
_DUPLICATE_LABEL_IN_SWITCH_STATEMENT;
static const ParserErrorCode DUPLICATE_DEFERRED = const ParserErrorCode(
'DUPLICATE_DEFERRED',
"An import directive can only have one 'deferred' keyword.",
correction: "Try removing all but one 'deferred' keyword.");
static const ParserErrorCode DUPLICATE_DEFERRED = _DUPLICATE_DEFERRED;
/**
* Parameters:
@ -150,18 +145,13 @@ class ParserErrorCode extends ErrorCode {
*/
static const ParserErrorCode DUPLICATED_MODIFIER = _DUPLICATED_MODIFIER;
static const ParserErrorCode DUPLICATE_PREFIX = const ParserErrorCode(
'DUPLICATE_PREFIX',
"An import directive can only have one prefix ('as' clause).",
correction: "Try removing all but one prefix.");
static const ParserErrorCode DUPLICATE_PREFIX = _DUPLICATE_PREFIX;
static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode(
'EMPTY_ENUM_BODY', "An enum must declare at least one constant name.",
correction: "Try declaring a constant.");
static const ParserErrorCode ENUM_IN_CLASS = const ParserErrorCode(
'ENUM_IN_CLASS', "Enums can't be declared inside classes.",
correction: "Try moving the enum to the top-level.");
static const ParserErrorCode ENUM_IN_CLASS = _ENUM_IN_CLASS;
static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND =
_EQUALITY_CANNOT_BE_EQUALITY_OPERAND;
@ -201,10 +191,7 @@ class ParserErrorCode extends ErrorCode {
const ParserErrorCode('EXPECTED_TYPE_NAME', "Expected a type name.");
static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
const ParserErrorCode('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
"Export directives must preceed part directives.",
correction:
"Try moving the export directives before the part directives.");
_EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE;
static const ParserErrorCode EXTERNAL_AFTER_CONST = _EXTERNAL_AFTER_CONST;
@ -245,18 +232,12 @@ class ParserErrorCode extends ErrorCode {
correction: "Try removing the body of the setter, or "
"removing the keyword 'external'.");
static const ParserErrorCode EXTERNAL_TYPEDEF = const ParserErrorCode(
'EXTERNAL_TYPEDEF', "Typedefs can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
static const ParserErrorCode EXTERNAL_TYPEDEF = _EXTERNAL_TYPEDEF;
static const ParserErrorCode EXTRANEOUS_MODIFIER = const ParserErrorCode(
'EXTRANEOUS_MODIFIER', "Can't have modifier '{0}' here.",
correction: "Try removing '{0}'.");
static const ParserErrorCode EXTRANEOUS_MODIFIER = _EXTRANEOUS_MODIFIER;
static const ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION =
const ParserErrorCode('FACTORY_TOP_LEVEL_DECLARATION',
"Top-level declarations can't be declared to be 'factory'.",
correction: "Try removing the keyword 'factory'.");
_FACTORY_TOP_LEVEL_DECLARATION;
static const ParserErrorCode FACTORY_WITH_INITIALIZERS = const ParserErrorCode(
'FACTORY_WITH_INITIALIZERS',
@ -271,15 +252,9 @@ class ParserErrorCode extends ErrorCode {
correction: "Try adding a body to the constructor.");
static const ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR =
const ParserErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR',
"Field formal parameters can only be used in a constructor.",
correction:
"Try replacing the field formal parameter with a normal parameter.");
_FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR;
static const ParserErrorCode FINAL_AND_COVARIANT = const ParserErrorCode(
'FINAL_AND_COVARIANT',
"Members can't be declared to be both 'final' and 'covariant'.",
correction: "Try removing either the 'final' or 'covariant' keyword.");
static const ParserErrorCode FINAL_AND_COVARIANT = _FINAL_AND_COVARIANT;
static const ParserErrorCode FINAL_AND_VAR = const ParserErrorCode(
'FINAL_AND_VAR',

View file

@ -78,6 +78,16 @@ final fastaAnalyzerErrorCodes = <ErrorCode>[
_DEFERRED_AFTER_PREFIX,
_DIRECTIVE_AFTER_DECLARATION,
_DUPLICATED_MODIFIER,
_DUPLICATE_DEFERRED,
_DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
_DUPLICATE_PREFIX,
_ENUM_IN_CLASS,
_EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
_EXTERNAL_TYPEDEF,
_EXTRANEOUS_MODIFIER,
_FACTORY_TOP_LEVEL_DECLARATION,
_FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
_FINAL_AND_COVARIANT,
];
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@ -181,6 +191,25 @@ const ParserErrorCode _DUPLICATED_MODIFIER = const ParserErrorCode(
'DUPLICATED_MODIFIER', r"The modifier '#lexeme' was already specified.",
correction: "Try removing all but one occurance of the modifier.");
const ParserErrorCode _DUPLICATE_DEFERRED = const ParserErrorCode(
'DUPLICATE_DEFERRED',
r"An import directive can only have one 'deferred' keyword.",
correction: "Try removing all but one 'deferred' keyword.");
const ParserErrorCode _DUPLICATE_LABEL_IN_SWITCH_STATEMENT =
const ParserErrorCode('DUPLICATE_LABEL_IN_SWITCH_STATEMENT',
r"The label '#name' was already used in this switch statement.",
correction: "Try choosing a different name for this label.");
const ParserErrorCode _DUPLICATE_PREFIX = const ParserErrorCode(
'DUPLICATE_PREFIX',
r"An import directive can only have one prefix ('as' clause).",
correction: "Try removing all but one prefix.");
const ParserErrorCode _ENUM_IN_CLASS = const ParserErrorCode(
'ENUM_IN_CLASS', r"Enums can't be declared inside classes.",
correction: "Try moving the enum to the top-level.");
const ParserErrorCode _EQUALITY_CANNOT_BE_EQUALITY_OPERAND = const ParserErrorCode(
'EQUALITY_CANNOT_BE_EQUALITY_OPERAND',
r"An equality expression can't be an operand of another equality expression.",
@ -189,6 +218,12 @@ const ParserErrorCode _EQUALITY_CANNOT_BE_EQUALITY_OPERAND = const ParserErrorCo
const ParserErrorCode _EXPECTED_INSTEAD = const ParserErrorCode(
'EXPECTED_INSTEAD', r"Expected '#string' instead of this.");
const ParserErrorCode _EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
const ParserErrorCode('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
r"Export directives must preceed part directives.",
correction:
"Try moving the export directives before the part directives.");
const ParserErrorCode _EXTERNAL_AFTER_CONST = const ParserErrorCode(
'EXTERNAL_AFTER_CONST',
r"The modifier 'external' should be before the modifier 'const'.",
@ -220,6 +255,29 @@ const ParserErrorCode _EXTERNAL_METHOD_WITH_BODY = const ParserErrorCode(
'EXTERNAL_METHOD_WITH_BODY',
r"An external or native method can't have a body.");
const ParserErrorCode _EXTERNAL_TYPEDEF = const ParserErrorCode(
'EXTERNAL_TYPEDEF', r"Typedefs can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
const ParserErrorCode _EXTRANEOUS_MODIFIER = const ParserErrorCode(
'EXTRANEOUS_MODIFIER', r"Can't have modifier '#lexeme' here.",
correction: "Try removing '#lexeme'.");
const ParserErrorCode _FACTORY_TOP_LEVEL_DECLARATION = const ParserErrorCode(
'FACTORY_TOP_LEVEL_DECLARATION',
r"Top-level declarations can't be declared to be 'factory'.",
correction: "Try removing the keyword 'factory'.");
const ParserErrorCode _FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR =
const ParserErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR',
r"Field formal parameters can only be used in a constructor.",
correction: "Try removing 'this.'.");
const ParserErrorCode _FINAL_AND_COVARIANT = const ParserErrorCode(
'FINAL_AND_COVARIANT',
r"Members can't be declared to be both 'final' and 'covariant'.",
correction: "Try removing either the 'final' or 'covariant' keyword.");
const ParserErrorCode _ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE =
const ParserErrorCode('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE',
r"Illegal assignment to non-assignable expression.");

View file

@ -68,13 +68,6 @@ class FastaErrorReporter {
errorReporter?.reportErrorForOffset(
ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, offset, length);
return;
case "DUPLICATE_LABEL_IN_SWITCH_STATEMENT":
errorReporter?.reportErrorForOffset(
ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
offset,
length,
[arguments['name']]);
return;
case "LABEL_UNDEFINED":
errorReporter?.reportErrorForOffset(
CompileTimeErrorCode.LABEL_UNDEFINED,
@ -82,22 +75,10 @@ class FastaErrorReporter {
length,
[arguments['name']]);
return;
case "DUPLICATE_DEFERRED":
errorReporter?.reportErrorForOffset(
ParserErrorCode.DUPLICATE_DEFERRED, offset, length);
return;
case "DUPLICATE_PREFIX":
errorReporter?.reportErrorForOffset(
ParserErrorCode.DUPLICATE_PREFIX, offset, length);
return;
case "EMPTY_ENUM_BODY":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EMPTY_ENUM_BODY, offset, length);
return;
case "ENUM_IN_CLASS":
errorReporter?.reportErrorForOffset(
ParserErrorCode.ENUM_IN_CLASS, offset, length);
return;
case "EXPECTED_CLASS_MEMBER":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXPECTED_CLASS_MEMBER, offset, length);
@ -118,44 +99,16 @@ class FastaErrorReporter {
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXPECTED_TYPE_NAME, offset, length);
return;
case "EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
offset,
length);
return;
case "EXTERNAL_CONSTRUCTOR_WITH_BODY":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, offset, length);
return;
case "EXTERNAL_TYPEDEF":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXTERNAL_TYPEDEF, offset, length);
return;
case "EXTRANEOUS_MODIFIER":
errorReporter?.reportErrorForOffset(
ParserErrorCode.EXTRANEOUS_MODIFIER, offset, length, [lexeme()]);
return;
case "FACTORY_TOP_LEVEL_DECLARATION":
errorReporter?.reportErrorForOffset(
ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, offset, length);
return;
case "FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR":
errorReporter?.reportErrorForOffset(
ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
offset,
length);
return;
case "FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR":
errorReporter?.reportErrorForOffset(
CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
offset,
length);
return;
case "FINAL_AND_COVARIANT":
errorReporter?.reportErrorForOffset(
ParserErrorCode.FINAL_AND_COVARIANT, offset, length);
return;
case "FINAL_AND_VAR":
errorReporter?.reportErrorForOffset(
ParserErrorCode.FINAL_AND_VAR, offset, length);

View file

@ -21,10 +21,12 @@ import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/timestamped_data.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/plugin/engine_plugin.dart';
import 'package:analyzer/src/plugin/resolver_provider.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:analyzer/src/task/api/dart.dart';
import 'package:analyzer/src/task/api/model.dart';
import 'package:analyzer/src/task/dart.dart';
@ -33,8 +35,6 @@ import 'package:analyzer/src/task/html.dart';
import 'package:analyzer/src/task/manager.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/task/yaml.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:analyzer/src/generated/timestamped_data.dart';
import 'package:front_end/src/fasta/scanner/token.dart';
import 'package:html/dom.dart' show Document;
import 'package:path/path.dart' as pathos;
@ -105,8 +105,7 @@ abstract class AnalysisContext {
/**
* Return the set of analysis options controlling the behavior of this
* context. Clients should not modify the returned set of options. The options
* should only be set by invoking the method [setAnalysisOptions].
* context. Clients should not modify the returned set of options.
*/
AnalysisOptions get analysisOptions;
@ -1226,6 +1225,7 @@ abstract class AnalysisOptions {
* Return `true` if mixins are allowed to inherit from types other than
* Object, and are allowed to reference `super`.
*/
@deprecated
bool get enableSuperMixins;
/**
@ -1415,9 +1415,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
@override
bool enableLazyAssignmentOperators = false;
@override
bool enableSuperMixins = false;
@override
bool enableTiming = false;
@ -1472,7 +1469,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
@override
bool disableCacheFlushing = false;
// A no-op setter.
/**
* A flag indicating whether implicit casts are allowed in [strongMode]
* (they are always allowed in Dart 1.0 mode).
@ -1493,6 +1489,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
*/
bool implicitDynamic = true;
// A no-op setter.
/**
* Return `true` to enable mixin declarations.
* https://github.com/dart-lang/language/issues/12
@ -1514,7 +1511,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
dart2jsHint = options.dart2jsHint;
enabledPluginNames = options.enabledPluginNames;
enableLazyAssignmentOperators = options.enableLazyAssignmentOperators;
enableSuperMixins = options.enableSuperMixins;
enableTiming = options.enableTiming;
errorProcessors = options.errorProcessors;
excludePatterns = options.excludePatterns;
@ -1610,6 +1606,15 @@ class AnalysisOptionsImpl implements AnalysisOptions {
@deprecated
void set enableInitializingFormalAccess(bool enable) {}
@override
@deprecated
bool get enableSuperMixins => false;
@deprecated
void set enableSuperMixins(bool enable) {
// Ignored.
}
@deprecated
@override
bool get enableUriInPartOf => true;
@ -1664,7 +1669,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
// Append boolean flags.
buffer.addBool(declarationCasts);
buffer.addBool(enableLazyAssignmentOperators);
buffer.addBool(enableSuperMixins);
buffer.addBool(implicitCasts);
buffer.addBool(implicitDynamic);
buffer.addBool(strongModeHints);
@ -1731,7 +1735,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
disableCacheFlushing = false;
enabledPluginNames = const <String>[];
enableLazyAssignmentOperators = false;
enableSuperMixins = false;
enableTiming = false;
_errorProcessors = null;
_excludePatterns = null;
@ -1752,7 +1755,6 @@ class AnalysisOptionsImpl implements AnalysisOptions {
@override
void setCrossContextOptionsFrom(AnalysisOptions options) {
enableLazyAssignmentOperators = options.enableLazyAssignmentOperators;
enableSuperMixins = options.enableSuperMixins;
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
}

View file

@ -267,12 +267,6 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
*/
List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT;
/**
* If `true`, mixins are allowed to inherit from types other than Object, and
* are allowed to reference `super`.
*/
final bool enableSuperMixins;
final _UninstantiatedBoundChecker _uninstantiatedBoundChecker;
/// Setting this flag to `true` disables the check for conflicting generics.
@ -287,7 +281,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
* Initialize a newly created error verifier.
*/
ErrorVerifier(ErrorReporter errorReporter, this._currentLibrary,
this._typeProvider, this._inheritanceManager, this.enableSuperMixins,
this._typeProvider, this._inheritanceManager, bool enableSuperMixins,
{this.disableConflictingGenericsCheck: false})
: _errorReporter = errorReporter,
_uninstantiatedBoundChecker =
@ -308,6 +302,13 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
_options = _currentLibrary.context.analysisOptions;
}
/**
* If `true`, mixins are allowed to inherit from types other than Object, and
* are allowed to reference `super`.
*/
@deprecated
bool get enableSuperMixins => false;
ClassElement get enclosingClass => _enclosingClass;
/**
@ -1920,8 +1921,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
mixinName, mixinElement)) {
problemReported = true;
}
if (!enableSuperMixins &&
_checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
if (_checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
problemReported = true;
}
if (_checkForMixinReferencesSuper(mixinName, mixinElement)) {
@ -4102,7 +4102,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
*/
bool _checkForMixinReferencesSuper(
TypeName mixinName, ClassElement mixinElement) {
if (!enableSuperMixins && mixinElement.hasReferenceToSuper) {
if (mixinElement.hasReferenceToSuper) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.MIXIN_REFERENCES_SUPER,
mixinName,

View file

@ -5577,11 +5577,7 @@ class VerifyUnitTask extends SourceBasedAnalysisTask {
// Use the ErrorVerifier to compute errors.
//
ErrorVerifier errorVerifier = new ErrorVerifier(
errorReporter,
libraryElement,
typeProvider,
inheritanceManager,
context.analysisOptions.enableSuperMixins,
errorReporter, libraryElement, typeProvider, inheritanceManager, false,
disableConflictingGenericsCheck: true);
unit.accept(errorVerifier);
//

View file

@ -73,20 +73,18 @@ class AnalyzerOptions {
exclude,
language,
plugins,
strong_mode
strong_mode,
];
/// Supported `analyzer` strong-mode options.
static const List<String> strongModeOptions = const [
declarationCasts, // deprecated
implicitCasts,
implicitDynamic
implicitDynamic,
];
/// Supported `analyzer` language options.
static const List<String> languageOptions = const [
enableSuperMixins,
];
static const List<String> languageOptions = const [];
}
/// Validates `analyzer` options.
@ -118,16 +116,21 @@ class ErrorBuilder {
/// Create a builder for the given [supportedOptions].
ErrorBuilder(List<String> supportedOptions) {
assert(supportedOptions != null && !supportedOptions.isEmpty);
if (supportedOptions.length > 1) {
proposal = StringUtilities.printListOfQuotedNames(supportedOptions);
code = pluralProposalCode;
} else {
assert(supportedOptions != null);
if (supportedOptions.isEmpty) {
code = noProposalCode;
} else if (supportedOptions.length == 1) {
proposal = "'${supportedOptions.join()}'";
code = singularProposalCode;
} else {
proposal = StringUtilities.printListOfQuotedNames(supportedOptions);
code = pluralProposalCode;
}
}
AnalysisOptionsWarningCode get noProposalCode =>
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITHOUT_VALUES;
AnalysisOptionsWarningCode get pluralProposalCode =>
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES;
@ -136,8 +139,12 @@ class ErrorBuilder {
/// Report an unsupported [node] value, defined in the given [scopeName].
void reportError(ErrorReporter reporter, String scopeName, YamlNode node) {
reporter
.reportErrorForSpan(code, node.span, [scopeName, node.value, proposal]);
if (proposal != null) {
reporter.reportErrorForSpan(
code, node.span, [scopeName, node.value, proposal]);
} else {
reporter.reportErrorForSpan(code, node.span, [scopeName, node.value]);
}
}
}
@ -381,6 +388,10 @@ class LanguageOptionValidator extends OptionsValidator {
reporter.reportErrorForSpan(
AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED,
k.span);
} else if (AnalyzerOptions.enableSuperMixins == key) {
reporter.reportErrorForSpan(
AnalysisOptionsHintCode.SUPER_MIXINS_SETTING_DEPRECATED,
k.span);
} else if (!AnalyzerOptions.languageOptions.contains(key)) {
builder.reportError(reporter, AnalyzerOptions.language, k);
} else {
@ -626,9 +637,7 @@ class _OptionsProcessor {
AnalysisOptionsImpl options, Object feature, Object value) {
bool boolValue = toBool(value);
if (boolValue != null) {
if (feature == AnalyzerOptions.enableSuperMixins) {
options.enableSuperMixins = boolValue;
}
// Currently no supported language options.
}
}

View file

@ -53,12 +53,6 @@ class CompileTimeErrorCodeTest_Driver extends CompileTimeErrorCodeTestBase {
return super.test_invalidIdentifierInAsync_yield();
}
@override
@failingTest
test_mixinInference_noMatchingClass_typeParametersSupplied() {
return super.test_mixinInference_noMatchingClass_typeParametersSupplied();
}
@override
@failingTest
test_mixinOfNonClass() {

View file

@ -60,18 +60,6 @@ class CompileTimeErrorCodeTest extends CompileTimeErrorCodeTestBase {
return super.test_invalidIdentifierInAsync_yield();
}
@override
@failingTest
test_mixinInference_noMatchingClass_typeParametersSupplied() {
return super.test_mixinInference_noMatchingClass_typeParametersSupplied();
}
@override
@failingTest // Does not work with old task model
test_mixinInference_recursiveSubtypeCheck() {
return super.test_mixinInference_recursiveSubtypeCheck();
}
@override
@failingTest // Does not work with old task model
test_mixinInference_recursiveSubtypeCheck_new_syntax() {
@ -3887,35 +3875,6 @@ class C = B with a.A;'''
]);
}
test_mixinInference_matchingClass() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C extends A<int> with M {}
''');
await computeAnalysisResult(source);
assertNoErrors(source);
}
test_mixinInference_matchingClass_inPreviousMixin() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M1 implements A<B> {}
class M2<T> extends A<T> {}
class C extends Object with M1, M2 {}
''');
await computeAnalysisResult(source);
assertNoErrors(source);
}
test_mixinInference_matchingClass_inPreviousMixin_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -3939,36 +3898,6 @@ class C extends A<int> with M {}
assertNoErrors(source);
}
test_mixinInference_noMatchingClass() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C extends Object with M {}
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS]);
}
test_mixinInference_noMatchingClass_namedMixinApplication() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C = Object with M;
''');
await computeAnalysisResult(source);
assertErrors(
source, [CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS]);
}
test_mixinInference_noMatchingClass_namedMixinApplication_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -3993,20 +3922,6 @@ class C extends Object with M {}
[CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE]);
}
test_mixinInference_noMatchingClass_noSuperclassConstraint() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> {}
class C extends Object with M {}
''');
await computeAnalysisResult(source);
assertNoErrors(source);
}
test_mixinInference_noMatchingClass_noSuperclassConstraint_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -4018,21 +3933,6 @@ class C extends Object with M {}
assertNoErrors(source);
}
test_mixinInference_noMatchingClass_typeParametersSupplied() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C extends Object with M<int> {}
''');
await computeAnalysisResult(source);
assertErrors(source,
[CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE]);
}
test_mixinInference_noMatchingClass_typeParametersSupplied_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -4045,44 +3945,6 @@ class C extends Object with M<int> {}
[CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE]);
}
test_mixinInference_recursiveSubtypeCheck() async {
// See dartbug.com/32353 for a detailed explanation.
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
class ioDirectory implements ioFileSystemEntity {}
class ioFileSystemEntity {}
abstract class _LocalDirectory
extends _LocalFileSystemEntity<_LocalDirectory, ioDirectory>
with ForwardingDirectory, DirectoryAddOnsMixin {}
abstract class _LocalFileSystemEntity<T extends FileSystemEntity,
D extends ioFileSystemEntity> extends ForwardingFileSystemEntity<T, D> {}
abstract class FileSystemEntity implements ioFileSystemEntity {}
abstract class ForwardingFileSystemEntity<T extends FileSystemEntity,
D extends ioFileSystemEntity> implements FileSystemEntity {}
abstract class ForwardingDirectory<T extends Directory>
extends ForwardingFileSystemEntity<T, ioDirectory>
implements Directory {}
abstract class Directory implements FileSystemEntity, ioDirectory {}
abstract class DirectoryAddOnsMixin implements Directory {}
''');
var analysisResult = await computeAnalysisResult(source);
assertNoErrors(source);
var mixins =
analysisResult.unit.declaredElement.getType('_LocalDirectory').mixins;
expect(mixins[0].toString(), 'ForwardingDirectory<_LocalDirectory>');
}
test_mixinInference_recursiveSubtypeCheck_new_syntax() async {
// See dartbug.com/32353 for a detailed explanation.
Source source = addSource('''

View file

@ -40,7 +40,6 @@ class AnalysisOptionsImplTest {
modifiedOptions.disableCacheFlushing = true;
modifiedOptions.enabledPluginNames = ['somePackage'];
modifiedOptions.enableLazyAssignmentOperators = true;
modifiedOptions.enableSuperMixins = true;
modifiedOptions.enableTiming = true;
modifiedOptions.errorProcessors = [null];
modifiedOptions.excludePatterns = ['a'];
@ -63,7 +62,6 @@ class AnalysisOptionsImplTest {
expect(modifiedOptions.enabledPluginNames, isEmpty);
expect(modifiedOptions.enableLazyAssignmentOperators,
defaultOptions.enableLazyAssignmentOperators);
expect(modifiedOptions.enableSuperMixins, defaultOptions.enableSuperMixins);
expect(modifiedOptions.enableTiming, defaultOptions.enableTiming);
expect(modifiedOptions.errorProcessors, defaultOptions.errorProcessors);
expect(modifiedOptions.excludePatterns, defaultOptions.excludePatterns);

View file

@ -32,36 +32,12 @@ class NonErrorResolverTest extends NonErrorResolverTestBase {
return super.test_constConstructorWithMixinWithField_withoutSuperMixins();
}
@override
@failingTest // Does not work with old task model
test_infer_mixin() {
return super.test_infer_mixin();
}
@override
@failingTest // Does not work with old task model
test_infer_mixin_multiplyConstrained() {
return super.test_infer_mixin_multiplyConstrained();
}
@override
@failingTest // Does not work with old task model
test_infer_mixin_new_syntax() {
return super.test_infer_mixin_new_syntax();
}
@override
@failingTest // Does not work with old task model
test_infer_mixin_with_substitution() {
return super.test_infer_mixin_with_substitution();
}
@override
@failingTest // Does not work with old task model
test_infer_mixin_with_substitution_functionType() {
return super.test_infer_mixin_with_substitution_functionType();
}
@override
@failingTest
test_infer_mixin_with_substitution_functionType_new_syntax() {
@ -98,12 +74,6 @@ class NonErrorResolverTest extends NonErrorResolverTestBase {
return super.test_mixinInference_with_actual_mixins();
}
@override
@failingTest // Does not work with old task model
test_mixinInference_with_actual_mixins_supermixins_enabled() {
return super.test_mixinInference_with_actual_mixins_supermixins_enabled();
}
@override
@failingTest
test_null_callOperator() {
@ -1315,19 +1285,6 @@ class A extends Object with M {
verify([source]);
}
test_constConstructorWithMixinWithField_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class M {
}
class A extends Object with M {
const A();
}''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_constConstructorWithMixinWithField_withSuperMixins_new_syntax() async {
Source source = addSource(r'''
mixin M {
@ -2672,58 +2629,6 @@ class C implements A, B {
verify([source]);
}
test_infer_mixin() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C extends A<B> with M {}
''');
TestAnalysisResult analysisResult = await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
CompilationUnit unit = analysisResult.unit;
ClassElement classC =
resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<B>');
}
test_infer_mixin_multiplyConstrained() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
abstract class B<U> {}
class C {}
class D {}
class M<T, U> extends A<T> with B<U> {}
class E extends A<C> implements B<D> {}
class F extends E with M {}
''');
TestAnalysisResult analysisResult = await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
CompilationUnit unit = analysisResult.unit;
ClassElement classF =
resolutionMap.elementDeclaredByCompilationUnit(unit).getType('F');
expect(classF.mixins, hasLength(1));
expect(classF.mixins[0].toString(), 'M<C, D>');
}
test_infer_mixin_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -2744,51 +2649,6 @@ class C extends A<B> with M {}
expect(classC.mixins[0].toString(), 'M<B>');
}
test_infer_mixin_with_substitution() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T> extends A<List<T>> {}
class C extends A<List<B>> with M {}
''');
TestAnalysisResult analysisResult = await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
CompilationUnit unit = analysisResult.unit;
ClassElement classC =
resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<B>');
}
test_infer_mixin_with_substitution_functionType() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
abstract class A<T> {}
class B {}
class M<T, U> extends A<T Function(U)> {}
class C extends A<int Function(String)> with M {}
''');
TestAnalysisResult analysisResult = await computeAnalysisResult(source);
assertNoErrors(source);
CompilationUnit unit = analysisResult.unit;
ClassElement classC =
resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<int, String>');
}
test_infer_mixin_with_substitution_functionType_new_syntax() async {
Source source = addSource('''
abstract class A<T> {}
@ -3953,48 +3813,6 @@ void main () {
expect(xElem.type.toString(), 'int');
}
test_mixinInference_with_actual_mixins_supermixins_enabled() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource('''
class I<X> {}
mixin M0<T> on I<T> {}
mixin M1<T> on I<T> {
T foo() => null;
}
class A = I<int> with M0, M1;
void main () {
var x = new A().foo();
}
''');
var result = await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
var main = result.unit.declarations.last as FunctionDeclaration;
var mainBody = main.functionExpression.body as BlockFunctionBody;
var xDecl = mainBody.block.statements[0] as VariableDeclarationStatement;
var xElem = xDecl.variables.variables[0].declaredElement;
expect(xElem.type.toString(), 'int');
}
test_mixinInheritsFromNotObject_classDeclaration_extends() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource(r'''
class A {}
class B extends A {}
class C extends A with B {}''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_mixinInheritsFromNotObject_classDeclaration_extends_new_syntax() async {
Source source = addSource(r'''
class A {}
@ -4015,32 +3833,6 @@ class C extends Object with B {}''');
verify([source]);
}
test_mixinInheritsFromNotObject_classDeclaration_with() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource(r'''
class A {}
class B extends Object with A {}
class C extends Object with B {}''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_mixinInheritsFromNotObject_typeAlias_extends() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource(r'''
class A {}
class B extends A {}
class C = A with B;''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_mixinInheritsFromNotObject_typeAlias_extends_new_syntax() async {
Source source = addSource(r'''
class A {}
@ -4051,19 +3843,6 @@ class C = A with B;''');
verify([source]);
}
test_mixinInheritsFromNotObject_typeAlias_with() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource(r'''
class A {}
class B extends Object with A {}
class C = Object with B;''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_mixinInheritsFromNotObject_typedef_mixTypeAlias() async {
Source source = addSource(r'''
class A {}
@ -4074,20 +3853,6 @@ class C = Object with B;''');
verify([source]);
}
test_mixinReferencesSuper() async {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.enableSuperMixins = true;
resetWith(options: options);
Source source = addSource(r'''
class A {
toString() => super.toString();
}
class B extends Object with A {}''');
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_mixinReferencesSuper_new_syntax() async {
Source source = addSource(r'''
mixin A {

View file

@ -927,7 +927,56 @@ class SimpleParserTest_Fasta extends FastaParserTestCase
*/
@reflectiveTest
class StatementParserTest_Fasta extends FastaParserTestCase
with StatementParserTestMixin {}
with StatementParserTestMixin {
void test_invalid_typeArg_34850() {
var unit = parseCompilationUnit('foo Future<List<int>> bar() {}', errors: [
expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 4),
expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 4, 6),
expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 22, 3),
]);
// Validate that recovery has properly updated the token stream.
analyzer.Token token = unit.beginToken;
while (!token.isEof) {
expect(token.type, isNot(TokenType.GT_GT));
analyzer.Token next = token.next;
expect(next.previous, token);
token = next;
}
}
void test_partial_typeArg1_34850() {
var unit = parseCompilationUnit('<bar<', errors: [
expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 0),
expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 1, 3),
expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 5, 0),
]);
// Validate that recovery has properly updated the token stream.
analyzer.Token token = unit.beginToken;
while (!token.isEof) {
expect(token.type, isNot(TokenType.GT_GT));
analyzer.Token next = token.next;
expect(next.previous, token);
token = next;
}
}
void test_partial_typeArg2_34850() {
var unit = parseCompilationUnit('foo <bar<', errors: [
expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 3),
expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 3),
expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 9, 0),
]);
// Validate that recovery has properly updated the token stream.
analyzer.Token token = unit.beginToken;
while (!token.isEof) {
expect(token.type, isNot(TokenType.GT_GT));
analyzer.Token next = token.next;
expect(next.previous, token);
token = next;
}
}
}
/**
* Tests of the fasta parser based on [TopLevelParserTestMixin].

View file

@ -4215,15 +4215,11 @@ class Wrong<T> {
}
void test_method_invalidTypeParameters() {
// TODO(jmesserly): ideally we'd be better at parser recovery here.
// It doesn't try to advance past the invalid token `!` to find the
// valid `>`. If it did we'd get less cascading errors, at least for this
// particular example.
createParser('void m<E, hello!>() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(usingFastaParser
? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 15, 1)]
? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 5)]
: [
expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0) /*>*/,
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 0),
@ -6576,7 +6572,7 @@ abstract class ExpressionParserTestMixin implements AbstractParserTestCase {
void test_parseFunctionExpression_functionInPlaceOfTypeName() {
Expression expression = parseExpression('<test(' ', (){});>[0, 1, 2]',
codes: usingFastaParser
? [ParserErrorCode.UNEXPECTED_TOKEN]
? [ParserErrorCode.EXPECTED_TOKEN]
: [
ParserErrorCode.EXPECTED_TOKEN,
ParserErrorCode.MISSING_IDENTIFIER,
@ -10632,7 +10628,10 @@ Map<Symbol, convertStringToSymbolMap(Map<String, dynamic> map) {
result[new Symbol(name)] = value;
});
return result;
}''', errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 24)]);
}''', errors: [
expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 24),
expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 3)
]);
}
}

View file

@ -9,7 +9,6 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -1038,23 +1037,6 @@ class C = Object with A;''');
verify([source]);
}
test_isValidMixin_badSuperclass_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class A extends B {}
class B {}
class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
ClassElement a = unit.getType('A');
expect(a.isValidMixin, isTrue);
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_isValidMixin_constructor() async {
Source source = addSource(r'''
class A {
@ -1075,27 +1057,6 @@ class C = Object with A;''');
verify([source]);
}
test_isValidMixin_constructor_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class A {
A() {}
}
class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
ClassElement a = unit.getType('A');
expect(a.isValidMixin, isFalse);
await computeAnalysisResult(source);
assertErrors(
source,
[CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR],
);
verify([source]);
}
test_isValidMixin_factoryConstructor() async {
Source source = addSource(r'''
class A {
@ -1113,24 +1074,6 @@ class C = Object with A;''');
verify([source]);
}
test_isValidMixin_factoryConstructor_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class A {
factory A() => null;
}
class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
ClassElement a = unit.getType('A');
expect(a.isValidMixin, isTrue);
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_isValidMixin_super() async {
Source source = addSource(r'''
class A {
@ -1150,26 +1093,6 @@ class C = Object with A;''');
verify([source]);
}
test_isValidMixin_super_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class A {
toString() {
return super.toString();
}
}
class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
ClassElement a = unit.getType('A');
expect(a.isValidMixin, isTrue);
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_isValidMixin_valid() async {
Source source = addSource('''
class A {}
@ -1185,22 +1108,6 @@ class C = Object with A;''');
verify([source]);
}
test_isValidMixin_valid_withSuperMixins() async {
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource('''
class A {}
class C = Object with A;''');
LibraryElement library = resolve2(source);
expect(library, isNotNull);
CompilationUnitElement unit = library.definingCompilationUnit;
expect(unit, isNotNull);
ClassElement a = unit.getType('A');
expect(a.isValidMixin, isTrue);
await computeAnalysisResult(source);
assertNoErrors(source);
verify([source]);
}
test_labels_switch() async {
Source source = addSource(r'''
void doSwitch(int target) {

View file

@ -18,71 +18,6 @@ main() {
@reflectiveTest
class StaticTypeWarningCodeTest extends ResolverTestCase {
fail_method_lookup_mixin_of_extends() async {
// See dartbug.com/25605
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
await assertErrorsInUnverifiedCode('''
class A { a() => null; }
class B {}
abstract class M extends A {}
class T = B with M; // Warning: B does not extend A
main() {
new T().a(); // Warning: The method 'a' is not defined for the class 'T'
}
''', [
// TODO(paulberry): when dartbug.com/25614 is fixed, add static warning
// code for "B does not extend A".
StaticTypeWarningCode.UNDEFINED_METHOD
]);
}
fail_method_lookup_mixin_of_implements() async {
// See dartbug.com/25605
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
await assertErrorsInUnverifiedCode('''
class A { a() => null; }
class B {}
abstract class M implements A {}
class T = B with M; // Warning: Missing concrete implementation of 'A.a'
main() {
new T().a(); // Warning: The method 'a' is not defined for the class 'T'
}
''', [
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
StaticTypeWarningCode.UNDEFINED_METHOD
]);
}
fail_method_lookup_mixin_of_mixin() async {
// See dartbug.com/25605
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
await assertErrorsInUnverifiedCode('''
class A {}
class B { b() => null; }
class C {}
class M extends A with B {}
class T = C with M;
main() {
new T().b();
}
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
}
fail_method_lookup_mixin_of_mixin_application() async {
// See dartbug.com/25605
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
await assertErrorsInUnverifiedCode('''
class A { a() => null; }
class B {}
class C {}
class M = A with B;
class T = C with M;
main() {
new T().a();
}
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
}
fail_undefinedEnumConstant() async {
// We need a way to set the parseEnum flag in the parser to true.
await assertErrorsInCode(r'''

View file

@ -5,7 +5,6 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -1293,6 +1292,28 @@ class B = Object with A;''');
verify([source]);
}
test_generalizedVoid_andVoidLhsError() async {
Source source = addSource(r'''
void main() {
void x;
x && true;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_andVoidRhsError() async {
Source source = addSource(r'''
void main() {
void x;
true && x;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_assignmentToVoidParameterOk() async {
// Note: the spec may decide to disallow this, but at this point that seems
// highly unlikely.
@ -1324,28 +1345,6 @@ void main() {
}
}
test_generalizedVoid_negateVoidValueError() async {
Source source = addSource(r'''
void main() {
void x;
!x;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_throwVoidValueError() async {
Source source = addSource(r'''
void main() {
void x;
throw x;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_interpolateVoidValueError() async {
Source source = addSource(r'''
void main() {
@ -1357,6 +1356,17 @@ void main() {
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_negateVoidValueError() async {
Source source = addSource(r'''
void main() {
void x;
!x;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_orVoidLhsError() async {
Source source = addSource(r'''
void main() {
@ -1379,22 +1389,11 @@ void main() {
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_andVoidLhsError() async {
test_generalizedVoid_throwVoidValueError() async {
Source source = addSource(r'''
void main() {
void x;
x && true;
}
''');
await computeAnalysisResult(source);
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
}
test_generalizedVoid_andVoidRhsError() async {
Source source = addSource(r'''
void main() {
void x;
true && x;
throw x;
}
''');
await computeAnalysisResult(source);
@ -3107,22 +3106,6 @@ class C implements I {
verify([source]);
}
test_nonAbstractClassInheritsAbstractMemberTwo_variable_fromMixin_missingBoth() async {
// 26411
resetWith(options: new AnalysisOptionsImpl()..enableSuperMixins = true);
Source source = addSource(r'''
class A {
int f;
}
class B extends A {}
class C extends Object with B {}
''');
await computeAnalysisResult(source);
assertErrors(source,
[StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO]);
verify([source]);
}
test_nonTypeInCatchClause_noElement() async {
Source source = addSource(r'''
f() {

View file

@ -38,7 +38,6 @@ class ArgumentsTest {
'--options=$defaultAnalysisOptionsFilePath',
'--packages=$defaultPackageFilePath',
'--package-root=$defaultPackagesDirectoryPath',
'--supermixin',
];
ArgResults result = parse(provider, parser, args);
ContextBuilderOptions options = createContextBuilderOptions(result);
@ -151,7 +150,7 @@ class ArgumentsTest {
void test_defineAnalysisArguments() {
ArgParser parser = new ArgParser();
defineAnalysisArguments(parser);
expect(parser.options, hasLength(13));
expect(parser.options, hasLength(12));
}
void test_extractDefinedVariables() {

View file

@ -241,28 +241,29 @@ linter:
_expectEqualOptions(options, expected);
}
@failingTest
void test_cmdline_options_override_options_file() {
ArgParser argParser = new ArgParser();
defineAnalysisArguments(argParser);
ArgResults argResults = argParser.parse(['--$enableSuperMixinFlag']);
var builder = new ContextBuilder(resourceProvider, sdkManager, contentCache,
options: createContextBuilderOptions(argResults));
AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
expected.enableSuperMixins = true;
expected.previewDart2 = true;
String path = resourceProvider.convertPath('/some/directory/path');
String filePath =
pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
resourceProvider.newFile(filePath, '''
analyzer:
language:
enablePreviewDart2: true
''');
AnalysisOptions options = builder.getAnalysisOptions(path);
_expectEqualOptions(options, expected);
fail('No clear choice of option to override.');
// ArgParser argParser = new ArgParser();
// defineAnalysisArguments(argParser);
// ArgResults argResults = argParser.parse(['--$enableSuperMixinFlag']);
// var builder = new ContextBuilder(resourceProvider, sdkManager, contentCache,
// options: createContextBuilderOptions(argResults));
//
// AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
// expected.previewDart2 = true;
//
// String path = resourceProvider.convertPath('/some/directory/path');
// String filePath =
// pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
// resourceProvider.newFile(filePath, '''
//analyzer:
// language:
// enablePreviewDart2: true
//''');
//
// AnalysisOptions options = builder.getAnalysisOptions(path);
// _expectEqualOptions(options, expected);
}
void test_convertPackagesToMap_noPackages() {
@ -298,7 +299,6 @@ analyzer:
defaultOptions.dart2jsHint = !defaultOptions.dart2jsHint;
defaultOptions.enableLazyAssignmentOperators =
!defaultOptions.enableLazyAssignmentOperators;
defaultOptions.enableSuperMixins = !defaultOptions.enableSuperMixins;
builderOptions.defaultOptions = defaultOptions;
AnalysisOptions options = builder.createDefaultOptions();
_expectEqualOptions(options, defaultOptions);
@ -712,19 +712,17 @@ linter:
void test_getAnalysisOptions_default_overrides() {
AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
defaultOptions.enableSuperMixins = false;
defaultOptions.enableLazyAssignmentOperators = true;
defaultOptions.implicitDynamic = true;
builderOptions.defaultOptions = defaultOptions;
AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
expected.enableSuperMixins = true;
expected.enableLazyAssignmentOperators = true;
expected.implicitDynamic = false;
String path = resourceProvider.convertPath('/some/directory/path');
String filePath =
pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
resourceProvider.newFile(filePath, '''
analyzer:
language:
enableSuperMixins : true
strong-mode:
implicit-dynamic: false
''');
AnalysisOptions options = builder.getAnalysisOptions(path);
@ -753,10 +751,8 @@ analyzer:
void test_getAnalysisOptions_includes() {
_defineMockLintRules();
AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
defaultOptions.enableSuperMixins = false;
builderOptions.defaultOptions = defaultOptions;
AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
expected.enableSuperMixins = true;
expected.lint = true;
expected.lintRules = <Linter>[
_mockLintRule,
@ -775,9 +771,6 @@ somepkg:../../../mypkgs/somepkg/lib
''');
resourceProvider.newFile(pathContext.join(path, 'bar.yaml'), '''
include: package:somepkg/here.yaml
analyzer:
language:
enableSuperMixins : true
linter:
rules:
- mock_lint_rule2
@ -821,14 +814,14 @@ linter:
void test_getAnalysisOptions_noDefault_overrides() {
AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
expected.enableSuperMixins = true;
expected.implicitDynamic = false;
String path = resourceProvider.convertPath('/some/directory/path');
String filePath =
pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
resourceProvider.newFile(filePath, '''
analyzer:
language:
enableSuperMixins : true
strong-mode:
implicit-dynamic: false
''');
AnalysisOptions options = builder.getAnalysisOptions(path);
@ -926,7 +919,6 @@ linter:
expect(actual.dart2jsHint, expected.dart2jsHint);
expect(actual.enableLazyAssignmentOperators,
expected.enableLazyAssignmentOperators);
expect(actual.enableSuperMixins, expected.enableSuperMixins);
expect(actual.enableTiming, expected.enableTiming);
expect(actual.generateImplicitErrors, expected.generateImplicitErrors);
expect(actual.generateSdkErrors, expected.generateSdkErrors);

View file

@ -758,7 +758,7 @@ foo
Future<List<int>> bar() {}
''', r'''
foo
Future<List<int>> bar() async {}
Future<List<int>> bar(int x) {}
''');
}

View file

@ -75,33 +75,6 @@ abstract class B extends A {
assertElement(findNode.simple('foo; // ref'), findElement.method('foo'));
}
test_abstractSuperMemberReference_noSuchMethod() async {
setAnalysisOptions(enableSuperMixins: true);
addTestFile('''
class A {
void foo();
noSuchMethod(im) {}
}
abstract class B {
void foo();
noSuchMethod(im) {}
}
class C extends A with B {
void bar() {
super.foo(); // ref
}
}
''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE]);
assertElement(
findNode.simple('foo(); // ref'),
findElement.method('foo', of: 'B'),
);
}
test_abstractSuperMemberReference_OK_superHasConcrete_mixinHasAbstract_method() async {
addTestFile('''
class A {
@ -1440,62 +1413,6 @@ abstract class C implements A, B {}
]);
}
test_mixinInference_conflictingSubstitution() async {
setAnalysisOptions(enableSuperMixins: true);
addTestFile('''
abstract class A<T> {}
class M<T> extends A<Map<T, T>> {}
class C extends A<Map<int, String>> with M {}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
]);
}
test_mixinInference_doNotIgnorePreviousExplicitMixins() async {
setAnalysisOptions(enableSuperMixins: true);
addTestFile('''
class A extends Object with B<String>, C {}
class B<T> {}
class C<T> extends B<T> {}
''');
await resolveTestFile();
assertNoTestErrors();
var mixins = result.unit.declaredElement.getType('A').mixins;
expect(mixins[1].toString(), 'C<String>');
}
test_mixinInference_impossibleSubstitution() async {
setAnalysisOptions(enableSuperMixins: true);
addTestFile('''
abstract class A<T> {}
class M<T> extends A<Map<T, T>> {}
class C extends A<List<int>> with M {}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES
]);
}
test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() async {
setAnalysisOptions(enableSuperMixins: true);
addTestFile('''
abstract class A<T> {}
class B {}
class M<T> extends A<T> {}
class C extends Object with M implements A<B> {}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.MIXIN_INFERENCE_NO_MATCHING_CLASS,
CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
]);
}
test_recursiveInterfaceInheritance_extends() async {
addTestFile(r'''
class A extends B {}
@ -1735,25 +1652,4 @@ class ClassTaskResolutionTest extends TaskResolutionTest
test_conflictingGenericInterfaces_viaMixin() {
return super.test_conflictingGenericInterfaces_viaMixin();
}
@failingTest
test_mixinInference_conflictingSubstitution() {
return super.test_mixinInference_conflictingSubstitution();
}
@failingTest
test_mixinInference_doNotIgnorePreviousExplicitMixins() {
return super.test_mixinInference_doNotIgnorePreviousExplicitMixins();
}
@failingTest
test_mixinInference_impossibleSubstitution() {
return super.test_mixinInference_impossibleSubstitution();
}
@failingTest
test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause() {
return super
.test_mixinInference_noMatchingClass_constraintSatisfiedByImplementsClause();
}
}

View file

@ -41,15 +41,6 @@ class DriverResolutionTest extends Object
);
}
@override
void setAnalysisOptions({bool enableSuperMixins}) {
var analysisOptions = new AnalysisOptionsImpl();
if (enableSuperMixins != null) {
analysisOptions.enableSuperMixins = enableSuperMixins;
}
driver.configure(analysisOptions: analysisOptions);
}
void setUp() {
sdk = new MockSdk(resourceProvider: resourceProvider);
logger = new PerformanceLog(logBuffer);

View file

@ -382,8 +382,6 @@ abstract class ResolutionTest implements ResourceProviderMixin {
findElement = new FindElement(result.unit);
}
void setAnalysisOptions({bool enableSuperMixins});
Element _unwrapHandle(Element element) {
if (element is ElementHandle && element is! Member) {
return element.actualElement;

View file

@ -39,15 +39,6 @@ class TaskResolutionTest extends Object
return new TestAnalysisResult(path, content, unit, errors);
}
@override
void setAnalysisOptions({bool enableSuperMixins}) {
var analysisOptions = new AnalysisOptionsImpl();
if (enableSuperMixins != null) {
analysisOptions.enableSuperMixins = enableSuperMixins;
}
analysisContext.analysisOptions = analysisOptions;
}
void setUp() {
sdk = new MockSdk(resourceProvider: resourceProvider);

View file

@ -40,7 +40,7 @@ const default = const Object();
f() {
return <g('')>[0, 1, 2];
}
''', [ParserErrorCode.UNEXPECTED_TOKEN], '''
''', [ParserErrorCode.EXPECTED_TOKEN], '''
f() {
return <g>[0, 1, 2];
}
@ -53,7 +53,7 @@ f() {
f() {
return <test('', (){})>[0, 1, 2];
}
''', [ParserErrorCode.UNEXPECTED_TOKEN], '''
''', [ParserErrorCode.EXPECTED_TOKEN], '''
f() {
return <test>[0, 1, 2];
}

View file

@ -41,7 +41,10 @@ f<T> > () => null;
void test_typeParameters_funct() {
testRecovery('''
f<T extends Function()() => null;
''', [ParserErrorCode.EXPECTED_TOKEN], '''
''', [
ParserErrorCode.EXPECTED_TOKEN,
ParserErrorCode.MISSING_FUNCTION_PARAMETERS
], '''
f<T extends Function()>() => null;
''');
}
@ -49,7 +52,10 @@ f<T extends Function()>() => null;
void test_typeParameters_funct2() {
testRecovery('''
f<T extends Function<X>()() => null;
''', [ParserErrorCode.EXPECTED_TOKEN], '''
''', [
ParserErrorCode.EXPECTED_TOKEN,
ParserErrorCode.MISSING_FUNCTION_PARAMETERS
], '''
f<T extends Function<X>()>() => null;
''');
}
@ -133,7 +139,10 @@ List<int, double> f;
void test_typeParameters_last() {
testRecovery('''
f<T() => null;
''', [ParserErrorCode.EXPECTED_TOKEN], '''
''', [
ParserErrorCode.EXPECTED_TOKEN,
ParserErrorCode.MISSING_FUNCTION_PARAMETERS
], '''
f<T>() => null;
''');
}
@ -141,7 +150,10 @@ f<T>() => null;
void test_typeParameters_outer_last() {
testRecovery('''
f<T extends List<int>() => null;
''', [ParserErrorCode.EXPECTED_TOKEN], '''
''', [
ParserErrorCode.EXPECTED_TOKEN,
ParserErrorCode.MISSING_FUNCTION_PARAMETERS
], '''
f<T extends List<int>>() => null;
''');
}

View file

@ -51,33 +51,6 @@ class ContextConfigurationTest extends AbstractContextTest {
YamlMap parseOptions(String source) =>
optionsProvider.getOptionsFromString(source);
test_configure_bad_options_contents() {
configureContext('''
analyzer:
language:
enableSuperMixins true; # misformatted
''');
expect(analysisOptions.enableSuperMixins, false);
}
test_configure_enableSuperMixins() {
configureContext('''
analyzer:
language:
enableSuperMixins: true
''');
expect(analysisOptions.enableSuperMixins, true);
}
test_configure_enableSuperMixins_badValue() {
configureContext('''
analyzer:
language:
enableSuperMixins: true;
''');
expect(analysisOptions.enableSuperMixins, false);
}
test_configure_error_processors() {
configureContext('''
analyzer:
@ -555,14 +528,6 @@ analyzer:
''', [AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT]);
}
test_analyzer_language_supported() {
validate('''
analyzer:
language:
enableSuperMixins: true
''', []);
}
test_analyzer_language_supports_empty() {
validate('''
analyzer:
@ -575,14 +540,14 @@ analyzer:
analyzer:
language:
unsupported: true
''', [AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE]);
''', [AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITHOUT_VALUES]);
}
test_analyzer_language_unsupported_value() {
validate('''
analyzer:
language:
enableSuperMixins: foo
strong-mode:
implicit-dynamic: foo
''', [AnalysisOptionsWarningCode.UNSUPPORTED_VALUE]);
}

View file

@ -3849,52 +3849,6 @@ class B extends A {
''');
}
@failingTest
test_superMixin_invalidApplication() {
// Failing: https://github.com/dart-lang/sdk/issues/30283
return checkFile(r'''
class A {
int get foo => 3;
}
// This expects a super class which satisfies the contract of A
class B extends A {}
class C {
num get foo => null;
}
// This mixin application doesn't provide a valid superclass for B
class D extends C with /*error:INCONSISTENT_INHERITANCE*/B {}
}
''', superMixins: true);
}
test_superMixinsMakeSuperclassMethodsAbstract() {
return checkFile(r'''
abstract class A {}
abstract class B extends A {}
abstract class ProvidesConcreteAGetter {
A get constraints => null;
}
abstract class ProvidesConcreteBGetter extends ProvidesConcreteAGetter {
@override
B get constraints => null;
}
abstract class ProvidesAbstractBGetter implements ProvidesConcreteBGetter {}
abstract class ProvidesAbstractAGetterMixin extends ProvidesConcreteAGetter {}
abstract class HasConcreteBGetterButMixesinAbstractAGetter
extends ProvidesConcreteBGetter
with ProvidesAbstractAGetterMixin, ProvidesAbstractBGetter {}
''', superMixins: true);
}
test_tearOffTreatedConsistentlyAsStrictArrow() async {
await checkFile(r'''
void foo(void f(String x)) {}

View file

@ -41,8 +41,7 @@ abstract class InferredTypeMixin {
Future<CompilationUnit> checkFile(String content,
{bool declarationCasts: true,
bool implicitCasts: true,
bool implicitDynamic: true,
bool superMixins: false});
bool implicitDynamic: true});
/**
* Add the file, process it (resolve, validate, etc) and return the resolved

View file

@ -16,15 +16,15 @@ import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:source_span/source_span.dart';
import 'package:test/test.dart';
@ -279,8 +279,7 @@ class AbstractStrongTest {
Future<CompilationUnit> check(
{bool declarationCasts: true,
bool implicitCasts: true,
bool implicitDynamic: true,
bool superMixins: false}) async {
bool implicitDynamic: true}) async {
_checkCalled = true;
File mainFile =
@ -292,7 +291,6 @@ class AbstractStrongTest {
analysisOptions.declarationCasts = declarationCasts;
analysisOptions.implicitCasts = implicitCasts;
analysisOptions.implicitDynamic = implicitDynamic;
analysisOptions.enableSuperMixins = superMixins;
var mockSdk = new MockSdk(resourceProvider: _resourceProvider);
mockSdk.context.analysisOptions = analysisOptions;
@ -371,14 +369,12 @@ class AbstractStrongTest {
Future<CompilationUnit> checkFile(String content,
{bool declarationCasts: true,
bool implicitCasts: true,
bool implicitDynamic: true,
bool superMixins: false}) async {
bool implicitDynamic: true}) async {
addFile(content);
return await check(
declarationCasts: declarationCasts,
implicitCasts: implicitCasts,
implicitDynamic: implicitDynamic,
superMixins: superMixins);
implicitDynamic: implicitDynamic);
}
void setUp() {

View file

@ -11,8 +11,10 @@ import 'package:analyzer/file_system/file_system.dart' as file_system;
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
@ -44,8 +46,6 @@ import 'package:analyzer_cli/src/has_context_mixin.dart';
import 'package:analyzer_cli/src/options.dart';
import 'package:analyzer_cli/src/perf_report.dart';
import 'package:analyzer_cli/starter.dart' show CommandLineStarter;
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:linter/src/rules.dart' as linter;
import 'package:meta/meta.dart';
import 'package:package_config/discovery.dart' as pkg_discovery;
@ -834,9 +834,6 @@ class Driver extends Object with HasContextMixin implements CommandLineStarter {
if (newOptions.strongMode != previous.strongMode) {
return false;
}
if (newOptions.enableSuperMixins != previous.enableSuperMixins) {
return false;
}
if (!_equalLists(
newOptions.buildSummaryInputs, previous.buildSummaryInputs)) {
return false;

View file

@ -20,6 +20,8 @@ const _binaryName = 'dartanalyzer';
/// *Visible for testing.*
ExitHandler exitHandler = exit;
T cast<T>(dynamic value) => value as T;
/// Print the given [message] to stderr and exit with the given [exitCode].
void printAndFail(String message, {int exitCode: 15}) {
errorSink.writeln(message);
@ -110,11 +112,6 @@ class CommandLineOptions {
/// Whether to enable parsing via the Fasta parser.
final bool useFastaParser;
/// Whether to enable the Dart 2.0 Preview.
///
/// This flag is deprecated and hard-coded to `true`.
bool get previewDart2 => true;
/// Batch mode (for unit testing)
final bool batchMode;
@ -147,10 +144,10 @@ class CommandLineOptions {
/// Whether implicit dynamic is enabled (mainly for strong mode users)
final bool implicitDynamic;
// TODO(devoncarew): Deprecate and remove this flag.
/// Whether to treat lints as fatal
final bool lintsAreFatal;
// TODO(devoncarew): Deprecate and remove this flag.
/// Emit output in a verbose mode.
final bool verbose;
@ -215,10 +212,6 @@ class CommandLineOptions {
Map<String, String> get definedVariables =>
contextBuilderOptions.declaredVariables;
/// Whether to relax restrictions on mixins (DEP 34).
bool get enableSuperMixins =>
contextBuilderOptions.defaultOptions.enableSuperMixins;
/// The path to a `.packages` configuration file
String get packageConfigPath => contextBuilderOptions.defaultPackageFilePath;
@ -226,6 +219,11 @@ class CommandLineOptions {
String get packageRootPath =>
contextBuilderOptions.defaultPackagesDirectoryPath;
/// Whether to enable the Dart 2.0 Preview.
///
/// This flag is deprecated and hard-coded to `true`.
bool get previewDart2 => true;
/// The source files to analyze
List<String> get sourceFiles => _sourceFiles;
@ -645,5 +643,3 @@ Run "dartanalyzer -h -v" for verbose help output, including less commonly used o
For more information, see https://www.dartlang.org/tools/analyzer.\n''');
}
}
T cast<T>(dynamic value) => value as T;

View file

@ -9,13 +9,11 @@ import 'embedder_test.dart' as embedder_test;
import 'error_test.dart' as error_test;
import 'errors_reported_once_test.dart' as errors_reported_once_test;
import 'errors_upgrade_fails_cli_test.dart' as errors_upgrade_fails_cli_test;
import 'fix/options_test.dart' as fix_options;
import 'options_test.dart' as options_test;
import 'package_prefix_test.dart' as package_prefix_test;
import 'perf_report_test.dart' as perf_report_test;
import 'reporter_test.dart' as reporter_test;
import 'sdk_ext_test.dart' as sdk_ext_test;
import 'super_mixin_test.dart' as super_mixin_test;
import 'strong_mode_test.dart' as strong_mode_test;
main() {
@ -26,12 +24,10 @@ main() {
error_test.main();
errors_reported_once_test.main();
errors_upgrade_fails_cli_test.main();
fix_options.main();
options_test.main();
package_prefix_test.main();
perf_report_test.main();
reporter_test.main();
sdk_ext_test.main();
super_mixin_test.main();
strong_mode_test.main();
}

View file

@ -905,11 +905,6 @@ class OptionsTest extends BaseTest {
expect(outSink.toString(), contains("1 error and 1 warning found."));
}
test_basic_language() async {
await _driveBasic();
expect(analysisOptions.enableSuperMixins, isTrue);
}
test_includeDirective() async {
String testDir = path.join(
testDirectory, 'data', 'options_include_directive_tests_project');

View file

@ -60,7 +60,6 @@ main() {
expect(options.disableHints, isFalse);
expect(options.lints, isFalse);
expect(options.displayVersion, isFalse);
expect(options.enableSuperMixins, isFalse);
expect(options.infosAreFatal, isFalse);
expect(options.ignoreUnrecognizedFlags, isFalse);
expect(options.log, isFalse);
@ -96,12 +95,6 @@ main() {
expect(options.disableCacheFlushing, isTrue);
});
test('enable super mixins', () {
CommandLineOptions options = CommandLineOptions.parse(
['--dart-sdk', '.', '--supermixin', 'foo.dart']);
expect(options.enableSuperMixins, isTrue);
});
test('hintsAreFatal', () {
CommandLineOptions options = CommandLineOptions.parse(
['--dart-sdk', '.', '--fatal-hints', 'foo.dart']);

View file

@ -1,71 +0,0 @@
// Copyright (c) 2015, 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.
library analyzer_cli.test.super_mixin;
import 'dart:io';
import 'package:analyzer_cli/src/ansi.dart' as ansi;
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'utils.dart';
/// End-to-end test for --supermixins.
///
/// Most super mixin tests are in Analyzer, but this verifies the option is
/// working and producing extra errors as expected.
///
/// Generally we don't want a lot of cases here as it requires spinning up a
/// full analysis context.
void main() {
group('--supermixins', () {
StringSink savedOutSink, savedErrorSink;
int savedExitCode;
setUp(() {
ansi.runningTests = true;
savedOutSink = outSink;
savedErrorSink = errorSink;
savedExitCode = exitCode;
outSink = new StringBuffer();
errorSink = new StringBuffer();
});
tearDown(() {
outSink = savedOutSink;
errorSink = savedErrorSink;
exitCode = savedExitCode;
ansi.runningTests = false;
});
test('produces errors when option absent', () async {
var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
await new Driver(isTesting: true).start([testPath]);
expect(exitCode, 3);
var stdout = outSink.toString();
expect(
stdout,
contains(
"error • The class 'C' can't be used as a mixin because it extends a class other than Object"));
expect(
stdout,
contains(
"error • The class 'C' can't be used as a mixin because it references 'super'"));
expect(stdout, contains('2 errors found.'));
expect(errorSink.toString(), '');
});
test('produces no errors when option present', () async {
var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
await new Driver(isTesting: true).start(['--supermixin', testPath]);
expect(exitCode, 0);
var stdout = outSink.toString();
expect(stdout, contains('No issues found'));
});
});
}

View file

@ -1,6 +1,6 @@
name: analyzer_plugin
description: A framework for building plugins for the analysis server.
version: 0.0.1-alpha.4
version: 0.0.1-alpha.5
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin

View file

@ -13,7 +13,6 @@ import 'io/source_information.dart';
import 'js_backend/inferred_data.dart';
import 'js_backend/js_backend.dart';
import 'js_backend/native_data.dart';
import 'js_emitter/sorter.dart';
import 'ssa/ssa.dart';
import 'types/types.dart';
import 'universe/world_builder.dart';
@ -26,8 +25,11 @@ abstract class BackendStrategy {
JClosedWorld createJClosedWorld(
KClosedWorld closedWorld, OutputUnitData outputUnitData);
/// The [Sorter] used for sorting elements in the generated code.
Sorter get sorter;
/// Registers [closedWorld] as the current closed world used by this backend
/// strategy.
///
/// This is used to support serialization after type inference.
void registerJClosedWorld(JClosedWorld closedWorld);
/// Creates the [CodegenWorldBuilder] used by the codegen enqueuer.
CodegenWorldBuilder createCodegenWorldBuilder(

View file

@ -7,6 +7,9 @@ import 'common/tasks.dart' show CompilerTask, Measurer;
import 'common.dart';
import 'elements/entities.dart';
import 'elements/types.dart';
import 'js_model/closure.dart';
import 'js_model/element_map.dart';
import 'serialization/serialization.dart';
abstract class ClosureConversionTask extends CompilerTask {
ClosureConversionTask(Measurer measurer) : super(measurer);
@ -17,6 +20,14 @@ abstract class ClosureConversionTask extends CompilerTask {
/// node to look up, it returns a information about the internal representation
/// of how closure conversion is implemented. T is an ir.Node or Node.
abstract class ClosureData {
/// Deserializes a [ClosureData] object from [source].
factory ClosureData.readFromDataSource(
JsToElementMap elementMap, DataSource source) =
ClosureDataImpl.readFromDataSource;
/// Serializes this [ClosureData] to [sink].
void writeToDataSink(DataSink sink);
/// Look up information about the variables that have been mutated and are
/// used inside the scope of [node].
ScopeInfo getScopeInfo(MemberEntity member);
@ -32,6 +43,14 @@ abstract class ClosureData {
CapturedScope getCapturedScope(MemberEntity entity);
}
/// Enum used for identifying [ScopeInfo] subclasses in serialization.
enum ScopeInfoKind {
scopeInfo,
capturedScope,
capturedLoopScope,
closureRepresentationInfo,
}
/// Class that represents one level of scoping information, whether this scope
/// is a closure or not. This is specifically used to store information
/// about the usage of variables in try or sync blocks, because they need to be
@ -44,6 +63,27 @@ abstract class ClosureData {
class ScopeInfo {
const ScopeInfo();
/// Deserializes a [ScopeInfo] object from [source].
factory ScopeInfo.readFromDataSource(DataSource source) {
ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
switch (kind) {
case ScopeInfoKind.scopeInfo:
return new JsScopeInfo.readFromDataSource(source);
case ScopeInfoKind.capturedScope:
return new JsCapturedScope.readFromDataSource(source);
case ScopeInfoKind.capturedLoopScope:
return new JsCapturedLoopScope.readFromDataSource(source);
case ScopeInfoKind.closureRepresentationInfo:
return new KernelClosureClassInfo.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
/// Serializes this [ScopeInfo] to [sink].
void writeToDataSink(DataSink sink) {
throw new UnsupportedError('${runtimeType}.writeToDataSink');
}
/// Convenience reference pointer to the element representing `this`.
/// If this scope is not in an instance member, it will be null.
Local get thisLocal => null;
@ -81,6 +121,21 @@ class ScopeInfo {
class CapturedScope extends ScopeInfo {
const CapturedScope();
/// Deserializes a [CapturedScope] object from [source].
factory CapturedScope.readFromDataSource(DataSource source) {
ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
switch (kind) {
case ScopeInfoKind.scopeInfo:
case ScopeInfoKind.closureRepresentationInfo:
throw new UnsupportedError('Unexpected CapturedScope kind $kind');
case ScopeInfoKind.capturedScope:
return new JsCapturedScope.readFromDataSource(source);
case ScopeInfoKind.capturedLoopScope:
return new JsCapturedLoopScope.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
/// If true, this closure accesses a variable that was defined in an outside
/// scope and this variable gets modified at some point (sometimes we say that
/// variable has been "captured"). In this situation, access to this variable
@ -113,6 +168,20 @@ class CapturedScope extends ScopeInfo {
class CapturedLoopScope extends CapturedScope {
const CapturedLoopScope();
/// Deserializes a [CapturedLoopScope] object from [source].
factory CapturedLoopScope.readFromDataSource(DataSource source) {
ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
switch (kind) {
case ScopeInfoKind.scopeInfo:
case ScopeInfoKind.closureRepresentationInfo:
case ScopeInfoKind.capturedScope:
throw new UnsupportedError('Unexpected CapturedLoopScope kind $kind');
case ScopeInfoKind.capturedLoopScope:
return new JsCapturedLoopScope.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
/// True if this loop scope declares in the first part of the loop
/// `for (<here>;...;...)` any variables that need to be boxed.
bool get hasBoxedLoopVariables => false;
@ -166,6 +235,21 @@ class CapturedLoopScope extends CapturedScope {
class ClosureRepresentationInfo extends ScopeInfo {
const ClosureRepresentationInfo();
/// Deserializes a [ClosureRepresentationInfo] object from [source].
factory ClosureRepresentationInfo.readFromDataSource(DataSource source) {
ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
switch (kind) {
case ScopeInfoKind.scopeInfo:
case ScopeInfoKind.capturedScope:
case ScopeInfoKind.capturedLoopScope:
throw new UnsupportedError(
'Unexpected ClosureRepresentationInfo kind $kind');
case ScopeInfoKind.closureRepresentationInfo:
return new KernelClosureClassInfo.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
/// The original local function before any translation.
///
/// Will be null for methods.

View file

@ -360,6 +360,7 @@ abstract class Compiler {
void generateJavaScriptCode(
GlobalTypeInferenceResults globalInferenceResults) {
JClosedWorld closedWorld = globalInferenceResults.closedWorld;
backendStrategy.registerJClosedWorld(closedWorld);
FunctionEntity mainFunction = closedWorld.elementEnvironment.mainFunction;
reporter.log('Compiling...');
phase = PHASE_COMPILING;
@ -402,7 +403,7 @@ abstract class Compiler {
enqueuer.createCodegenEnqueuer(closedWorld, globalInferenceResults);
_codegenWorldBuilder = codegenEnqueuer.worldBuilder;
codegenEnqueuer.applyImpact(backend.onCodegenStart(
closedWorld, _codegenWorldBuilder, backendStrategy.sorter));
closedWorld, _codegenWorldBuilder, closedWorld.sorter));
return codegenEnqueuer;
}

View file

@ -22,6 +22,7 @@ import 'elements/types.dart';
import 'elements/entities.dart';
import 'kernel/kelements.dart' show KLocalFunction;
import 'library_loader.dart';
import 'serialization/serialization.dart';
import 'universe/use.dart';
import 'universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
@ -1271,6 +1272,10 @@ class ConstantWorkItem extends WorkItem {
// TODO(sigmund): consider moving here every piece of data used as a result of
// deferred loading (including hunksToLoad, etc).
class OutputUnitData {
/// Tag used for identifying serialized [OutputUnitData] objects in a
/// debugging data stream.
static const String tag = 'output-unit-data';
final bool isProgramSplit;
final OutputUnit mainOutputUnit;
final Map<ClassEntity, OutputUnit> _classToUnit;
@ -1288,6 +1293,7 @@ class OutputUnitData {
this._constantToUnit,
this.outputUnits);
// Creates J-world data from the K-world data.
OutputUnitData.from(
OutputUnitData other,
Map<ClassEntity, OutputUnit> Function(
@ -1305,9 +1311,90 @@ class OutputUnitData {
convertMemberMap(other._memberToUnit, other._localFunctionToUnit),
_classToUnit =
convertClassMap(other._classToUnit, other._localFunctionToUnit),
// Local functions only make sense in the K-world model.
_localFunctionToUnit = const <Local, OutputUnit>{},
_constantToUnit = convertConstantMap(other._constantToUnit);
/// Deserializes an [OutputUnitData] object from [source].
factory OutputUnitData.readFromDataSource(DataSource source) {
source.begin(tag);
bool isProgramSplit = source.readBool();
List<ImportEntity> imports = source.readList(() {
String name = source.readString();
Uri uri = source.readUri();
Uri enclosingLibraryUri = source.readUri();
bool isDeferred = source.readBool();
return new ImportEntity(isDeferred, name, uri, enclosingLibraryUri);
});
List<OutputUnit> outputUnits = source.readList(() {
bool isMainOutput = source.readBool();
String name = source.readString();
Set<ImportEntity> importSet = source.readList(() {
return imports[source.readInt()];
}).toSet();
return new OutputUnit(isMainOutput, name, importSet);
});
OutputUnit mainOutputUnit = outputUnits[source.readInt()];
Map<ClassEntity, OutputUnit> classToUnit = source.readClassMap(() {
return outputUnits[source.readInt()];
});
Map<MemberEntity, OutputUnit> memberToUnit = source.readMemberMap(() {
return outputUnits[source.readInt()];
});
Map<ConstantValue, OutputUnit> constantToUnit = source.readConstantMap(() {
return outputUnits[source.readInt()];
});
source.end(tag);
return new OutputUnitData(
isProgramSplit,
mainOutputUnit,
classToUnit,
memberToUnit,
// Local functions only make sense in the K-world model.
const <Local, OutputUnit>{},
constantToUnit,
outputUnits);
}
/// Serializes this [OutputUnitData] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeBool(isProgramSplit);
Map<ImportEntity, int> importIndex = {};
for (OutputUnit outputUnit in outputUnits) {
for (ImportEntity import in outputUnit._imports) {
importIndex[import] ??= importIndex.length;
}
}
sink.writeList(importIndex.keys, (ImportEntity import) {
sink.writeString(import.name);
sink.writeUri(import.uri);
sink.writeUri(import.enclosingLibraryUri);
sink.writeBool(import.isDeferred);
});
Map<OutputUnit, int> outputUnitIndices = {};
sink.writeList(outputUnits, (OutputUnit outputUnit) {
outputUnitIndices[outputUnit] = outputUnitIndices.length;
sink.writeBool(outputUnit.isMainOutput);
sink.writeString(outputUnit.name);
sink.writeList(outputUnit._imports, (ImportEntity import) {
sink.writeInt(importIndex[import]);
});
});
sink.writeInt(outputUnitIndices[mainOutputUnit]);
sink.writeClassMap(_classToUnit, (OutputUnit outputUnit) {
sink.writeInt(outputUnitIndices[outputUnit]);
});
sink.writeMemberMap(_memberToUnit, (OutputUnit outputUnit) {
sink.writeInt(outputUnitIndices[outputUnit]);
});
sink.writeConstantMap(_constantToUnit, (OutputUnit outputUnit) {
sink.writeInt(outputUnitIndices[outputUnit]);
});
sink.end(tag);
}
/// Returns the [OutputUnit] where [cls] belongs.
OutputUnit outputUnitForClass(ClassEntity cls) {
if (!isProgramSplit) return mainOutputUnit;

View file

@ -7,6 +7,7 @@ library entities;
import 'package:front_end/src/api_unstable/dart2js.dart' show AsyncModifier;
import '../common.dart';
import '../serialization/serialization.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'names.dart';
@ -258,6 +259,10 @@ abstract class Local extends Entity {}
/// The structure of function parameters.
class ParameterStructure {
/// Tag used for identifying serialized [ParameterStructure] objects in a
/// debugging data stream.
static const String tag = 'parameter-structure';
/// The number of required (positional) parameters.
final int requiredParameters;
@ -285,6 +290,28 @@ class ParameterStructure {
type.typeVariables.length);
}
/// Deserializes a [ParameterStructure] object from [source].
factory ParameterStructure.readFromDataSource(DataSource source) {
source.begin(tag);
int requiredParameters = source.readInt();
int positionalParameters = source.readInt();
List<String> namedParameters = source.readStrings();
int typeParameters = source.readInt();
source.end(tag);
return new ParameterStructure(requiredParameters, positionalParameters,
namedParameters, typeParameters);
}
/// Serializes this [ParameterStructure] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeInt(requiredParameters);
sink.writeInt(positionalParameters);
sink.writeStrings(namedParameters);
sink.writeInt(typeParameters);
sink.end(tag);
}
/// The number of optional parameters (positional or named).
int get optionalParameters =>
positionalParameters - requiredParameters + namedParameters.length;

View file

@ -53,12 +53,16 @@ abstract class IndexedLocal extends _Indexed implements Local {
/// Base implementation for an index based map of entities of type [E].
abstract class EntityMapBase<E extends _Indexed> {
int _size = 0;
List<E> _list = <E>[];
/// Returns the [index]th entity in the map.
E getEntity(int index) => _list[index];
/// Returns the number entities in the map.
/// Returns the number of non-null entities in the map.
int get size => _size;
/// Returns the number (null and non-null) entities in the map.
int get length => _list.length;
}
@ -73,8 +77,26 @@ class EntityMap<E extends _Indexed> extends EntityMapBase<E> {
assert(entity._index == null);
entity._index = _list.length;
_list.add(entity);
_size++;
return entity;
}
/// Registers a new [entity] by the given [index].
E0 registerByIndex<E0 extends E>(int index, E0 entity) {
assert(index >= _list.length);
_list.length = index;
return register(entity);
}
/// Calls [f] for each non-null entity.
void forEach<E0 extends E>(void f(E0 entity)) {
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity);
}
}
}
}
/// Base implementation of an index based map of entities of type [E] with a
@ -86,7 +108,7 @@ abstract class EntityDataMapBase<E extends _Indexed, D>
/// Returns the data object stored for the [index]th entity.
D getData(E entity) {
int index = entity._index;
if (index < length && index >= _data.length) {
if (index < _list.length && index >= _data.length) {
throw new StateError(
'Data is in the process of being created for ${_list[index]}.');
}
@ -111,12 +133,39 @@ class EntityDataMap<E extends _Indexed, D> extends EntityDataMapBase<E, D> {
E0 register<E0 extends E, D0 extends D>(E0 entity, D0 data) {
assert(entity != null);
assert(entity._index == null);
assert(
_list.length == _data.length,
'Data list length ${_data.length} inconsistent '
'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
_size++;
assert(data != null);
_data.add(data);
return entity;
}
/// Registers a new [entity] with an associated [data] object by the given
/// [index].
E0 registerByIndex<E0 extends E, D0 extends D>(
int index, E0 entity, D0 data) {
assert(index >= _list.length);
_list.length = _data.length = index;
return register(entity, data);
}
/// Calls [f] for each non-null entity with its corresponding data object.
void forEach<E0 extends E, D0 extends D>(void f(E0 entity, D0 data)) {
if (_list.length != _data.length) {
throw new StateError('Data is in the process of being created.');
}
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity, _data[index]);
}
}
}
}
/// Base implementation for an index based of entities of type [E] with a
@ -128,7 +177,7 @@ abstract class EntityDataEnvMapBase<E extends _Indexed, D, V>
/// Returns the environment object stored for the [index]th entity.
V getEnv(E entity) {
int index = entity._index;
if (index < length && index >= _env.length) {
if (index < _list.length && index >= _env.length) {
throw new StateError(
'Env is in the process of being created for ${_list[index]}.');
}
@ -149,12 +198,48 @@ class EntityDataEnvMap<E extends _Indexed, D, V>
E0 entity, D0 data, V0 env) {
assert(entity != null);
assert(entity._index == null);
assert(
_list.length == _data.length,
'Data list length ${_data.length} inconsistent '
'with entity list length ${_list.length}.');
assert(
_list.length == _env.length,
'Env list length ${_env.length} inconsistent '
'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
_size++;
assert(data != null);
_data.add(data);
assert(env != null);
_env.add(env);
return entity;
}
/// Registers a new [entity] with an associated [data] object and environment
/// [env] by the given [index].
E0 registerByIndex<E0 extends E, D0 extends D, V0 extends V>(
int index, E0 entity, D0 data, V0 env) {
assert(index >= _list.length);
_list.length = _data.length = _env.length = index;
return register(entity, data, env);
}
/// Calls [f] for each non-null entity with its corresponding data object and
/// environment.
void forEach<E0 extends E, D0 extends D, V0 extends V>(
void f(E0 entity, D0 data, V0 env)) {
if (_list.length != _data.length) {
throw new StateError('Data is in the process of being created.');
}
if (_list.length != _env.length) {
throw new StateError('Env is in the process of being created.');
}
for (int index = 0; index < _list.length; index++) {
E entity = _list[index];
if (entity != null) {
f(entity, _data[index], _env[index]);
}
}
}
}

View file

@ -16,12 +16,12 @@ import '../elements/names.dart';
import '../elements/types.dart';
import '../js_backend/inferred_data.dart';
import '../js_backend/no_such_method_registry.dart';
import '../js_emitter/sorter.dart';
import '../js_model/element_map.dart';
import '../js_model/js_strategy.dart';
import '../js_model/locals.dart';
import '../native/behavior.dart' as native;
import '../options.dart';
import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
@ -288,8 +288,6 @@ class InferrerEngineImpl extends InferrerEngine {
final NoSuchMethodRegistry noSuchMethodRegistry;
final Sorter sorter;
InferrerEngineImpl(
this.options,
this.progress,
@ -298,7 +296,6 @@ class InferrerEngineImpl extends InferrerEngine {
this.closedWorld,
this.noSuchMethodRegistry,
this.mainElement,
this.sorter,
this.inferredDataBuilder)
: this.types = new TypeSystem(
closedWorld, new KernelTypeSystemStrategy(closedWorld));
@ -1365,6 +1362,10 @@ class KernelTypeSystemStrategy implements TypeSystemStrategy {
class KernelGlobalTypeInferenceElementData
implements GlobalTypeInferenceElementData {
/// Tag used for identifying serialized [GlobalTypeInferenceElementData]
/// objects in a debugging data stream.
static const String tag = 'global-type-inference-element-data';
// TODO(johnniwinther): Rename this together with [typeOfSend].
Map<ir.TreeNode, AbstractValue> _sendMap;
@ -1372,6 +1373,86 @@ class KernelGlobalTypeInferenceElementData
Map<ir.ForInStatement, AbstractValue> _currentMap;
Map<ir.ForInStatement, AbstractValue> _moveNextMap;
KernelGlobalTypeInferenceElementData();
KernelGlobalTypeInferenceElementData.internal(
this._sendMap, this._iteratorMap, this._currentMap, this._moveNextMap);
/// Deserializes a [GlobalTypeInferenceElementData] object from [source].
factory KernelGlobalTypeInferenceElementData.readFromDataSource(
DataSource source, AbstractValueDomain abstractValueDomain) {
source.begin(tag);
Map<ir.TreeNode, AbstractValue> sendMap = source.readTreeNodeMap(
() => abstractValueDomain.readAbstractValueFromDataSource(source),
emptyAsNull: true);
Map<ir.ForInStatement, AbstractValue> iteratorMap = source.readTreeNodeMap(
() => abstractValueDomain.readAbstractValueFromDataSource(source),
emptyAsNull: true);
Map<ir.ForInStatement, AbstractValue> currentMap = source.readTreeNodeMap(
() => abstractValueDomain.readAbstractValueFromDataSource(source),
emptyAsNull: true);
Map<ir.ForInStatement, AbstractValue> moveNextMap = source.readTreeNodeMap(
() => abstractValueDomain.readAbstractValueFromDataSource(source),
emptyAsNull: true);
source.end(tag);
return new KernelGlobalTypeInferenceElementData.internal(
sendMap, iteratorMap, currentMap, moveNextMap);
}
/// Serializes this [GlobalTypeInferenceElementData] to [sink].
void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
sink.begin(tag);
sink.writeTreeNodeMap(
_sendMap,
(AbstractValue value) =>
abstractValueDomain.writeAbstractValueToDataSink(sink, value),
allowNull: true);
sink.writeTreeNodeMap(
_iteratorMap,
(AbstractValue value) =>
abstractValueDomain.writeAbstractValueToDataSink(sink, value),
allowNull: true);
sink.writeTreeNodeMap(
_currentMap,
(AbstractValue value) =>
abstractValueDomain.writeAbstractValueToDataSink(sink, value),
allowNull: true);
sink.writeTreeNodeMap(
_moveNextMap,
(AbstractValue value) =>
abstractValueDomain.writeAbstractValueToDataSink(sink, value),
allowNull: true);
sink.end(tag);
}
@override
void compress() {
if (_sendMap != null) {
_sendMap.removeWhere(_mapsToNull);
if (_sendMap.isEmpty) {
_sendMap = null;
}
}
if (_iteratorMap != null) {
_iteratorMap.removeWhere(_mapsToNull);
if (_iteratorMap.isEmpty) {
_iteratorMap = null;
}
}
if (_currentMap != null) {
_currentMap.removeWhere(_mapsToNull);
if (_currentMap.isEmpty) {
_currentMap = null;
}
}
if (_moveNextMap != null) {
_moveNextMap.removeWhere(_mapsToNull);
if (_moveNextMap.isEmpty) {
_moveNextMap = null;
}
}
}
@override
AbstractValue typeOfSend(ir.TreeNode node) {
if (_sendMap == null) return null;
@ -1429,3 +1510,5 @@ class KernelGlobalTypeInferenceElementData
return _sendMap[node];
}
}
bool _mapsToNull(ir.TreeNode node, AbstractValue value) => value == null;

View file

@ -79,7 +79,6 @@ class TypeGraphInferrer implements TypesInferrer {
closedWorld,
_compiler.backend.noSuchMethodRegistry,
main,
_compiler.backendStrategy.sorter,
_inferredDataBuilder);
}
@ -109,6 +108,7 @@ class TypeGraphInferrer implements TypesInferrer {
void createMemberResults(
MemberEntity member, MemberTypeInformation typeInformation) {
GlobalTypeInferenceElementData data = inferrer.dataOfMember(member);
data.compress();
bool isJsInterop = closedWorld.nativeData.isJsInteropMember(member);
AbstractValue returnType;

View file

@ -8,6 +8,10 @@ part of masks;
/// site of a container (currently only List) that will get specialized
/// once the [TypeGraphInferrer] phase finds an element type for it.
class ContainerTypeMask extends AllocationTypeMask {
/// Tag used for identifying serialized [ContainerTypeMask] objects in a
/// debugging data stream.
static const String tag = 'container-type-mask';
final TypeMask forwardTo;
// The [Node] where this type mask was created.
@ -25,6 +29,32 @@ class ContainerTypeMask extends AllocationTypeMask {
ContainerTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
this.elementType, this.length);
/// Deserializes a [ContainerTypeMask] object from [source].
factory ContainerTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
ir.TreeNode allocationNode = source.readTreeNodeOrNull();
MemberEntity allocationElement = source.readMemberOrNull();
TypeMask elementType = new TypeMask.readFromDataSource(source, closedWorld);
int length = source.readIntOrNull();
source.end(tag);
return new ContainerTypeMask(
forwardTo, allocationNode, allocationElement, elementType, length);
}
/// Serializes this [ContainerTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.container);
sink.begin(tag);
forwardTo.writeToDataSink(sink);
sink.writeTreeNodeOrNull(allocationNode);
sink.writeMemberOrNull(allocationElement);
elementType.writeToDataSink(sink);
sink.writeIntOrNull(length);
sink.end(tag);
}
TypeMask nullable() {
return isNullable
? this

View file

@ -13,6 +13,10 @@ part of masks;
* the more general [MapTypeMask] is used.
*/
class DictionaryTypeMask extends MapTypeMask {
/// Tag used for identifying serialized [DictionaryTypeMask] objects in a
/// debugging data stream.
static const String tag = 'dictionary-type-mask';
// The underlying key/value map of this dictionary.
final Map<String, AbstractValue> _typeMap;
@ -25,6 +29,38 @@ class DictionaryTypeMask extends MapTypeMask {
this._typeMap)
: super(forwardTo, allocationNode, allocationElement, keyType, valueType);
/// Deserializes a [DictionaryTypeMask] object from [source].
factory DictionaryTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
ir.TreeNode allocationNode = source.readTreeNode();
MemberEntity allocationElement = source.readMember();
TypeMask keyType = new TypeMask.readFromDataSource(source, closedWorld);
TypeMask valueType = new TypeMask.readFromDataSource(source, closedWorld);
Map<String, AbstractValue> typeMap = source.readStringMap(
() => new TypeMask.readFromDataSource(source, closedWorld));
source.end(tag);
return new DictionaryTypeMask(forwardTo, allocationNode, allocationElement,
keyType, valueType, typeMap);
}
/// Serializes this [DictionaryTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.dictionary);
sink.begin(tag);
forwardTo.writeToDataSink(sink);
sink.writeTreeNode(allocationNode);
sink.writeMember(allocationElement);
valueType.writeToDataSink(sink);
keyType.writeToDataSink(sink);
sink.writeStringMap(_typeMap, (AbstractValue value) {
TypeMask typeMask = value;
typeMask.writeToDataSink(sink);
});
sink.end(tag);
}
TypeMask nullable() {
return isNullable
? this

View file

@ -9,6 +9,10 @@ part of masks;
* base type.
*/
class FlatTypeMask implements TypeMask {
/// Tag used for identifying serialized [FlatTypeMask] objects in a
/// debugging data stream.
static const String tag = 'flat-type-mask';
static const int EMPTY = 0;
static const int EXACT = 1;
static const int SUBCLASS = 2;
@ -39,10 +43,6 @@ class FlatTypeMask implements TypeMask {
FlatTypeMask.nonNullSubtype(ClassEntity base)
: this.internal(base, SUBTYPE << 1);
ClassQuery get _classQuery => isExact
? ClassQuery.EXACT
: (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE);
FlatTypeMask.internal(this.base, this.flags);
/**
@ -69,6 +69,31 @@ class FlatTypeMask implements TypeMask {
base, flags, () => new FlatTypeMask.internal(base, flags));
}
/// Deserializes a [FlatTypeMask] object from [source].
factory FlatTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
ClassEntity base = source.readClassOrNull();
int flags = source.readInt();
source.end(tag);
CommonMasks commonMasks = closedWorld.abstractValueDomain;
return commonMasks.getCachedMask(
base, flags, () => new FlatTypeMask.internal(base, flags));
}
/// Serializes this [FlatTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.flat);
sink.begin(tag);
sink.writeClassOrNull(base);
sink.writeInt(flags);
sink.end(tag);
}
ClassQuery get _classQuery => isExact
? ClassQuery.EXACT
: (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE);
bool get isEmpty => isEmptyOrNull && !isNullable;
bool get isNull => isEmptyOrNull && isNullable;
bool get isEmptyOrNull => (flags >> 1) == EMPTY;

View file

@ -10,6 +10,10 @@ part of masks;
* once the [TypeGraphInferrer] phase finds a key and/or value type for it.
*/
class MapTypeMask extends AllocationTypeMask {
/// Tag used for identifying serialized [MapTypeMask] objects in a
/// debugging data stream.
static const String tag = 'map-type-mask';
final TypeMask forwardTo;
// The [Node] where this type mask was created.
@ -27,6 +31,32 @@ class MapTypeMask extends AllocationTypeMask {
MapTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
this.keyType, this.valueType);
/// Deserializes a [MapTypeMask] object from [source].
factory MapTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
ir.TreeNode allocationNode = source.readTreeNode();
MemberEntity allocationElement = source.readMember();
TypeMask keyType = new TypeMask.readFromDataSource(source, closedWorld);
TypeMask valueType = new TypeMask.readFromDataSource(source, closedWorld);
source.end(tag);
return new MapTypeMask(
forwardTo, allocationNode, allocationElement, keyType, valueType);
}
/// Serializes this [MapTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.map);
sink.begin(tag);
forwardTo.writeToDataSink(sink);
sink.writeTreeNode(allocationNode);
sink.writeMember(allocationElement);
valueType.writeToDataSink(sink);
keyType.writeToDataSink(sink);
sink.end(tag);
}
TypeMask nullable() {
return isNullable
? this

View file

@ -8,8 +8,9 @@ import 'package:kernel/ast.dart' as ir;
import '../../common.dart';
import '../../common_elements.dart' show CommonElements;
import '../../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
import '../../constants/values.dart';
import '../../elements/entities.dart';
import '../../serialization/serialization.dart';
import '../../types/abstract_value_domain.dart';
import '../../universe/class_hierarchy.dart';
import '../../universe/selector.dart' show Selector;
@ -718,6 +719,16 @@ class CommonMasks implements AbstractValueDomain {
String getCompactText(AbstractValue value) {
return formatType(value);
}
@override
TypeMask readAbstractValueFromDataSource(DataSource source) {
return new TypeMask.readFromDataSource(source, _closedWorld);
}
@override
void writeAbstractValueToDataSink(DataSink sink, covariant TypeMask value) {
value.writeToDataSink(sink);
}
}
/// Convert the given TypeMask to a compact string format.

View file

@ -91,6 +91,16 @@ class TypeMaskSelectorStrategy implements SelectorConstraintsStrategy {
}
}
/// Enum used for identifying [TypeMask] subclasses in serialization.
enum TypeMaskKind {
flat,
union,
container,
map,
dictionary,
value,
}
/**
* A type mask represents a set of contained classes, but the
* operations on it are not guaranteed to be precise and they may
@ -209,6 +219,30 @@ abstract class TypeMask implements AbstractValue {
return UnionTypeMask.unionOf(masks, closedWorld);
}
/// Deserializes a [TypeMask] object from [source].
factory TypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
TypeMaskKind kind = source.readEnum(TypeMaskKind.values);
switch (kind) {
case TypeMaskKind.flat:
return new FlatTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.union:
return new UnionTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.container:
return new ContainerTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.map:
return new MapTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.dictionary:
return new DictionaryTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.value:
return new ValueTypeMask.readFromDataSource(source, closedWorld);
}
throw new UnsupportedError("Unexpected TypeMaskKind $kind.");
}
/// Serializes this [TypeMask] to [sink].
void writeToDataSink(DataSink sink);
/**
* If [mask] is forwarding, returns the first non-forwarding [TypeMask] in
* [mask]'s forwarding chain.

View file

@ -5,7 +5,9 @@
part of masks;
class UnionTypeMask implements TypeMask {
final Iterable<FlatTypeMask> disjointMasks;
/// Tag used for identifying serialized [UnionTypeMask] objects in a
/// debugging data stream.
static const String tag = 'union-type-mask';
static const int MAX_UNION_LENGTH = 4;
@ -14,11 +16,32 @@ class UnionTypeMask implements TypeMask {
// helpful in debugging.
static const bool PERFORM_EXTRA_CONTAINS_CHECK = false;
final Iterable<FlatTypeMask> disjointMasks;
UnionTypeMask._internal(this.disjointMasks) {
assert(disjointMasks.length > 1);
assert(disjointMasks.every((TypeMask mask) => !mask.isUnion));
}
/// Deserializes a [UnionTypeMask] object from [source].
factory UnionTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
List<FlatTypeMask> disjointMasks = source
.readList(() => new TypeMask.readFromDataSource(source, closedWorld));
source.end(tag);
return new UnionTypeMask._internal(disjointMasks);
}
/// Serializes this [UnionTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.union);
sink.begin(tag);
sink.writeList(
disjointMasks, (FlatTypeMask mask) => mask.writeToDataSink(sink));
sink.end(tag);
}
static TypeMask unionOf(Iterable<TypeMask> masks, JClosedWorld closedWorld) {
assert(
masks.every((mask) => TypeMask.assertIsNormalized(mask, closedWorld)));

View file

@ -5,11 +5,34 @@
part of masks;
class ValueTypeMask extends ForwardingTypeMask {
/// Tag used for identifying serialized [ValueTypeMask] objects in a
/// debugging data stream.
static const String tag = 'value-type-mask';
final TypeMask forwardTo;
final PrimitiveConstantValue value;
ValueTypeMask(this.forwardTo, this.value);
/// Deserializes a [ValueTypeMask] object from [source].
factory ValueTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
ConstantValue constant = source.readConstant();
source.end(tag);
return new ValueTypeMask(forwardTo, constant);
}
/// Serializes this [ValueTypeMask] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.value);
sink.begin(tag);
forwardTo.writeToDataSink(sink);
sink.writeConstant(value);
sink.end(tag);
}
TypeMask nullable() {
return isNullable ? this : new ValueTypeMask(forwardTo.nullable(), value);
}

View file

@ -10,6 +10,7 @@ import '../kernel/element_map.dart';
import '../kernel/kernel_strategy.dart';
import '../kernel/kelements.dart' show KClass, KField;
import '../options.dart';
import '../serialization/serialization.dart';
abstract class AllocatorAnalysis {}
@ -70,6 +71,10 @@ class KAllocatorAnalysis implements AllocatorAnalysis {
}
class JAllocatorAnalysis implements AllocatorAnalysis {
/// Tag used for identifying serialized [JAllocatorAnalysis] objects in a
/// debugging data stream.
static const String tag = 'allocator-analysis';
// --csp and --fast-startup have different constraints to the generated code.
final CompilerOptions _options;
final Map<JField, ConstantValue> _fixedInitializers =
@ -77,6 +82,34 @@ class JAllocatorAnalysis implements AllocatorAnalysis {
JAllocatorAnalysis._(this._options);
/// Deserializes a [JAllocatorAnalysis] object from [source].
factory JAllocatorAnalysis.readFromDataSource(
DataSource source, CompilerOptions options) {
source.begin(tag);
JAllocatorAnalysis analysis = new JAllocatorAnalysis._(options);
int fieldCount = source.readInt();
for (int i = 0; i < fieldCount; i++) {
JField field = source.readMember();
// TODO(sra): Deserialize constant, when non-null is supported.
ConstantValue value = const NullConstantValue();
analysis._fixedInitializers[field] = value;
}
source.end(tag);
return analysis;
}
/// Serializes this [JAllocatorAnalysis] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeInt(_fixedInitializers.length);
_fixedInitializers.forEach((JField field, ConstantValue value) {
sink.writeMember(field);
// TODO(sra): Serialize constant, when non-null is supported.
assert(value.isNull);
});
sink.end(tag);
}
static JAllocatorAnalysis from(KAllocatorAnalysis kAnalysis,
JsToFrontendMap map, CompilerOptions options) {
var result = new JAllocatorAnalysis._(options);

View file

@ -10,6 +10,7 @@ import '../diagnostics/diagnostic_listener.dart';
import '../diagnostics/messages.dart';
import '../elements/entities.dart';
import '../native/native.dart' as native;
import '../serialization/serialization.dart';
/// Returns `true` if parameter and returns types should be trusted for
/// [element].
@ -179,6 +180,13 @@ AnnotationsData processAnnotations(
}
abstract class AnnotationsData {
/// Deserializes a [AnnotationsData] object from [source].
factory AnnotationsData.readFromDataSource(DataSource source) =
AnnotationsDataImpl.readFromDataSource;
/// Serializes this [AnnotationsData] to [sink].
void writeToDataSink(DataSink sink);
/// Functions with a `@NoInline()` or `@noInline` annotation.
Iterable<FunctionEntity> get nonInlinableFunctions;
@ -199,6 +207,10 @@ abstract class AnnotationsData {
}
class AnnotationsDataImpl implements AnnotationsData {
/// Tag used for identifying serialized [AnnotationsData] objects in a
/// debugging data stream.
static const String tag = 'annotations-data';
final Iterable<FunctionEntity> nonInlinableFunctions;
final Iterable<FunctionEntity> tryInlineFunctions;
final Iterable<FunctionEntity> cannotThrowFunctions;
@ -213,6 +225,35 @@ class AnnotationsDataImpl implements AnnotationsData {
this.sideEffectFreeFunctions,
this.trustTypeAnnotationsMembers,
this.assumeDynamicMembers);
factory AnnotationsDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
Iterable<FunctionEntity> nonInlinableFunctions = source.readMembers();
Iterable<FunctionEntity> tryInlineFunctions = source.readMembers();
Iterable<FunctionEntity> cannotThrowFunctions = source.readMembers();
Iterable<FunctionEntity> sideEffectFreeFunctions = source.readMembers();
Iterable<MemberEntity> trustTypeAnnotationsMembers = source.readMembers();
Iterable<MemberEntity> assumeDynamicMembers = source.readMembers();
source.end(tag);
return new AnnotationsDataImpl(
nonInlinableFunctions,
tryInlineFunctions,
cannotThrowFunctions,
sideEffectFreeFunctions,
trustTypeAnnotationsMembers,
assumeDynamicMembers);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMembers(nonInlinableFunctions);
sink.writeMembers(tryInlineFunctions);
sink.writeMembers(cannotThrowFunctions);
sink.writeMembers(sideEffectFreeFunctions);
sink.writeMembers(trustTypeAnnotationsMembers);
sink.writeMembers(assumeDynamicMembers);
sink.end(tag);
}
}
class AnnotationsDataBuilder implements AnnotationsData {
@ -255,4 +296,8 @@ class AnnotationsDataBuilder implements AnnotationsData {
Iterable<MemberEntity> get trustTypeAnnotationsMembers =>
_trustTypeAnnotationsMembers;
Iterable<MemberEntity> get assumeDynamicMembers => _assumeDynamicMembers;
void writeToDataSink(DataSink sink) {
throw new UnsupportedError('AnnotationsDataBuilder.writeToDataSink');
}
}

View file

@ -7,11 +7,19 @@ import '../common_elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../frontend_strategy.dart';
import '../serialization/serialization.dart';
import '../universe/feature.dart';
import '../util/util.dart' show Setlet;
import 'backend_impact.dart';
abstract class BackendUsage {
/// Deserializes a [BackendUsage] object from [source].
factory BackendUsage.readFromDataSource(DataSource source) =
BackendUsageImpl.readFromDataSource;
/// Serializes this [BackendUsage] to [sink].
void writeToDataSink(DataSink sink);
bool needToInitializeIsolateAffinityTag;
bool needToInitializeDispatchProperty;
@ -262,6 +270,10 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
}
class BackendUsageImpl implements BackendUsage {
/// Tag used for identifying serialized [BackendUsage] objects in a
/// debugging data stream.
static const String tag = 'backend-usage';
// TODO(johnniwinther): Remove the need for these.
final Set<FunctionEntity> _globalFunctionDependencies;
final Set<ClassEntity> _globalClassDependencies;
@ -307,6 +319,61 @@ class BackendUsageImpl implements BackendUsage {
this._helperClassesUsed = helperClassesUsed,
this._runtimeTypeUses = runtimeTypeUses;
factory BackendUsageImpl.readFromDataSource(DataSource source) {
source.begin(tag);
Set<FunctionEntity> globalFunctionDependencies =
source.readMembers<FunctionEntity>().toSet();
Set<ClassEntity> globalClassDependencies = source.readClasses().toSet();
Set<FunctionEntity> helperFunctionsUsed =
source.readMembers<FunctionEntity>().toSet();
Set<ClassEntity> helperClassesUsed = source.readClasses().toSet();
Set<RuntimeTypeUse> runtimeTypeUses = source.readList(() {
RuntimeTypeUseKind kind = source.readEnum(RuntimeTypeUseKind.values);
DartType receiverType = source.readDartType();
DartType argumentType = source.readDartType(allowNull: true);
return new RuntimeTypeUse(kind, receiverType, argumentType);
}).toSet();
bool needToInitializeIsolateAffinityTag = source.readBool();
bool needToInitializeDispatchProperty = source.readBool();
bool requiresPreamble = source.readBool();
bool isFunctionApplyUsed = source.readBool();
bool isMirrorsUsed = source.readBool();
bool isNoSuchMethodUsed = source.readBool();
source.end(tag);
return new BackendUsageImpl(
globalFunctionDependencies: globalFunctionDependencies,
globalClassDependencies: globalClassDependencies,
helperFunctionsUsed: helperFunctionsUsed,
helperClassesUsed: helperClassesUsed,
runtimeTypeUses: runtimeTypeUses,
needToInitializeIsolateAffinityTag: needToInitializeIsolateAffinityTag,
needToInitializeDispatchProperty: needToInitializeDispatchProperty,
requiresPreamble: requiresPreamble,
isFunctionApplyUsed: isFunctionApplyUsed,
isMirrorsUsed: isMirrorsUsed,
isNoSuchMethodUsed: isNoSuchMethodUsed);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMembers(_globalFunctionDependencies);
sink.writeClasses(_globalClassDependencies);
sink.writeMembers(_helperFunctionsUsed);
sink.writeClasses(_helperClassesUsed);
sink.writeList(runtimeTypeUses, (RuntimeTypeUse runtimeTypeUse) {
sink.writeEnum(runtimeTypeUse.kind);
sink.writeDartType(runtimeTypeUse.receiverType);
sink.writeDartType(runtimeTypeUse.argumentType, allowNull: true);
});
sink.writeBool(needToInitializeIsolateAffinityTag);
sink.writeBool(needToInitializeDispatchProperty);
sink.writeBool(requiresPreamble);
sink.writeBool(isFunctionApplyUsed);
sink.writeBool(isMirrorsUsed);
sink.writeBool(isNoSuchMethodUsed);
sink.end(tag);
}
@override
bool isFunctionUsedByBackend(FunctionEntity element) {
return _helperFunctionsUsed.contains(element);

View file

@ -6,6 +6,7 @@ import 'dart:collection' show Queue;
import '../common.dart';
import '../elements/entities.dart';
import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
@ -13,6 +14,20 @@ import '../world.dart';
import 'annotations.dart';
abstract class InferredData {
/// Deserializes a [InferredData] object from [source].
factory InferredData.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
bool isTrivial = source.readBool();
if (isTrivial) {
return new TrivialInferredData();
} else {
return new InferredDataImpl.readFromDataSource(source, closedWorld);
}
}
/// Serializes this [InferredData] to [sink].
void writeToDataSink(DataSink sink);
/// Returns the side effects of executing [element].
SideEffects getSideEffectsOfElement(FunctionEntity element);
@ -62,6 +77,10 @@ abstract class InferredDataBuilder {
}
class InferredDataImpl implements InferredData {
/// Tag used for identifying serialized [InferredData] objects in a
/// debugging data stream.
static const String tag = 'inferred-data';
final JClosedWorld _closedWorld;
final Set<MemberEntity> _functionsCalledInLoop;
final Map<FunctionEntity, SideEffects> _sideEffects;
@ -80,6 +99,40 @@ class InferredDataImpl implements InferredData {
this._elementsThatCannotThrow,
this._functionsThatMightBePassedToApply);
factory InferredDataImpl.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
Set<MemberEntity> functionsCalledInLoop = source.readMembers().toSet();
Map<FunctionEntity, SideEffects> sideEffects =
source.readMemberMap(() => new SideEffects.readFromDataSource(source));
Set<FunctionEntity> sideEffectsFreeElements =
source.readMembers<FunctionEntity>().toSet();
Set<FunctionEntity> elementsThatCannotThrow =
source.readMembers<FunctionEntity>().toSet();
Set<FunctionEntity> functionsThatMightBePassedToApply =
source.readMembers<FunctionEntity>().toSet();
source.end(tag);
return new InferredDataImpl(
closedWorld,
functionsCalledInLoop,
sideEffects,
sideEffectsFreeElements,
elementsThatCannotThrow,
functionsThatMightBePassedToApply);
}
void writeToDataSink(DataSink sink) {
sink.writeBool(false); // Is _not_ trivial.
sink.begin(tag);
sink.writeMembers(_functionsCalledInLoop);
sink.writeMemberMap(_sideEffects,
(SideEffects sideEffects) => sideEffects.writeToDataSink(sink));
sink.writeMembers(_sideEffectsFreeElements);
sink.writeMembers(_elementsThatCannotThrow);
sink.writeMembers(_functionsThatMightBePassedToApply);
sink.end(tag);
}
@override
SideEffects getSideEffectsOfSelector(
Selector selector, AbstractValue receiver) {
@ -250,6 +303,11 @@ class InferredDataBuilderImpl implements InferredDataBuilder {
class TrivialInferredData implements InferredData {
final SideEffects _allSideEffects = new SideEffects();
@override
void writeToDataSink(DataSink sink) {
sink.writeBool(true); // Is trivial.
}
@override
SideEffects getSideEffectsOfElement(FunctionEntity element) {
return _allSideEffects;

View file

@ -10,6 +10,7 @@ import '../common_elements.dart'
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart';
import '../world.dart' show JClosedWorld;
@ -17,6 +18,15 @@ import 'namer.dart';
import 'native_data.dart';
abstract class InterceptorData {
/// Deserializes a [InterceptorData] object from [source].
factory InterceptorData.readFromDataSource(
DataSource source,
NativeData nativeData,
CommonElements commonElements) = InterceptorDataImpl.readFromDataSource;
/// Serializes this [InterceptorData] to [sink].
void writeToDataSink(DataSink sink);
/// Returns `true` if [cls] is an intercepted class.
bool isInterceptedClass(ClassEntity element);
@ -49,6 +59,10 @@ abstract class InterceptorDataBuilder {
}
class InterceptorDataImpl implements InterceptorData {
/// Tag used for identifying serialized [InterceptorData] objects in a
/// debugging data stream.
static const String tag = 'interceptor-data';
final NativeBasicData _nativeData;
final CommonElements _commonElements;
@ -89,6 +103,40 @@ class InterceptorDataImpl implements InterceptorData {
this.interceptedClasses,
this.classesMixedIntoInterceptedClasses);
factory InterceptorDataImpl.readFromDataSource(
DataSource source, NativeData nativeData, CommonElements commonElements) {
source.begin(tag);
int interceptedMembersCount = source.readInt();
Map<String, Set<MemberEntity>> interceptedMembers = {};
for (int i = 0; i < interceptedMembersCount; i++) {
String name = source.readString();
Set<MemberEntity> members = source.readMembers().toSet();
interceptedMembers[name] = members;
}
Set<ClassEntity> interceptedClasses = source.readClasses().toSet();
Set<ClassEntity> classesMixedIntoInterceptedClasses =
source.readClasses().toSet();
source.end(tag);
return new InterceptorDataImpl(
nativeData,
commonElements,
interceptedMembers,
interceptedClasses,
classesMixedIntoInterceptedClasses);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeInt(interceptedMembers.length);
interceptedMembers.forEach((String name, Set<MemberEntity> members) {
sink.writeString(name);
sink.writeMembers(members);
});
sink.writeClasses(interceptedClasses);
sink.writeClasses(classesMixedIntoInterceptedClasses);
sink.end(tag);
}
bool isInterceptedMethod(MemberEntity element) {
if (!element.isInstanceMember) return false;
// TODO(johnniwinther): Avoid this hack.

View file

@ -8,12 +8,21 @@ import '../common.dart';
import '../common_elements.dart' show ElementEnvironment;
import '../elements/entities.dart';
import '../native/behavior.dart' show NativeBehavior;
import '../serialization/serialization.dart';
import '../util/util.dart';
/// Basic information for native classes and js-interop libraries and classes.
///
/// This information is computed during loading using [NativeBasicDataBuilder].
abstract class NativeBasicData {
/// Deserializes a [NativeBasicData] object from [source].
factory NativeBasicData.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) =
NativeBasicDataImpl.readFromDataSource;
/// Serializes this [NativeBasicData] to [sink].
void writeToDataSink(DataSink sink);
/// Returns `true` if [cls] corresponds to a native JavaScript class.
///
/// A class is marked as native either through the `@Native(...)` annotation
@ -48,6 +57,14 @@ abstract class NativeBasicData {
///
/// This information is computed during resolution using [NativeDataBuilder].
abstract class NativeData extends NativeBasicData {
/// Deserializes a [NativeData] object from [source].
factory NativeData.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) =
NativeDataImpl.readFromDataSource;
/// Serializes this [NativeData] to [sink].
void writeToDataSink(DataSink sink);
/// Returns `true` if [element] corresponds to a native JavaScript member.
///
/// A member is marked as native either through the native mechanism
@ -267,6 +284,10 @@ class NativeBasicDataBuilderImpl implements NativeBasicDataBuilder {
}
class NativeBasicDataImpl implements NativeBasicData {
/// Tag used for identifying serialized [NativeBasicData] objects in a
/// debugging data stream.
static const String tag = 'native-basic-data';
final ElementEnvironment _env;
/// Tag info for native JavaScript classes names. See
@ -293,6 +314,45 @@ class NativeBasicDataImpl implements NativeBasicData {
this.anonymousJsInteropClasses,
this.jsInteropMembers);
factory NativeBasicDataImpl.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) {
source.begin(tag);
Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
source.readClassMap(() {
List<String> names = source.readStrings();
bool isNonLeaf = source.readBool();
return new NativeClassTag.internal(names, isNonLeaf);
});
Map<LibraryEntity, String> jsInteropLibraries =
source.readLibraryMap(source.readString);
Map<ClassEntity, String> jsInteropClasses =
source.readLibraryMap(source.readString);
Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
Map<MemberEntity, String> jsInteropMembers =
source.readLibraryMap(source.readString);
source.end(tag);
return new NativeBasicDataImpl(
elementEnvironment,
nativeClassTagInfo,
jsInteropLibraries,
jsInteropClasses,
anonymousJsInteropClasses,
jsInteropMembers);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeClassMap(nativeClassTagInfo, (NativeClassTag tag) {
sink.writeStrings(tag.names);
sink.writeBool(tag.isNonLeaf);
});
sink.writeLibraryMap(jsInteropLibraries, sink.writeString);
sink.writeClassMap(jsInteropClasses, sink.writeString);
sink.writeClasses(anonymousJsInteropClasses);
sink.writeMemberMap(jsInteropMembers, sink.writeString);
sink.end(tag);
}
@override
bool isNativeClass(ClassEntity element) {
if (isJsInteropClass(element)) return true;
@ -480,7 +540,13 @@ class NativeDataBuilderImpl implements NativeDataBuilder {
jsInteropMembers);
}
// TODO(johnniwinther): Remove fields that overlap with [NativeBasicData], like
// [anonymousJsInteropClasses].
class NativeDataImpl implements NativeData, NativeBasicDataImpl {
/// Tag used for identifying serialized [NativeData] objects in a
/// debugging data stream.
static const String tag = 'native-data';
/// Prefix used to escape JS names that are not valid Dart names
/// when using JSInterop.
static const String _jsInteropEscapePrefix = r'JS$';
@ -525,6 +591,63 @@ class NativeDataImpl implements NativeData, NativeBasicDataImpl {
this.jsInteropClasses,
this.jsInteropMembers);
factory NativeDataImpl.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) {
source.begin(tag);
NativeBasicData nativeBasicData =
new NativeBasicData.readFromDataSource(source, elementEnvironment);
Map<MemberEntity, String> nativeMemberName =
source.readMemberMap(source.readString);
Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = source
.readMemberMap(() => new NativeBehavior.readFromDataSource(source));
Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = source
.readMemberMap(() => new NativeBehavior.readFromDataSource(source));
Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = source
.readMemberMap(() => new NativeBehavior.readFromDataSource(source));
Map<LibraryEntity, String> jsInteropLibraries =
source.readLibraryMap(source.readString);
Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
Map<ClassEntity, String> jsInteropClasses =
source.readClassMap(source.readString);
Map<MemberEntity, String> jsInteropMembers =
source.readMemberMap(source.readString);
source.end(tag);
return new NativeDataImpl(
nativeBasicData,
nativeMemberName,
nativeMethodBehavior,
nativeFieldLoadBehavior,
nativeFieldStoreBehavior,
jsInteropLibraries,
anonymousJsInteropClasses,
jsInteropClasses,
jsInteropMembers);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
_nativeBasicData.writeToDataSink(sink);
sink.writeMemberMap(nativeMemberName, sink.writeString);
sink.writeMemberMap(nativeMethodBehavior, (NativeBehavior behavior) {
behavior.writeToDataSink(sink);
});
sink.writeMemberMap(nativeFieldLoadBehavior, (NativeBehavior behavior) {
behavior.writeToDataSink(sink);
});
sink.writeMemberMap(nativeFieldStoreBehavior, (NativeBehavior behavior) {
behavior.writeToDataSink(sink);
});
sink.writeLibraryMap(jsInteropLibraries, sink.writeString);
sink.writeClasses(anonymousJsInteropClasses);
sink.writeClassMap(jsInteropClasses, sink.writeString);
sink.writeMemberMap(jsInteropMembers, sink.writeString);
sink.end(tag);
}
@override
bool isAnonymousJsInteropClass(ClassEntity element) {
return anonymousJsInteropClasses.contains(element);

View file

@ -6,6 +6,7 @@ import '../common.dart';
import '../common_elements.dart' show CommonElements;
import '../common/names.dart' show Identifiers, Selectors;
import '../elements/entities.dart';
import '../serialization/serialization.dart';
import '../types/types.dart';
/// [NoSuchMethodRegistry] and [NoSuchMethodData] categorizes `noSuchMethod`
@ -171,6 +172,13 @@ class NoSuchMethodRegistryImpl implements NoSuchMethodRegistry {
/// Post inference collected category `D` methods are into subcategories `D1`
/// and `D2`.
abstract class NoSuchMethodData {
/// Deserializes a [NoSuchMethodData] object from [source].
factory NoSuchMethodData.readFromDataSource(DataSource source) =
NoSuchMethodDataImpl.readFromDataSource;
/// Serializes this [NoSuchMethodData] to [sink].
void writeToDataSink(DataSink sink);
/// Returns [true] if the given element is a complex [noSuchMethod]
/// implementation. An implementation is complex if it falls into
/// category D, as described above.
@ -186,6 +194,10 @@ abstract class NoSuchMethodData {
}
class NoSuchMethodDataImpl implements NoSuchMethodData {
/// Tag used for identifying serialized [NoSuchMethodData] objects in a
/// debugging data stream.
static const String tag = 'no-such-method-data';
/// The implementations that fall into category B, described above.
final Set<FunctionEntity> throwingImpls;
@ -203,6 +215,35 @@ class NoSuchMethodDataImpl implements NoSuchMethodData {
NoSuchMethodDataImpl(
this.throwingImpls, this.otherImpls, this.forwardingSyntaxImpls);
factory NoSuchMethodDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
Set<FunctionEntity> throwingImpls =
source.readMembers<FunctionEntity>().toSet();
Set<FunctionEntity> otherImpls =
source.readMembers<FunctionEntity>().toSet();
Set<FunctionEntity> forwardingSyntaxImpls =
source.readMembers<FunctionEntity>().toSet();
List<FunctionEntity> complexNoReturnImpls =
source.readMembers<FunctionEntity>();
List<FunctionEntity> complexReturningImpls =
source.readMembers<FunctionEntity>();
source.end(tag);
return new NoSuchMethodDataImpl(
throwingImpls, otherImpls, forwardingSyntaxImpls)
..complexNoReturnImpls.addAll(complexNoReturnImpls)
..complexReturningImpls.addAll(complexReturningImpls);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMembers(throwingImpls);
sink.writeMembers(otherImpls);
sink.writeMembers(forwardingSyntaxImpls);
sink.writeMembers(complexNoReturnImpls);
sink.writeMembers(complexReturningImpls);
sink.end(tag);
}
/// Now that type inference is complete, split category D into two
/// subcategories: D1, those that have no return type, and D2, those
/// that have a return type.

View file

@ -19,6 +19,7 @@ import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../js_emitter/js_emitter.dart' show Emitter;
import '../options.dart';
import '../serialization/serialization.dart';
import '../universe/class_hierarchy.dart';
import '../universe/feature.dart';
import '../universe/selector.dart';
@ -42,6 +43,20 @@ typedef bool ShouldEncodeTypedefCallback(TypedefType variable);
/// Interface for the classes and methods that need runtime types.
abstract class RuntimeTypesNeed {
/// Deserializes a [RuntimeTypesNeed] object from [source].
factory RuntimeTypesNeed.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) {
bool isTrivial = source.readBool();
if (isTrivial) {
return const TrivialRuntimeTypesNeed();
}
return new RuntimeTypesNeedImpl.readFromDataSource(
source, elementEnvironment);
}
/// Serializes this [RuntimeTypesNeed] to [sink].
void writeToDataSink(DataSink sink);
/// Returns `true` if [cls] needs type arguments at runtime type.
///
/// This is for instance the case for generic classes used in a type test:
@ -106,6 +121,10 @@ abstract class RuntimeTypesNeed {
class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
const TrivialRuntimeTypesNeed();
void writeToDataSink(DataSink sink) {
sink.writeBool(true); // Is trivial.
}
@override
bool classNeedsTypeArguments(ClassEntity cls) => true;
@ -718,6 +737,10 @@ abstract class _RuntimeTypesBase {
}
class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
/// Tag used for identifying serialized [RuntimeTypesNeed] objects in a
/// debugging data stream.
static const String tag = 'runtime-types-need';
final ElementEnvironment _elementEnvironment;
final Set<ClassEntity> classesNeedingTypeArguments;
final Set<FunctionEntity> methodsNeedingSignature;
@ -737,6 +760,45 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
this.selectorsNeedingTypeArguments,
this.instantiationsNeedingTypeArguments);
factory RuntimeTypesNeedImpl.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) {
source.begin(tag);
Set<ClassEntity> classesNeedingTypeArguments =
source.readClasses<ClassEntity>().toSet();
Set<FunctionEntity> methodsNeedingSignature =
source.readMembers<FunctionEntity>().toSet();
Set<FunctionEntity> methodsNeedingTypeArguments =
source.readMembers<FunctionEntity>().toSet();
Set<Selector> selectorsNeedingTypeArguments =
source.readList(() => new Selector.readFromDataSource(source)).toSet();
Set<int> instantiationsNeedingTypeArguments =
source.readList(source.readInt).toSet();
source.end(tag);
return new RuntimeTypesNeedImpl(
elementEnvironment,
classesNeedingTypeArguments,
methodsNeedingSignature,
methodsNeedingTypeArguments,
null,
null,
selectorsNeedingTypeArguments,
instantiationsNeedingTypeArguments);
}
void writeToDataSink(DataSink sink) {
sink.writeBool(false); // Is _not_ trivial.
sink.begin(tag);
sink.writeClasses(classesNeedingTypeArguments);
sink.writeMembers(methodsNeedingSignature);
sink.writeMembers(methodsNeedingTypeArguments);
assert(localFunctionsNeedingSignature == null);
assert(localFunctionsNeedingTypeArguments == null);
sink.writeList(selectorsNeedingTypeArguments,
(Selector selector) => selector.writeToDataSink(sink));
sink.writeList(instantiationsNeedingTypeArguments, sink.writeInt);
sink.end(tag);
}
bool checkClass(covariant ClassEntity cls) => true;
bool classNeedsTypeArguments(ClassEntity cls) {

View file

@ -201,7 +201,7 @@ class CodeEmitterTask extends CompilerTask {
closedWorld.allocatorAnalysis,
inferredData,
backend.sourceInformationStrategy,
compiler.backendStrategy.sorter,
closedWorld.sorter,
typeTestRegistry.rtiNeededClasses,
closedWorld.elementEnvironment.mainFunction);
int size = emitter.emitProgram(programBuilder);

View file

@ -18,6 +18,7 @@ import '../js_model/element_map.dart';
import '../js_model/env.dart';
import '../ordered_typeset.dart';
import '../options.dart';
import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../universe/selector.dart';
import 'elements.dart';
@ -66,6 +67,8 @@ class KernelClosureConversionTask extends ClosureConversionTask {
}
class ClosureDataImpl implements ClosureData {
/// Tag used for identifying serialized [ClosureData] objects in a
/// debugging data stream.
static const String tag = 'closure-data';
final JsToElementMap _elementMap;
@ -84,6 +87,42 @@ class ClosureDataImpl implements ClosureData {
ClosureDataImpl(this._elementMap, this._scopeMap, this._capturedScopesMap,
this._capturedScopeForSignatureMap, this._localClosureRepresentationMap);
/// Deserializes a [ClosureData] object from [source].
factory ClosureDataImpl.readFromDataSource(
JsToElementMap elementMap, DataSource source) {
source.begin(tag);
// TODO(johnniwinther): Support shared [ScopeInfo].
Map<MemberEntity, ScopeInfo> scopeMap =
source.readMemberMap(() => new ScopeInfo.readFromDataSource(source));
Map<ir.TreeNode, CapturedScope> capturedScopesMap = source
.readTreeNodeMap(() => new CapturedScope.readFromDataSource(source));
Map<MemberEntity, CapturedScope> capturedScopeForSignatureMap = source
.readMemberMap(() => new CapturedScope.readFromDataSource(source));
Map<ir.TreeNode, ClosureRepresentationInfo> localClosureRepresentationMap =
source.readTreeNodeMap(
() => new ClosureRepresentationInfo.readFromDataSource(source));
source.end(tag);
return new ClosureDataImpl(elementMap, scopeMap, capturedScopesMap,
capturedScopeForSignatureMap, localClosureRepresentationMap);
}
/// Serializes this [ClosureData] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMemberMap(
_scopeMap, (ScopeInfo info) => info.writeToDataSink(sink));
sink.writeTreeNodeMap(_capturedScopesMap, (CapturedScope scope) {
scope.writeToDataSink(sink);
});
sink.writeMemberMap(_capturedScopeForSignatureMap,
(CapturedScope scope) => scope.writeToDataSink(sink));
sink.writeTreeNodeMap(_localClosureRepresentationMap,
(ClosureRepresentationInfo info) {
info.writeToDataSink(sink);
});
sink.end(tag);
}
@override
ScopeInfo getScopeInfo(MemberEntity entity) {
// TODO(johnniwinther): Remove this check when constructor bodies a created
@ -659,7 +698,11 @@ Local _getLocal(
}
class JsScopeInfo extends ScopeInfo {
final Set<Local> localsUsedInTryOrSync;
/// Tag used for identifying serialized [JsScopeInfo] objects in a
/// debugging data stream.
static const String tag = 'scope-info';
final Iterable<Local> localsUsedInTryOrSync;
final Local thisLocal;
final Map<Local, JRecordField> boxedVariables;
@ -702,6 +745,29 @@ class JsScopeInfo extends ScopeInfo {
}
bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
factory JsScopeInfo.readFromDataSource(DataSource source) {
source.begin(tag);
Iterable<Local> localsUsedInTryOrSync = source.readLocals();
Local thisLocal = source.readLocalOrNull();
Map<Local, JRecordField> boxedVariables =
source.readLocalMap<Local, JRecordField>(() => source.readMember());
Set<Local> freeVariables = source.readLocals().toSet();
source.end(tag);
return new JsScopeInfo.internal(
localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.scopeInfo);
sink.begin(tag);
sink.writeLocals(localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
sink.writeLocalMap(boxedVariables, sink.writeMember);
sink.writeLocals(freeVariables);
sink.end(tag);
}
}
class KernelCapturedScope extends KernelScopeInfo {
@ -746,8 +812,21 @@ class KernelCapturedScope extends KernelScopeInfo {
}
class JsCapturedScope extends JsScopeInfo implements CapturedScope {
/// Tag used for identifying serialized [JsCapturedScope] objects in a
/// debugging data stream.
static const String tag = 'captured-scope';
final Local context;
JsCapturedScope.internal(
Iterable<Local> localsUsedInTryOrSync,
Local thisLocal,
Map<Local, JRecordField> boxedVariables,
Set<Local> freeVariables,
this.context)
: super.internal(
localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
JsCapturedScope.from(
Map<Local, JRecordField> boxedVariables,
KernelCapturedScope capturedScope,
@ -758,6 +837,31 @@ class JsCapturedScope extends JsScopeInfo implements CapturedScope {
super.from(boxedVariables, capturedScope, localsMap, elementMap);
bool get requiresContextBox => boxedVariables.isNotEmpty;
factory JsCapturedScope.readFromDataSource(DataSource source) {
source.begin(tag);
Iterable<Local> localsUsedInTryOrSync = source.readLocals();
Local thisLocal = source.readLocalOrNull();
Map<Local, JRecordField> boxedVariables =
source.readLocalMap<Local, JRecordField>(() => source.readMember());
Set<Local> freeVariables = source.readLocals().toSet();
Local context = source.readLocalOrNull();
source.end(tag);
return new JsCapturedScope.internal(localsUsedInTryOrSync, thisLocal,
boxedVariables, freeVariables, context);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.capturedScope);
sink.begin(tag);
sink.writeLocals(localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
sink.writeLocalMap(boxedVariables, sink.writeMember);
sink.writeLocals(freeVariables);
sink.writeLocalOrNull(context);
sink.end(tag);
}
}
class KernelCapturedLoopScope extends KernelCapturedScope {
@ -788,8 +892,22 @@ class KernelCapturedLoopScope extends KernelCapturedScope {
}
class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
/// Tag used for identifying serialized [JsCapturedLoopScope] objects in a
/// debugging data stream.
static const String tag = 'captured-loop-scope';
final List<Local> boxedLoopVariables;
JsCapturedLoopScope.internal(
Iterable<Local> localsUsedInTryOrSync,
Local thisLocal,
Map<Local, JRecordField> boxedVariables,
Set<Local> freeVariables,
Local context,
this.boxedLoopVariables)
: super.internal(localsUsedInTryOrSync, thisLocal, boxedVariables,
freeVariables, context);
JsCapturedLoopScope.from(
Map<Local, JRecordField> boxedVariables,
KernelCapturedLoopScope capturedScope,
@ -801,11 +919,43 @@ class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
super.from(boxedVariables, capturedScope, localsMap, elementMap);
bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
factory JsCapturedLoopScope.readFromDataSource(DataSource source) {
source.begin(tag);
Iterable<Local> localsUsedInTryOrSync = source.readLocals();
Local thisLocal = source.readLocalOrNull();
Map<Local, JRecordField> boxedVariables =
source.readLocalMap<Local, JRecordField>(() => source.readMember());
Set<Local> freeVariables = source.readLocals().toSet();
Local context = source.readLocalOrNull();
List<Local> boxedLoopVariables = source.readLocals();
source.end(tag);
return new JsCapturedLoopScope.internal(localsUsedInTryOrSync, thisLocal,
boxedVariables, freeVariables, context, boxedLoopVariables);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.capturedLoopScope);
sink.begin(tag);
sink.writeLocals(localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
sink.writeLocalMap(boxedVariables, sink.writeMember);
sink.writeLocals(freeVariables);
sink.writeLocalOrNull(context);
sink.writeLocals(boxedLoopVariables);
sink.end(tag);
}
}
// TODO(johnniwinther): Rename this class.
// TODO(johnniwinther): Add unittest for the computed [ClosureClass].
class KernelClosureClassInfo extends JsScopeInfo
implements ClosureRepresentationInfo {
/// Tag used for identifying serialized [KernelClosureClassInfo] objects in a
/// debugging data stream.
static const String tag = 'closure-representation-info';
JFunction callMethod;
JSignatureMethod signatureMethod;
final Local closureEntity;
@ -839,6 +989,47 @@ class KernelClosureClassInfo extends JsScopeInfo
: localToFieldMap = new Map<Local, JField>(),
super.from(boxedVariables, info, localsMap, elementMap);
factory KernelClosureClassInfo.readFromDataSource(DataSource source) {
source.begin(tag);
Iterable<Local> localsUsedInTryOrSync = source.readLocals();
Local thisLocal = source.readLocalOrNull();
Map<Local, JRecordField> boxedVariables =
source.readLocalMap<Local, JRecordField>(() => source.readMember());
Set<Local> freeVariables = source.readLocals().toSet();
JFunction callMethod = source.readMember();
JSignatureMethod signatureMethod = source.readMemberOrNull();
Local closureEntity = source.readLocalOrNull();
JClass closureClassEntity = source.readClass();
Map<Local, JField> localToFieldMap =
source.readLocalMap(() => source.readMember());
source.end(tag);
return new KernelClosureClassInfo.internal(
localsUsedInTryOrSync,
thisLocal,
boxedVariables,
freeVariables,
callMethod,
signatureMethod,
closureEntity,
closureClassEntity,
localToFieldMap);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.closureRepresentationInfo);
sink.begin(tag);
sink.writeLocals(localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
sink.writeLocalMap(boxedVariables, sink.writeMember);
sink.writeLocals(freeVariables);
sink.writeMember(callMethod);
sink.writeMemberOrNull(signatureMethod);
sink.writeLocalOrNull(closureEntity);
sink.writeClass(closureClassEntity);
sink.writeLocalMap(localToFieldMap, sink.writeMember);
sink.end(tag);
}
List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
@override
@ -880,9 +1071,29 @@ class NodeBox {
}
class JClosureClass extends JClass {
/// Tag used for identifying serialized [JClosureClass] objects in a
/// debugging data stream.
static const String tag = 'closure-class';
JClosureClass(JLibrary library, String name)
: super(library, name, isAbstract: false);
factory JClosureClass.readFromDataSource(DataSource source) {
source.begin(tag);
JLibrary library = source.readLibrary();
String name = source.readString();
source.end(tag);
return new JClosureClass(library, name);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassKind.closure);
sink.begin(tag);
sink.writeLibrary(library);
sink.writeString(name);
sink.end(tag);
}
@override
bool get isClosure => true;
@ -909,6 +1120,10 @@ class AnonymousClosureLocal implements Local {
}
class JClosureField extends JField implements PrivatelyNamedJSEntity {
/// Tag used for identifying serialized [JClosureClass] objects in a
/// debugging data stream.
static const String tag = 'closure-field';
final String declaredName;
JClosureField(
@ -927,12 +1142,40 @@ class JClosureField extends JField implements PrivatelyNamedJSEntity {
: super(library, enclosingClass, memberName,
isAssignable: isAssignable, isConst: isConst, isStatic: false);
factory JClosureField.readFromDataSource(DataSource source) {
source.begin(tag);
JClass cls = source.readClass();
String name = source.readString();
String declaredName = source.readString();
bool isConst = source.readBool();
bool isAssignable = source.readBool();
source.end(tag);
return new JClosureField.internal(
cls.library, cls, new Name(name, cls.library), declaredName,
isAssignable: isAssignable, isConst: isConst);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.closureField);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.writeString(name);
sink.writeString(declaredName);
sink.writeBool(isConst);
sink.writeBool(isAssignable);
sink.end(tag);
}
@override
Entity get rootOfScope => enclosingClass;
}
class RecordClassData implements JClassData {
/// Tag used for identifying serialized [RecordClassData] objects in a
/// debugging data stream.
static const String tag = 'record-class-data';
@override
final ClassDefinition definition;
@ -948,6 +1191,28 @@ class RecordClassData implements JClassData {
RecordClassData(
this.definition, this.thisType, this.supertype, this.orderedTypeSet);
factory RecordClassData.readFromDataSource(DataSource source) {
source.begin(tag);
ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
InterfaceType thisType = source.readDartType();
InterfaceType supertype = source.readDartType();
OrderedTypeSet orderedTypeSet =
new OrderedTypeSet.readFromDataSource(source);
source.end(tag);
return new RecordClassData(definition, thisType, supertype, orderedTypeSet);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassDataKind.record);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartType(thisType);
sink.writeDartType(supertype);
orderedTypeSet.writeToDataSink(sink);
sink.end(tag);
}
@override
bool get isMixinApplication => false;
@ -969,12 +1234,32 @@ class RecordClassData implements JClassData {
/// A container for variables declared in a particular scope that are accessed
/// elsewhere.
// TODO(efortuna, johnniwinther): Don't implement JClass. This isn't actually a
// TODO(johnniwinther): Don't implement JClass. This isn't actually a
// class.
class JRecord extends JClass {
/// Tag used for identifying serialized [JRecord] objects in a
/// debugging data stream.
static const String tag = 'record';
JRecord(LibraryEntity library, String name)
: super(library, name, isAbstract: false);
factory JRecord.readFromDataSource(DataSource source) {
source.begin(tag);
JLibrary library = source.readLibrary();
String name = source.readString();
source.end(tag);
return new JRecord(library, name);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassKind.record);
sink.begin(tag);
sink.writeLibrary(library);
sink.writeString(name);
sink.end(tag);
}
bool get isClosure => false;
String toString() => '${jsElementPrefix}record_container($name)';
@ -986,6 +1271,10 @@ class JRecord extends JClass {
/// This corresponds to BoxFieldElement; we reuse BoxLocal from the original
/// algorithm to correspond to the actual name of the variable.
class JRecordField extends JField {
/// Tag used for identifying serialized [JRecordField] objects in a
/// debugging data stream.
static const String tag = 'record-field';
final BoxLocal box;
JRecordField(String name, this.box, {bool isConst})
@ -993,24 +1282,92 @@ class JRecordField extends JField {
new Name(name, box.container.library),
isStatic: false, isAssignable: true, isConst: isConst);
factory JRecordField.readFromDataSource(DataSource source) {
source.begin(tag);
String name = source.readString();
JClass enclosingClass = source.readClass();
bool isConst = source.readBool();
source.end(tag);
return new JRecordField(name, new BoxLocal(enclosingClass),
isConst: isConst);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.recordField);
sink.begin(tag);
sink.writeString(name);
sink.writeClass(enclosingClass);
sink.writeBool(isConst);
sink.end(tag);
}
@override
bool get isInstanceMember => false;
}
class ClosureClassData extends RecordClassData {
/// Tag used for identifying serialized [ClosureClassData] objects in a
/// debugging data stream.
static const String tag = 'closure-class-data';
@override
FunctionType callType;
ClosureClassData(ClassDefinition definition, InterfaceType thisType,
InterfaceType supertype, OrderedTypeSet orderedTypeSet)
: super(definition, thisType, supertype, orderedTypeSet);
factory ClosureClassData.readFromDataSource(DataSource source) {
source.begin(tag);
ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
InterfaceType thisType = source.readDartType();
InterfaceType supertype = source.readDartType();
OrderedTypeSet orderedTypeSet =
new OrderedTypeSet.readFromDataSource(source);
FunctionType callType = source.readDartType();
source.end(tag);
return new ClosureClassData(definition, thisType, supertype, orderedTypeSet)
..callType = callType;
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassDataKind.closure);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartType(thisType);
sink.writeDartType(supertype);
orderedTypeSet.writeToDataSink(sink);
sink.writeDartType(callType);
sink.end(tag);
}
}
class ClosureClassDefinition implements ClassDefinition {
/// Tag used for identifying serialized [ClosureClassDefinition] objects in a
/// debugging data stream.
static const String tag = 'closure-class-definition';
final SourceSpan location;
ClosureClassDefinition(this.location);
factory ClosureClassDefinition.readFromDataSource(DataSource source) {
source.begin(tag);
SourceSpan location = source.readSourceSpan();
source.end(tag);
return new ClosureClassDefinition(location);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ClassKind.closure);
sink.begin(tag);
sink.writeSourceSpan(location);
sink.end(tag);
}
ClassKind get kind => ClassKind.closure;
ir.Node get node =>
@ -1034,6 +1391,10 @@ abstract class ClosureMemberData implements JMemberData {
class ClosureFunctionData extends ClosureMemberData
with FunctionDataMixin
implements FunctionData {
/// Tag used for identifying serialized [ClosureFunctionData] objects in a
/// debugging data stream.
static const String tag = 'closure-function-data';
final FunctionType functionType;
final ir.FunctionNode functionNode;
final ClassTypeVariableAccess classTypeVariableAccess;
@ -1046,6 +1407,31 @@ class ClosureFunctionData extends ClosureMemberData
this.classTypeVariableAccess)
: super(definition, memberThisType);
factory ClosureFunctionData.readFromDataSource(DataSource source) {
source.begin(tag);
ClosureMemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
InterfaceType memberThisType = source.readDartType(allowNull: true);
FunctionType functionType = source.readDartType();
ir.FunctionNode functionNode = source.readTreeNode();
ClassTypeVariableAccess classTypeVariableAccess =
source.readEnum(ClassTypeVariableAccess.values);
source.end(tag);
return new ClosureFunctionData(definition, memberThisType, functionType,
functionNode, classTypeVariableAccess);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.closureFunction);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartType(memberThisType, allowNull: true);
sink.writeDartType(functionType);
sink.writeTreeNode(functionNode);
sink.writeEnum(classTypeVariableAccess);
sink.end(tag);
}
void forEachParameter(JsToElementMap elementMap,
void f(DartType type, String name, ConstantValue defaultValue)) {
void handleParameter(ir.VariableDeclaration node, {bool isOptional: true}) {
@ -1078,10 +1464,32 @@ class ClosureFunctionData extends ClosureMemberData
}
class ClosureFieldData extends ClosureMemberData implements JFieldData {
/// Tag used for identifying serialized [ClosureFieldData] objects in a
/// debugging data stream.
static const String tag = 'closure-field-data';
DartType _type;
ClosureFieldData(MemberDefinition definition, InterfaceType memberThisType)
: super(definition, memberThisType);
factory ClosureFieldData.readFromDataSource(DataSource source) {
source.begin(tag);
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
InterfaceType memberThisType = source.readDartType(allowNull: true);
source.end(tag);
return new ClosureFieldData(definition, memberThisType);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.closureField);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartType(memberThisType, allowNull: true);
sink.end(tag);
}
@override
DartType getFieldType(IrToElementMap elementMap) {
if (_type != null) return _type;
@ -1142,6 +1550,10 @@ class ClosureFieldData extends ClosureMemberData implements JFieldData {
}
class ClosureMemberDefinition implements MemberDefinition {
/// Tag used for identifying serialized [ClosureMemberDefinition] objects in a
/// debugging data stream.
static const String tag = 'closure-member-definition';
final SourceSpan location;
final MemberKind kind;
final ir.TreeNode node;
@ -1150,14 +1562,50 @@ class ClosureMemberDefinition implements MemberDefinition {
: assert(
kind == MemberKind.closureCall || kind == MemberKind.closureField);
factory ClosureMemberDefinition.readFromDataSource(
DataSource source, MemberKind kind) {
source.begin(tag);
SourceSpan location = source.readSourceSpan();
ir.TreeNode node = source.readTreeNode();
source.end(tag);
return new ClosureMemberDefinition(location, kind, node);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(kind);
sink.begin(tag);
sink.writeSourceSpan(location);
sink.writeTreeNode(node);
sink.end(tag);
}
String toString() => 'ClosureMemberDefinition(kind:$kind,location:$location)';
}
class RecordContainerDefinition implements ClassDefinition {
/// Tag used for identifying serialized [RecordContainerDefinition] objects in
/// a debugging data stream.
static const String tag = 'record-definition';
final SourceSpan location;
RecordContainerDefinition(this.location);
factory RecordContainerDefinition.readFromDataSource(DataSource source) {
source.begin(tag);
SourceSpan location = source.readSourceSpan();
source.end(tag);
return new RecordContainerDefinition(location);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ClassKind.record);
sink.begin(tag);
sink.writeSourceSpan(location);
sink.end(tag);
}
ClassKind get kind => ClassKind.record;
ir.Node get node => throw new UnsupportedError(

View file

@ -18,11 +18,13 @@ import '../js_emitter/code_emitter_task.dart';
import '../js_model/closure.dart' show JRecordField, KernelScopeInfo;
import '../js_model/elements.dart' show JGeneratorBody;
import '../native/native.dart' as native;
import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../types/abstract_value_domain.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../world.dart';
import 'closure.dart';
/// Interface that translates between Kernel IR nodes and entities used for
/// global type inference and building the SSA graph for members.
@ -273,6 +275,9 @@ abstract class KernelToLocalsMap {
/// Returns the [JumpTarget] defined by the while statement [node] or `null`
/// if [node] is not a jump target.
JumpTarget getJumpTargetForWhile(ir.WhileStatement node);
/// Serializes this [KernelToLocalsMap] to [sink].
void writeToDataSink(DataSink sink);
}
/// Returns the [ir.FunctionNode] that defines [member] or `null` if [member]
@ -346,6 +351,27 @@ abstract class MemberDefinition {
/// The canonical location of [member]. This is used for sorting the members
/// in the emitted code.
SourceSpan get location;
/// Deserializes a [MemberDefinition] object from [source].
factory MemberDefinition.readFromDataSource(DataSource source) {
MemberKind kind = source.readEnum(MemberKind.values);
switch (kind) {
case MemberKind.regular:
return new RegularMemberDefinition.readFromDataSource(source);
case MemberKind.constructor:
case MemberKind.constructorBody:
case MemberKind.signature:
case MemberKind.generatorBody:
return new SpecialMemberDefinition.readFromDataSource(source, kind);
case MemberKind.closureCall:
case MemberKind.closureField:
return new ClosureMemberDefinition.readFromDataSource(source, kind);
}
throw new UnsupportedError("Unexpected MemberKind $kind");
}
/// Serializes this [MemberDefinition] to [sink].
void writeToDataSink(DataSink sink);
}
enum ClassKind {
@ -358,10 +384,29 @@ enum ClassKind {
/// A member directly defined by its [ir.Member] node.
class RegularMemberDefinition implements MemberDefinition {
/// Tag used for identifying serialized [RegularMemberDefinition] objects in a
/// debugging data stream.
static const String tag = 'regular-member-definition';
final ir.Member node;
RegularMemberDefinition(this.node);
factory RegularMemberDefinition.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
source.end(tag);
return new RegularMemberDefinition(node);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(MemberKind.regular);
sink.begin(tag);
sink.writeMemberNode(node);
sink.end(tag);
}
SourceSpan get location => computeSourceSpanFromTreeNode(node);
MemberKind get kind => MemberKind.regular;
@ -372,11 +417,31 @@ class RegularMemberDefinition implements MemberDefinition {
/// The definition of a special kind of member
class SpecialMemberDefinition implements MemberDefinition {
/// Tag used for identifying serialized [SpecialMemberDefinition] objects in a
/// debugging data stream.
static const String tag = 'special-member-definition';
final ir.TreeNode node;
final MemberKind kind;
SpecialMemberDefinition(this.node, this.kind);
factory SpecialMemberDefinition.readFromDataSource(
DataSource source, MemberKind kind) {
source.begin(tag);
ir.TreeNode node = source.readTreeNode();
source.end(tag);
return new SpecialMemberDefinition(node, kind);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(kind);
sink.begin(tag);
sink.writeTreeNode(node);
sink.end(tag);
}
SourceSpan get location => computeSourceSpanFromTreeNode(node);
String toString() => 'SpecialMemberDefinition(kind:$kind,'
@ -394,14 +459,49 @@ abstract class ClassDefinition {
/// The canonical location of [cls]. This is used for sorting the classes
/// in the emitted code.
SourceSpan get location;
/// Deserializes a [ClassDefinition] object from [source].
factory ClassDefinition.readFromDataSource(DataSource source) {
ClassKind kind = source.readEnum(ClassKind.values);
switch (kind) {
case ClassKind.regular:
return new RegularClassDefinition.readFromDataSource(source);
case ClassKind.closure:
return new ClosureClassDefinition.readFromDataSource(source);
case ClassKind.record:
return new RecordContainerDefinition.readFromDataSource(source);
}
throw new UnsupportedError("Unexpected ClassKind $kind");
}
/// Serializes this [ClassDefinition] to [sink].
void writeToDataSink(DataSink sink);
}
/// A class directly defined by its [ir.Class] node.
class RegularClassDefinition implements ClassDefinition {
/// Tag used for identifying serialized [RegularClassDefinition] objects in a
/// debugging data stream.
static const String tag = 'regular-class-definition';
final ir.Class node;
RegularClassDefinition(this.node);
factory RegularClassDefinition.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Class node = source.readClassNode();
source.end(tag);
return new RegularClassDefinition(node);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(kind);
sink.begin(tag);
sink.writeClassNode(node);
sink.end(tag);
}
SourceSpan get location => computeSourceSpanFromTreeNode(node);
ClassKind get kind => ClassKind.regular;

View file

@ -43,6 +43,7 @@ import '../kernel/kelements.dart';
import '../native/native.dart' as native;
import '../options.dart';
import '../ordered_typeset.dart';
import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@ -1442,6 +1443,23 @@ class JsEvaluationEnvironment extends EvaluationEnvironmentBase {
class JsKernelToElementMap extends JsToElementMapBase
with JsElementCreatorMixin
implements JsToWorldBuilder, JsToElementMap {
/// Tag used for identifying serialized [JsKernelToElementMap] objects in a
/// debugging data stream.
static const String tag = 'js-kernel-to-element-map';
/// Tags used for identifying serialized subsections of a
/// [JsKernelToElementMap] object in a debugging data stream.
static const String libraryTag = 'libraries';
static const String classTag = 'classes';
static const String typedefTag = 'typedefs';
static const String memberTag = 'members';
static const String typeVariableTag = 'type-variables';
static const String libraryDataTag = 'library-data';
static const String classDataTag = 'class-data';
static const String typedefDataTag = 'typedef-data';
static const String memberDataTag = 'member-data';
static const String typeVariableDataTag = 'type-variable-data';
final Map<ir.Library, IndexedLibrary> libraryMap = {};
final Map<ir.Class, IndexedClass> classMap = {};
final Map<ir.Typedef, IndexedTypedef> typedefMap = {};
@ -1574,7 +1592,6 @@ class JsKernelToElementMap extends JsToElementMapBase
assert(newTypeVariable.typeVariableIndex ==
oldTypeVariable.typeVariableIndex);
}
//typeVariableMap.keys.forEach((n) => print(n.parent));
// TODO(johnniwinther): We should close the environment in the beginning of
// this constructor but currently we need the [MemberEntity] to query if the
// member is live, thus potentially creating the [MemberEntity] in the
@ -1582,6 +1599,207 @@ class JsKernelToElementMap extends JsToElementMapBase
_elementMap.envIsClosed = true;
}
JsKernelToElementMap.readFromDataSource(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
ir.Component component,
DataSource source)
: super(options, reporter, environment) {
source.registerComponentLookup(new ComponentLookup(component));
_EntityLookup entityLookup = new _EntityLookup();
source.registerEntityLookup(entityLookup);
source.begin(tag);
source.begin(libraryTag);
int libraryCount = source.readInt();
for (int i = 0; i < libraryCount; i++) {
int index = source.readInt();
JLibrary library = new JLibrary.readFromDataSource(source);
entityLookup.registerLibrary(index, library);
}
source.end(libraryTag);
source.begin(classTag);
int classCount = source.readInt();
for (int i = 0; i < classCount; i++) {
int index = source.readInt();
JClass cls = new JClass.readFromDataSource(source);
entityLookup.registerClass(index, cls);
}
source.end(classTag);
source.begin(typedefTag);
int typedefCount = source.readInt();
for (int i = 0; i < typedefCount; i++) {
int index = source.readInt();
JTypedef typedef = new JTypedef.readFromDataSource(source);
entityLookup.registerTypedef(index, typedef);
}
source.end(typedefTag);
source.begin(memberTag);
int memberCount = source.readInt();
for (int i = 0; i < memberCount; i++) {
int index = source.readInt();
JMember member = new JMember.readFromDataSource(source);
entityLookup.registerMember(index, member);
}
source.end(memberTag);
source.begin(typeVariableTag);
int typeVariableCount = source.readInt();
for (int i = 0; i < typeVariableCount; i++) {
int index = source.readInt();
JTypeVariable typeVariable = new JTypeVariable.readFromDataSource(source);
entityLookup.registerTypeVariable(index, typeVariable);
}
source.end(typeVariableTag);
programEnv = new JProgramEnv([component]);
source.begin(libraryDataTag);
entityLookup.forEachLibrary((int index, JLibrary library) {
JLibraryEnv env = new JLibraryEnv.readFromDataSource(source);
JLibraryData data = new JLibraryData.readFromDataSource(source);
libraryMap[env.library] =
libraries.registerByIndex(index, library, data, env);
programEnv.registerLibrary(env);
assert(index == library.libraryIndex);
});
source.end(libraryDataTag);
source.begin(classDataTag);
entityLookup.forEachClass((int index, JClass cls) {
JClassEnv env = new JClassEnv.readFromDataSource(source);
JClassData data = new JClassData.readFromDataSource(source);
classMap[env.cls] = classes.registerByIndex(index, cls, data, env);
libraries.getEnv(cls.library).registerClass(cls.name, env);
assert(index == cls.classIndex);
});
source.end(classDataTag);
source.begin(typedefDataTag);
entityLookup.forEachTypedef((int index, JTypedef typedef) {
JTypedefData data = new JTypedefData.readFromDataSource(source);
typedefs.registerByIndex(index, typedef, data);
assert(index == typedef.typedefIndex);
});
source.end(typedefDataTag);
source.begin(memberDataTag);
entityLookup.forEachMember((int index, IndexedMember member) {
JMemberData data = new JMemberData.readFromDataSource(source);
members.registerByIndex(index, member, data);
switch (data.definition.kind) {
case MemberKind.regular:
case MemberKind.constructor:
ir.Member node = data.definition.node;
if (member.isField) {
fieldMap[node] = member;
} else if (member.isConstructor) {
constructorMap[node] = member;
} else {
methodMap[node] = member;
}
break;
default:
}
assert(index == member.memberIndex);
});
source.end(memberDataTag);
source.begin(typeVariableDataTag);
entityLookup.forEachTypeVariable((int index, JTypeVariable typeVariable) {
JTypeVariableData data = new JTypeVariableData.readFromDataSource(source);
typeVariableMap[data.node] =
typeVariables.registerByIndex(index, typeVariable, data);
assert(index == typeVariable.typeVariableIndex);
});
source.end(typeVariableDataTag);
source.end(tag);
}
/// Serializes this [JsToElementMap] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
// Serialize the entities before serializing the data.
sink.begin(libraryTag);
sink.writeInt(libraries.size);
libraries.forEach((JLibrary library, _, __) {
sink.writeInt(library.libraryIndex);
library.writeToDataSink(sink);
});
sink.end(libraryTag);
sink.begin(classTag);
sink.writeInt(classes.size);
classes.forEach((JClass cls, _, __) {
sink.writeInt(cls.classIndex);
cls.writeToDataSink(sink);
});
sink.end(classTag);
sink.begin(typedefTag);
sink.writeInt(typedefs.size);
typedefs.forEach((JTypedef typedef, _) {
sink.writeInt(typedef.typedefIndex);
typedef.writeToDataSink(sink);
});
sink.end(typedefTag);
sink.begin(memberTag);
sink.writeInt(members.size);
members.forEach((JMember member, _) {
sink.writeInt(member.memberIndex);
member.writeToDataSink(sink);
});
sink.end(memberTag);
sink.begin(typeVariableTag);
sink.writeInt(typeVariables.size);
typeVariables.forEach((JTypeVariable typeVariable, _) {
sink.writeInt(typeVariable.typeVariableIndex);
typeVariable.writeToDataSink(sink);
});
sink.end(typeVariableTag);
// Serialize the entity data after having serialized the entities.
sink.begin(libraryDataTag);
libraries.forEach((_, JLibraryData data, JLibraryEnv env) {
env.writeToDataSink(sink);
data.writeToDataSink(sink);
});
sink.end(libraryDataTag);
sink.begin(classDataTag);
classes.forEach((_, JClassData data, JClassEnv env) {
env.writeToDataSink(sink);
data.writeToDataSink(sink);
});
sink.end(classDataTag);
sink.begin(typedefDataTag);
typedefs.forEach((_, JTypedefData data) {
data.writeToDataSink(sink);
});
sink.end(typedefDataTag);
sink.begin(memberDataTag);
members.forEach((_, JMemberData data) {
data.writeToDataSink(sink);
});
sink.end(memberDataTag);
sink.begin(typeVariableDataTag);
typeVariables.forEach((_, JTypeVariableData data) {
data.writeToDataSink(sink);
});
sink.end(typeVariableDataTag);
sink.end(tag);
}
@override
void forEachNestedClosure(
MemberEntity member, void f(FunctionEntity closure)) {
@ -2223,3 +2441,101 @@ class JsToFrontendMapImpl extends JsToFrontendMapBase
.getEntity(indexedTypeVariable.typeVariableIndex);
}
}
/// [EntityLookup] implementation used to deserialize [JsKernelToElementMap].
///
/// Since data objects and environments are registered together with their
/// entity we need to have a separate lookup-by-index mechanism to allow for
/// index-based reference within data objects and environments.
class _EntityLookup implements EntityLookup {
final Map<int, JLibrary> _libraries = {};
final Map<int, JClass> _classes = {};
final Map<int, JTypedef> _typedefs = {};
final Map<int, JMember> _members = {};
final Map<int, JTypeVariable> _typeVariables = {};
void registerLibrary(int index, JLibrary library) {
assert(!_libraries.containsKey(index),
"Library for index $index has already been defined.");
_libraries[index] = library;
}
void registerClass(int index, JClass cls) {
assert(!_classes.containsKey(index),
"Class for index $index has already been defined.");
_classes[index] = cls;
}
void registerTypedef(int index, JTypedef typedef) {
assert(!_typedefs.containsKey(index),
"Typedef for index $index has already been defined.");
_typedefs[index] = typedef;
}
void registerMember(int index, JMember member) {
assert(!_members.containsKey(index),
"Member for index $index has already been defined.");
_members[index] = member;
}
void registerTypeVariable(int index, JTypeVariable typeVariable) {
assert(!_typeVariables.containsKey(index),
"Type variable for index $index has already been defined.");
_typeVariables[index] = typeVariable;
}
void forEachLibrary(void f(int index, JLibrary library)) {
_libraries.forEach(f);
}
void forEachClass(void f(int index, JClass cls)) {
_classes.forEach(f);
}
void forEachTypedef(void f(int index, JTypedef typedef)) {
_typedefs.forEach(f);
}
void forEachMember(void f(int index, JMember member)) {
_members.forEach(f);
}
void forEachTypeVariable(void f(int index, JTypeVariable typeVariable)) {
_typeVariables.forEach(f);
}
@override
IndexedLibrary getLibraryByIndex(int index) {
IndexedLibrary library = _libraries[index];
assert(library != null, "No library found for index $index");
return library;
}
@override
IndexedClass getClassByIndex(int index) {
IndexedClass cls = _classes[index];
assert(cls != null, "No class found for index $index");
return cls;
}
@override
IndexedTypedef getTypedefByIndex(int index) {
IndexedTypedef typedef = _typedefs[index];
assert(typedef != null, "No typedef found for index $index");
return typedef;
}
@override
IndexedMember getMemberByIndex(int index) {
IndexedMember member = _members[index];
assert(member != null, "No member found for index $index");
return member;
}
@override
IndexedTypeVariable getTypeVariableByIndex(int index) {
IndexedTypeVariable typeVariable = _typeVariables[index];
assert(typeVariable != null, "No type variable found for index $index");
return typeVariable;
}
}

View file

@ -9,7 +9,9 @@ import '../elements/entities.dart';
import '../elements/indexed.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../serialization/serialization.dart';
import '../universe/class_set.dart' show ClassHierarchyNodesMapKey;
import 'closure.dart';
/// Map from 'frontend' to 'backend' elements.
///
@ -318,15 +320,43 @@ class TypeConverter implements DartTypeVisitor<DartType, EntityConverter> {
const String jsElementPrefix = 'j:';
class JLibrary extends IndexedLibrary {
/// Tag used for identifying serialized [JLibrary] objects in a
/// debugging data stream.
static const String tag = 'library';
final String name;
final Uri canonicalUri;
JLibrary(this.name, this.canonicalUri);
/// Deserializes a [JLibrary] object from [source].
factory JLibrary.readFromDataSource(DataSource source) {
source.begin(tag);
String name = source.readString();
Uri canonicalUri = source.readUri();
source.end(tag);
return new JLibrary(name, canonicalUri);
}
/// Serializes this [JLibrary] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeString(name);
sink.writeUri(canonicalUri);
sink.end(tag);
}
String toString() => '${jsElementPrefix}library($name)';
}
/// Enum used for identifying [JClass] subclasses in serialization.
enum JClassKind { node, closure, record }
class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
/// Tag used for identifying serialized [JClass] objects in a
/// debugging data stream.
static const String tag = 'class';
final JLibrary library;
final String name;
@ -334,6 +364,35 @@ class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
JClass(this.library, this.name, {this.isAbstract});
/// Deserializes a [JClass] object from [source].
factory JClass.readFromDataSource(DataSource source) {
JClassKind kind = source.readEnum(JClassKind.values);
switch (kind) {
case JClassKind.node:
source.begin(tag);
JLibrary library = source.readLibrary();
String name = source.readString();
bool isAbstract = source.readBool();
source.end(tag);
return new JClass(library, name, isAbstract: isAbstract);
case JClassKind.closure:
return new JClosureClass.readFromDataSource(source);
case JClassKind.record:
return new JRecord.readFromDataSource(source);
}
throw new UnsupportedError("Unexpected ClassKind $kind");
}
/// Serializes this [JClass] to [sink].
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassKind.node);
sink.begin(tag);
sink.writeLibrary(library);
sink.writeString(name);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isClosure => false;
@ -341,15 +400,52 @@ class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
}
class JTypedef extends IndexedTypedef {
/// Tag used for identifying serialized [JTypedef] objects in a
/// debugging data stream.
static const String tag = 'typedef';
final JLibrary library;
final String name;
JTypedef(this.library, this.name);
/// Deserializes a [JTypedef] object from [source].
factory JTypedef.readFromDataSource(DataSource source) {
source.begin(tag);
JLibrary library = source.readLibrary();
String name = source.readString();
source.end(tag);
return new JTypedef(library, name);
}
/// Serializes this [JTypedef] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeLibrary(library);
sink.writeString(name);
sink.end(tag);
}
String toString() => '${jsElementPrefix}typedef($name)';
}
/// Enum used for identifying [JMember] subclasses in serialization.
enum JMemberKind {
generativeConstructor,
factoryConstructor,
constructorBody,
field,
getter,
setter,
method,
closureField,
closureCallMethod,
generatorBody,
signatureMethod,
recordField,
}
abstract class JMember extends IndexedMember {
final JLibrary library;
final JClass enclosingClass;
@ -359,6 +455,41 @@ abstract class JMember extends IndexedMember {
JMember(this.library, this.enclosingClass, this._name, {bool isStatic: false})
: _isStatic = isStatic;
/// Deserializes a [JMember] object from [source].
factory JMember.readFromDataSource(DataSource source) {
JMemberKind kind = source.readEnum(JMemberKind.values);
switch (kind) {
case JMemberKind.generativeConstructor:
return new JGenerativeConstructor.readFromDataSource(source);
case JMemberKind.factoryConstructor:
return new JFactoryConstructor.readFromDataSource(source);
case JMemberKind.constructorBody:
return new JConstructorBody.readFromDataSource(source);
case JMemberKind.field:
return new JField.readFromDataSource(source);
case JMemberKind.getter:
return new JGetter.readFromDataSource(source);
case JMemberKind.setter:
return new JSetter.readFromDataSource(source);
case JMemberKind.method:
return new JMethod.readFromDataSource(source);
case JMemberKind.closureField:
return new JClosureField.readFromDataSource(source);
case JMemberKind.closureCallMethod:
return new JClosureCallMethod.readFromDataSource(source);
case JMemberKind.generatorBody:
return new JGeneratorBody.readFromDataSource(source);
case JMemberKind.signatureMethod:
return new JSignatureMethod.readFromDataSource(source);
case JMemberKind.recordField:
return new JRecordField.readFromDataSource(source);
}
throw new UnsupportedError("Unexpected JMemberKind $kind");
}
/// Serializes this [JMember] to [sink].
void writeToDataSink(DataSink sink);
String get name => _name.text;
Name get memberName => _name;
@ -444,12 +575,42 @@ abstract class JConstructor extends JFunction
}
class JGenerativeConstructor extends JConstructor {
/// Tag used for identifying serialized [JGenerativeConstructor] objects in a
/// debugging data stream.
static const String tag = 'generative-constructor';
JGenerativeConstructor(
JClass enclosingClass, Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst})
: super(enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
factory JGenerativeConstructor.readFromDataSource(DataSource source) {
source.begin(tag);
JClass enclosingClass = source.readClass();
String name = source.readString();
ParameterStructure parameterStructure =
new ParameterStructure.readFromDataSource(source);
bool isExternal = source.readBool();
bool isConst = source.readBool();
source.end(tag);
return new JGenerativeConstructor(enclosingClass,
new Name(name, enclosingClass.library), parameterStructure,
isExternal: isExternal, isConst: isConst);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.generativeConstructor);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.writeString(name);
parameterStructure.writeToDataSink(sink);
sink.writeBool(isExternal);
sink.writeBool(isConst);
sink.end(tag);
}
@override
bool get isFactoryConstructor => false;
@ -458,6 +619,10 @@ class JGenerativeConstructor extends JConstructor {
}
class JFactoryConstructor extends JConstructor {
/// Tag used for identifying serialized [JFactoryConstructor] objects in a
/// debugging data stream.
static const String tag = 'factory-constructor';
@override
final bool isFromEnvironmentConstructor;
@ -467,6 +632,36 @@ class JFactoryConstructor extends JConstructor {
: super(enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
factory JFactoryConstructor.readFromDataSource(DataSource source) {
source.begin(tag);
JClass enclosingClass = source.readClass();
String name = source.readString();
ParameterStructure parameterStructure =
new ParameterStructure.readFromDataSource(source);
bool isExternal = source.readBool();
bool isConst = source.readBool();
bool isFromEnvironmentConstructor = source.readBool();
source.end(tag);
return new JFactoryConstructor(enclosingClass,
new Name(name, enclosingClass.library), parameterStructure,
isExternal: isExternal,
isConst: isConst,
isFromEnvironmentConstructor: isFromEnvironmentConstructor);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.factoryConstructor);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.writeString(name);
parameterStructure.writeToDataSink(sink);
sink.writeBool(isExternal);
sink.writeBool(isConst);
sink.writeBool(isFromEnvironmentConstructor);
sink.end(tag);
}
@override
bool get isFactoryConstructor => true;
@ -475,7 +670,11 @@ class JFactoryConstructor extends JConstructor {
}
class JConstructorBody extends JFunction implements ConstructorBodyEntity {
final ConstructorEntity constructor;
/// Tag used for identifying serialized [JConstructorBody] objects in a
/// debugging data stream.
static const String tag = 'constructor-body';
final JConstructor constructor;
JConstructorBody(this.constructor)
: super(
@ -487,10 +686,29 @@ class JConstructorBody extends JFunction implements ConstructorBodyEntity {
isStatic: false,
isExternal: false);
factory JConstructorBody.readFromDataSource(DataSource source) {
source.begin(tag);
JConstructor constructor = source.readMember();
source.end(tag);
return new JConstructorBody(constructor);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.constructorBody);
sink.begin(tag);
sink.writeMember(constructor);
sink.end(tag);
}
String get _kind => 'constructor_body';
}
class JMethod extends JFunction {
/// Tag used for identifying serialized [JMethod] objects in a
/// debugging data stream.
static const String tag = 'method';
final bool isAbstract;
JMethod(JLibrary library, JClass enclosingClass, Name name,
@ -499,6 +717,53 @@ class JMethod extends JFunction {
: super(library, enclosingClass, name, parameterStructure, asyncMarker,
isStatic: isStatic, isExternal: isExternal);
factory JMethod.readFromDataSource(DataSource source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
JLibrary library;
JClass enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary();
break;
case MemberContextKind.cls:
enclosingClass = source.readClass();
library = enclosingClass.library;
break;
}
String name = source.readString();
ParameterStructure parameterStructure =
new ParameterStructure.readFromDataSource(source);
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return new JMethod(library, enclosingClass, new Name(name, library),
parameterStructure, asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.method);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeString(name);
parameterStructure.writeToDataSink(sink);
sink.writeEnum(asyncMarker);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isFunction => true;
@ -506,7 +771,11 @@ class JMethod extends JFunction {
}
class JGeneratorBody extends JFunction {
final FunctionEntity function;
/// Tag used for identifying serialized [JGeneratorBody] objects in a
/// debugging data stream.
static const String tag = 'generator-body';
final JFunction function;
final DartType elementType;
final int hashCode;
@ -516,10 +785,31 @@ class JGeneratorBody extends JFunction {
function.parameterStructure, function.asyncMarker,
isStatic: function.isStatic, isExternal: false);
factory JGeneratorBody.readFromDataSource(DataSource source) {
source.begin(tag);
JFunction function = source.readMember();
DartType elementType = source.readDartType();
source.end(tag);
return new JGeneratorBody(function, elementType);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.generatorBody);
sink.begin(tag);
sink.writeMember(function);
sink.writeDartType(elementType);
sink.end(tag);
}
String get _kind => 'generator_body';
}
class JGetter extends JFunction {
/// Tag used for identifying serialized [JGetter] objects in a
/// debugging data stream.
static const String tag = 'getter';
final bool isAbstract;
JGetter(JLibrary library, JClass enclosingClass, Name name,
@ -529,6 +819,50 @@ class JGetter extends JFunction {
asyncMarker,
isStatic: isStatic, isExternal: isExternal);
factory JGetter.readFromDataSource(DataSource source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
JLibrary library;
JClass enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary();
break;
case MemberContextKind.cls:
enclosingClass = source.readClass();
library = enclosingClass.library;
break;
}
String name = source.readString();
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return new JGetter(
library, enclosingClass, new Name(name, library), asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.getter);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeString(name);
sink.writeEnum(asyncMarker);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isGetter => true;
@ -536,6 +870,10 @@ class JGetter extends JFunction {
}
class JSetter extends JFunction {
/// Tag used for identifying serialized [JSetter] objects in a
/// debugging data stream.
static const String tag = 'setter';
final bool isAbstract;
JSetter(JLibrary library, JClass enclosingClass, Name name,
@ -544,6 +882,47 @@ class JSetter extends JFunction {
AsyncMarker.SYNC,
isStatic: isStatic, isExternal: isExternal);
factory JSetter.readFromDataSource(DataSource source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
JLibrary library;
JClass enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary();
break;
case MemberContextKind.cls:
enclosingClass = source.readClass();
library = enclosingClass.library;
break;
}
String name = source.readString();
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return new JSetter(library, enclosingClass, new Name(name, library),
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.setter);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeString(name);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isAssignable => true;
@ -554,6 +933,10 @@ class JSetter extends JFunction {
}
class JField extends JMember implements FieldEntity, IndexedField {
/// Tag used for identifying serialized [JField] objects in a
/// debugging data stream.
static const String tag = 'field';
final bool isAssignable;
final bool isConst;
@ -561,6 +944,47 @@ class JField extends JMember implements FieldEntity, IndexedField {
{bool isStatic, this.isAssignable, this.isConst})
: super(library, enclosingClass, name, isStatic: isStatic);
factory JField.readFromDataSource(DataSource source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
JLibrary library;
JClass enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary();
break;
case MemberContextKind.cls:
enclosingClass = source.readClass();
library = enclosingClass.library;
break;
}
String name = source.readString();
bool isStatic = source.readBool();
bool isAssignable = source.readBool();
bool isConst = source.readBool();
source.end(tag);
return new JField(library, enclosingClass, new Name(name, library),
isStatic: isStatic, isAssignable: isAssignable, isConst: isConst);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.field);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeString(name);
sink.writeBool(isStatic);
sink.writeBool(isAssignable);
sink.writeBool(isConst);
sink.end(tag);
}
@override
bool get isField => true;
@ -568,33 +992,137 @@ class JField extends JMember implements FieldEntity, IndexedField {
}
class JClosureCallMethod extends JMethod {
/// Tag used for identifying serialized [JClosureCallMethod] objects in a
/// debugging data stream.
static const String tag = 'closure-call-method';
JClosureCallMethod(ClassEntity enclosingClass,
ParameterStructure parameterStructure, AsyncMarker asyncMarker)
: super(enclosingClass.library, enclosingClass, Names.call,
parameterStructure, asyncMarker,
isStatic: false, isExternal: false, isAbstract: false);
factory JClosureCallMethod.readFromDataSource(DataSource source) {
source.begin(tag);
JClass enclosingClass = source.readClass();
ParameterStructure parameterStructure =
new ParameterStructure.readFromDataSource(source);
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
source.end(tag);
return new JClosureCallMethod(
enclosingClass, parameterStructure, asyncMarker);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.closureCallMethod);
sink.begin(tag);
sink.writeClass(enclosingClass);
parameterStructure.writeToDataSink(sink);
sink.writeEnum(asyncMarker);
sink.end(tag);
}
String get _kind => 'closure_call';
}
/// A method that returns the signature of the Dart closure/tearoff that this
/// method's parent class is representing.
class JSignatureMethod extends JMethod {
/// Tag used for identifying serialized [JSignatureMethod] objects in a
/// debugging data stream.
static const String tag = 'signature-method';
JSignatureMethod(ClassEntity enclosingClass)
: super(enclosingClass.library, enclosingClass, Names.signature,
const ParameterStructure(0, 0, const [], 0), AsyncMarker.SYNC,
isStatic: false, isExternal: false, isAbstract: false);
factory JSignatureMethod.readFromDataSource(DataSource source) {
source.begin(tag);
JClass cls = source.readClass();
source.end(tag);
return new JSignatureMethod(cls);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberKind.signatureMethod);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.end(tag);
}
String get _kind => 'signature';
}
/// Enum used for identifying [JTypeVariable] variants in serialization.
enum JTypeVariableKind { cls, member, typedef, local }
class JTypeVariable extends IndexedTypeVariable {
/// Tag used for identifying serialized [JTypeVariable] objects in a
/// debugging data stream.
static const String tag = 'type-variable';
final Entity typeDeclaration;
final String name;
final int index;
JTypeVariable(this.typeDeclaration, this.name, this.index);
/// Deserializes a [JTypeVariable] object from [source].
factory JTypeVariable.readFromDataSource(DataSource source) {
source.begin(tag);
JTypeVariableKind kind = source.readEnum(JTypeVariableKind.values);
Entity typeDeclaration;
switch (kind) {
case JTypeVariableKind.cls:
typeDeclaration = source.readClass();
break;
case JTypeVariableKind.member:
typeDeclaration = source.readMember();
break;
case JTypeVariableKind.typedef:
typeDeclaration = source.readTypedef();
break;
case JTypeVariableKind.local:
// Type variables declared by local functions don't point to their
// declaration, since the corresponding closure call methods is created
// after the type variable.
// TODO(johnniwinther): Fix this.
break;
}
String name = source.readString();
int index = source.readInt();
source.end(tag);
return new JTypeVariable(typeDeclaration, name, index);
}
/// Serializes this [JTypeVariable] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
if (typeDeclaration is IndexedClass) {
IndexedClass cls = typeDeclaration;
sink.writeEnum(JTypeVariableKind.cls);
sink.writeClass(cls);
} else if (typeDeclaration is IndexedMember) {
IndexedMember member = typeDeclaration;
sink.writeEnum(JTypeVariableKind.member);
sink.writeMember(member);
} else if (typeDeclaration is IndexedTypedef) {
IndexedTypedef typedef = typeDeclaration;
sink.writeEnum(JTypeVariableKind.typedef);
sink.writeTypedef(typedef);
} else if (typeDeclaration == null) {
sink.writeEnum(JTypeVariableKind.local);
} else {
throw new UnsupportedError(
"Unexpected type variable declarer $typeDeclaration.");
}
sink.writeString(name);
sink.writeInt(index);
sink.end(tag);
}
String toString() =>
'${jsElementPrefix}type_variable(${typeDeclaration.name}.$name)';
}

View file

@ -18,14 +18,16 @@ import '../ir/visitors.dart';
import '../ir/util.dart';
import '../js_model/element_map.dart';
import '../ordered_typeset.dart';
import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import 'closure.dart';
import 'element_map.dart';
import 'element_map_impl.dart';
import 'elements.dart';
/// Environment for fast lookup of component libraries.
class JProgramEnv {
final Set<ir.Component> _components;
final Iterable<ir.Component> _components;
final Map<Uri, JLibraryEnv> _libraryMap = {};
JProgramEnv(this._components);
@ -57,6 +59,10 @@ class JProgramEnv {
/// Environment for fast lookup of library classes and members.
class JLibraryEnv {
/// Tag used for identifying serialized [JLibraryEnv] objects in a
/// debugging data stream.
static const String tag = 'library-env';
final ir.Library library;
final Map<String, JClassEnv> _classMap = {};
final Map<String, ir.Member> _memberMap;
@ -64,6 +70,27 @@ class JLibraryEnv {
JLibraryEnv(this.library, this._memberMap, this._setterMap);
/// Deserializes a [JLibraryEnv] object from [source].
factory JLibraryEnv.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Library library = source.readLibraryNode();
Map<String, ir.Member> memberMap =
source.readStringMap(source.readMemberNode);
Map<String, ir.Member> setterMap =
source.readStringMap(source.readMemberNode);
source.end(tag);
return new JLibraryEnv(library, memberMap, setterMap);
}
/// Serializes this [JLibraryEnv] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeLibraryNode(library);
sink.writeStringMap(_memberMap, sink.writeMemberNode);
sink.writeStringMap(_setterMap, sink.writeMemberNode);
sink.end(tag);
}
void registerClass(String name, JClassEnv classEnv) {
_classMap[name] = classEnv;
}
@ -96,16 +123,64 @@ class JLibraryEnv {
}
class JLibraryData {
/// Tag used for identifying serialized [JLibraryData] objects in a
/// debugging data stream.
static const String tag = 'library-data';
final ir.Library library;
// TODO(johnniwinther): Avoid direct access to [imports]. It might be null if
// it hasn't been computed for the corresponding [KLibraryData].
final Map<ir.LibraryDependency, ImportEntity> imports;
JLibraryData(this.library, this.imports);
factory JLibraryData.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Library library = source.readLibraryNode();
int importCount = source.readInt();
Map<ir.LibraryDependency, ImportEntity> imports;
if (importCount > 0) {
// TODO(johnniwinther): Deserialize imports.
}
source.end(tag);
return new JLibraryData(library, imports);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeLibraryNode(library);
if (imports == null) {
sink.writeInt(0);
} else {
sink.writeInt(imports.length);
// TODO(johnniwinther): Serialize imports.
}
sink.end(tag);
}
}
/// Enum used for identifying [JClassEnv] subclasses in serialization.
enum JClassEnvKind { node, closure, record }
/// Member data for a class.
abstract class JClassEnv {
/// Deserializes a [JClassEnv] object from [source].
factory JClassEnv.readFromDataSource(DataSource source) {
JClassEnvKind kind = source.readEnum(JClassEnvKind.values);
switch (kind) {
case JClassEnvKind.node:
return new JClassEnvImpl.readFromDataSource(source);
case JClassEnvKind.closure:
return new ClosureClassEnv.readFromDataSource(source);
case JClassEnvKind.record:
return new RecordEnv.readFromDataSource(source);
}
throw new UnsupportedError("Unsupported JClassEnvKind $kind");
}
/// Serializes this [JClassEnv] to [sink].
void writeToDataSink(DataSink sink);
/// The [ir.Class] that defined the class, if any.
ir.Class get cls;
@ -139,6 +214,10 @@ abstract class JClassEnv {
/// Environment for fast lookup of class members.
class JClassEnvImpl implements JClassEnv {
/// Tag used for identifying serialized [JClassEnv] objects in a
/// debugging data stream.
static const String tag = 'class-env';
final ir.Class cls;
final Map<String, ir.Member> _constructorMap;
final Map<String, ir.Member> _memberMap;
@ -152,6 +231,35 @@ class JClassEnvImpl implements JClassEnv {
JClassEnvImpl(this.cls, this._constructorMap, this._memberMap,
this._setterMap, this._members, this.isSuperMixinApplication);
factory JClassEnvImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Class cls = source.readClassNode();
Map<String, ir.Member> constructorMap =
source.readStringMap(source.readMemberNode);
Map<String, ir.Member> memberMap =
source.readStringMap(source.readMemberNode);
Map<String, ir.Member> setterMap =
source.readStringMap(source.readMemberNode);
List<ir.Member> members = source.readMemberNodes();
bool isSuperMixinApplication = source.readBool();
source.end(tag);
return new JClassEnvImpl(cls, constructorMap, memberMap, setterMap, members,
isSuperMixinApplication);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassEnvKind.node);
sink.begin(tag);
sink.writeClassNode(cls);
sink.writeStringMap(_constructorMap, sink.writeMemberNode);
sink.writeStringMap(_memberMap, sink.writeMemberNode);
sink.writeStringMap(_setterMap, sink.writeMemberNode);
sink.writeMemberNodes(_members);
sink.writeBool(isSuperMixinApplication);
sink.end(tag);
}
bool get isUnnamedMixinApplication => cls.isAnonymousMixin;
/// Return the [MemberEntity] for the member [name] in [cls]. If [setter] is
@ -195,10 +303,31 @@ class JClassEnvImpl implements JClassEnv {
}
class RecordEnv implements JClassEnv {
/// Tag used for identifying serialized [RecordEnv] objects in a
/// debugging data stream.
static const String tag = 'record-env';
final Map<String, IndexedMember> _memberMap;
RecordEnv(this._memberMap);
factory RecordEnv.readFromDataSource(DataSource source) {
source.begin(tag);
Map<String, IndexedMember> _memberMap =
source.readStringMap(() => source.readMember());
source.end(tag);
return new RecordEnv(_memberMap);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassEnvKind.record);
sink.begin(tag);
sink.writeStringMap(
_memberMap, (IndexedMember member) => sink.writeMember(member));
sink.end(tag);
}
@override
void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) {
// We do not create constructor bodies for containers.
@ -238,8 +367,29 @@ class RecordEnv implements JClassEnv {
}
class ClosureClassEnv extends RecordEnv {
/// Tag used for identifying serialized [ClosureClassEnv] objects in a
/// debugging data stream.
static const String tag = 'closure-class-env';
ClosureClassEnv(Map<String, MemberEntity> memberMap) : super(memberMap);
factory ClosureClassEnv.readFromDataSource(DataSource source) {
source.begin(tag);
Map<String, IndexedMember> _memberMap =
source.readStringMap(() => source.readMember());
source.end(tag);
return new ClosureClassEnv(_memberMap);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassEnvKind.closure);
sink.begin(tag);
sink.writeStringMap(
_memberMap, (IndexedMember member) => sink.writeMember(member));
sink.end(tag);
}
@override
MemberEntity lookupMember(IrToElementMap elementMap, String name,
{bool setter: false}) {
@ -251,7 +401,27 @@ class ClosureClassEnv extends RecordEnv {
}
}
/// Enum used for identifying [JClassData] subclasses in serialization.
enum JClassDataKind { node, closure, record }
abstract class JClassData {
/// Deserializes a [JClassData] object from [source].
factory JClassData.readFromDataSource(DataSource source) {
JClassDataKind kind = source.readEnum(JClassDataKind.values);
switch (kind) {
case JClassDataKind.node:
return new JClassDataImpl.readFromDataSource(source);
case JClassDataKind.closure:
return new ClosureClassData.readFromDataSource(source);
case JClassDataKind.record:
return new RecordClassData.readFromDataSource(source);
}
throw new UnsupportedError("Unexpected JClassDataKind $kind");
}
/// Serializes this [JClassData] to [sink].
void writeToDataSink(DataSink sink);
ClassDefinition get definition;
InterfaceType get thisType;
@ -267,6 +437,10 @@ abstract class JClassData {
}
class JClassDataImpl implements JClassData {
/// Tag used for identifying serialized [JClassDataImpl] objects in a
/// debugging data stream.
static const String tag = 'class-data';
final ir.Class cls;
final ClassDefinition definition;
bool isMixinApplication;
@ -281,17 +455,75 @@ class JClassDataImpl implements JClassData {
JClassDataImpl(this.cls, this.definition);
factory JClassDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Class cls = source.readClassNode();
ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
source.end(tag);
return new JClassDataImpl(cls, definition);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(JClassDataKind.node);
sink.begin(tag);
sink.writeClassNode(cls);
definition.writeToDataSink(sink);
sink.end(tag);
}
bool get isEnumClass => cls != null && cls.isEnum;
DartType get callType => null;
}
/// Enum used for identifying [JMemberData] subclasses in serialization.
enum JMemberDataKind {
function,
field,
constructor,
constructorBody,
signature,
generatorBody,
closureFunction,
closureField,
}
abstract class JMemberData {
MemberDefinition get definition;
InterfaceType getMemberThisType(JsToElementMap elementMap);
ClassTypeVariableAccess get classTypeVariableAccess;
JMemberData();
/// Deserializes a [JMemberData] object from [source].
factory JMemberData.readFromDataSource(DataSource source) {
JMemberDataKind kind = source.readEnum(JMemberDataKind.values);
switch (kind) {
case JMemberDataKind.function:
return new FunctionDataImpl.readFromDataSource(source);
case JMemberDataKind.field:
return new JFieldDataImpl.readFromDataSource(source);
case JMemberDataKind.constructor:
return new JConstructorDataImpl.readFromDataSource(source);
case JMemberDataKind.constructorBody:
return new ConstructorBodyDataImpl.readFromDataSource(source);
case JMemberDataKind.signature:
return new SignatureFunctionData.readFromDataSource(source);
case JMemberDataKind.generatorBody:
return new GeneratorBodyFunctionData.readFromDataSource(source);
case JMemberDataKind.closureFunction:
return new ClosureFunctionData.readFromDataSource(source);
case JMemberDataKind.closureField:
return new ClosureFieldData.readFromDataSource(source);
}
throw new UnsupportedError("Unexpected JMemberDataKind $kind");
}
/// Serializes this [JMemberData] to [sink].
void writeToDataSink(DataSink sink);
}
abstract class JMemberDataImpl implements JMemberData {
@ -351,6 +583,10 @@ abstract class FunctionDataMixin implements FunctionData {
class FunctionDataImpl extends JMemberDataImpl
with FunctionDataMixin
implements FunctionData {
/// Tag used for identifying serialized [FunctionDataImpl] objects in a
/// debugging data stream.
static const String tag = 'function-data';
final ir.FunctionNode functionNode;
FunctionType _type;
@ -358,6 +594,32 @@ class FunctionDataImpl extends JMemberDataImpl
ir.Member node, this.functionNode, MemberDefinition definition)
: super(node, definition);
factory FunctionDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw new UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
source.end(tag);
return new FunctionDataImpl(node, functionNode, definition);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.function);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
FunctionType getFunctionType(covariant JsToElementMapBase elementMap) {
return _type ??= elementMap.getFunctionType(functionNode);
}
@ -395,6 +657,10 @@ class FunctionDataImpl extends JMemberDataImpl
}
class SignatureFunctionData implements FunctionData {
/// Tag used for identifying serialized [SignatureFunctionData] objects in a
/// debugging data stream.
static const String tag = 'signature-function-data';
final MemberDefinition definition;
final InterfaceType memberThisType;
final ClassTypeVariableAccess classTypeVariableAccess;
@ -403,6 +669,29 @@ class SignatureFunctionData implements FunctionData {
SignatureFunctionData(this.definition, this.memberThisType,
this.typeParameters, this.classTypeVariableAccess);
factory SignatureFunctionData.readFromDataSource(DataSource source) {
source.begin(tag);
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
InterfaceType memberThisType = source.readDartType(allowNull: true);
List<ir.TypeParameter> typeParameters = source.readTypeParameterNodes();
ClassTypeVariableAccess classTypeVariableAccess =
source.readEnum(ClassTypeVariableAccess.values);
source.end(tag);
return new SignatureFunctionData(
definition, memberThisType, typeParameters, classTypeVariableAccess);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.signature);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartType(memberThisType, allowNull: true);
sink.writeTypeParameterNodes(typeParameters);
sink.writeEnum(classTypeVariableAccess);
sink.end(tag);
}
FunctionType getFunctionType(covariant JsToElementMapBase elementMap) {
throw new UnsupportedError("SignatureFunctionData.getFunctionType");
}
@ -451,9 +740,32 @@ abstract class DelegatedFunctionData implements FunctionData {
}
class GeneratorBodyFunctionData extends DelegatedFunctionData {
/// Tag used for identifying serialized [GeneratorBodyFunctionData] objects in
/// a debugging data stream.
static const String tag = 'generator-body-data';
final MemberDefinition definition;
GeneratorBodyFunctionData(FunctionData baseData, this.definition)
: super(baseData);
factory GeneratorBodyFunctionData.readFromDataSource(DataSource source) {
source.begin(tag);
// TODO(johnniwinther): Share the original base data on deserialization.
FunctionData baseData = new JMemberData.readFromDataSource(source);
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
source.end(tag);
return new GeneratorBodyFunctionData(baseData, definition);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.generatorBody);
sink.begin(tag);
baseData.writeToDataSink(sink);
definition.writeToDataSink(sink);
sink.end(tag);
}
}
abstract class JConstructorData extends FunctionData {
@ -463,6 +775,10 @@ abstract class JConstructorData extends FunctionData {
class JConstructorDataImpl extends FunctionDataImpl
implements JConstructorData {
/// Tag used for identifying serialized [JConstructorDataImpl] objects in a
/// debugging data stream.
static const String tag = 'constructor-data';
ConstantConstructor _constantConstructor;
JConstructorBody constructorBody;
@ -470,6 +786,33 @@ class JConstructorDataImpl extends FunctionDataImpl
ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition)
: super(node, functionNode, definition);
factory JConstructorDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw new UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
source.end(tag);
return new JConstructorDataImpl(node, functionNode, definition);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.constructor);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
assert(constructorBody == null);
sink.end(tag);
}
ConstantConstructor getConstructorConstant(
JsToElementMapBase elementMap, ConstructorEntity constructor) {
if (_constantConstructor == null) {
@ -492,10 +835,40 @@ class JConstructorDataImpl extends FunctionDataImpl
}
class ConstructorBodyDataImpl extends FunctionDataImpl {
/// Tag used for identifying serialized [ConstructorBodyDataImpl] objects in
/// a debugging data stream.
static const String tag = 'constructor-body-data';
ConstructorBodyDataImpl(
ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition)
: super(node, functionNode, definition);
factory ConstructorBodyDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw new UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
source.end(tag);
return new ConstructorBodyDataImpl(node, functionNode, definition);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.constructorBody);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
// TODO(johnniwinther,sra): Constructor bodies should access type variables
// through `this`.
@override
@ -518,6 +891,10 @@ abstract class JFieldData extends JMemberData {
}
class JFieldDataImpl extends JMemberDataImpl implements JFieldData {
/// Tag used for identifying serialized [JFieldDataImpl] objects in
/// a debugging data stream.
static const String tag = 'field-data';
DartType _type;
bool _isConstantComputed = false;
ConstantValue _constantValue;
@ -526,6 +903,23 @@ class JFieldDataImpl extends JMemberDataImpl implements JFieldData {
JFieldDataImpl(ir.Field node, MemberDefinition definition)
: super(node, definition);
factory JFieldDataImpl.readFromDataSource(DataSource source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
source.end(tag);
return new JFieldDataImpl(node, definition);
}
void writeToDataSink(DataSink sink) {
sink.writeEnum(JMemberDataKind.field);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
ir.Field get node => super.node;
DartType getFieldType(covariant JsToElementMapBase elementMap) {
@ -582,18 +976,52 @@ class JFieldDataImpl extends JMemberDataImpl implements JFieldData {
}
class JTypedefData {
/// Tag used for identifying serialized [JTypedefData] objects in
/// a debugging data stream.
static const String tag = 'typedef-data';
final TypedefType rawType;
JTypedefData(this.rawType);
factory JTypedefData.readFromDataSource(DataSource source) {
source.begin(tag);
TypedefType rawType = source.readDartType();
source.end(tag);
return new JTypedefData(rawType);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeDartType(rawType);
sink.end(tag);
}
}
class JTypeVariableData {
/// Tag used for identifying serialized [JTypeVariableData] objects in
/// a debugging data stream.
static const String tag = 'type-variable-data';
final ir.TypeParameter node;
DartType _bound;
DartType _defaultType;
JTypeVariableData(this.node);
factory JTypeVariableData.readFromDataSource(DataSource source) {
source.begin(tag);
ir.TypeParameter node = source.readTypeParameterNode();
source.end(tag);
return new JTypeVariableData(node);
}
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeTypeParameterNode(node);
sink.end(tag);
}
DartType getBound(IrToElementMap elementMap) {
return _bound ??= elementMap.getDartType(node.bound);
}

View file

@ -16,10 +16,12 @@ import '../compiler.dart';
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../deferred_load.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/entities.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../elements/entity_utils.dart' as utils;
import '../environment.dart';
import '../enqueue.dart';
import '../io/kernel_source_information.dart'
show KernelSourceInformationStrategy;
@ -42,6 +44,7 @@ import '../kernel/kelements.dart';
import '../native/behavior.dart';
import '../ordered_typeset.dart';
import '../options.dart';
import '../serialization/serialization.dart';
import '../ssa/builder_kernel.dart';
import '../ssa/nodes.dart';
import '../ssa/ssa.dart';
@ -64,7 +67,6 @@ import 'locals.dart';
class JsBackendStrategy implements BackendStrategy {
final Compiler _compiler;
JsKernelToElementMap _elementMap;
Sorter _sorter;
JsBackendStrategy(this._compiler);
@ -101,8 +103,8 @@ class JsBackendStrategy implements BackendStrategy {
}
@override
Sorter get sorter {
return _sorter ??= new KernelSorter(elementMap);
void registerJClosedWorld(covariant JsClosedWorld closedWorld) {
_elementMap = closedWorld.elementMap;
}
@override
@ -634,6 +636,8 @@ class JsClosedWorldBuilder {
}
class JsClosedWorld extends ClosedWorldBase {
static const String tag = 'closed-world';
final JsKernelToElementMap elementMap;
final RuntimeTypesNeed rtiNeed;
AbstractValueDomain _abstractValueDomain;
@ -642,6 +646,7 @@ class JsClosedWorld extends ClosedWorldBase {
final GlobalLocalsMap globalLocalsMap;
final ClosureData closureDataLookup;
final OutputUnitData outputUnitData;
Sorter _sorter;
JsClosedWorld(this.elementMap,
{ConstantSystem constantSystem,
@ -656,8 +661,8 @@ class JsClosedWorld extends ClosedWorldBase {
Iterable<MemberEntity> liveInstanceMembers,
Iterable<MemberEntity> assignedInstanceMembers,
Iterable<MemberEntity> processedMembers,
Map<ClassEntity, Iterable<ClassEntity>> mixinUses,
Map<ClassEntity, Iterable<ClassEntity>> typesImplementedBySubclasses,
Map<ClassEntity, Set<ClassEntity>> mixinUses,
Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses,
ClassHierarchy classHierarchy,
AbstractValueStrategy abstractValueStrategy,
this.annotationsData,
@ -684,6 +689,113 @@ class JsClosedWorld extends ClosedWorldBase {
_abstractValueDomain = abstractValueStrategy.createDomain(this);
}
/// Deserializes a [JsClosedWorld] object from [source].
factory JsClosedWorld.readFromDataSource(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
DataSource source) {
source.begin(tag);
JsKernelToElementMap elementMap =
new JsKernelToElementMap.readFromDataSource(
options, reporter, environment, component, source);
GlobalLocalsMap globalLocalsMap =
new GlobalLocalsMap.readFromDataSource(source);
source.registerLocalLookup(new LocalLookupImpl(globalLocalsMap));
ClassHierarchy classHierarchy = new ClassHierarchy.readFromDataSource(
source, elementMap.commonElements);
NativeData nativeData = new NativeData.readFromDataSource(
source, elementMap.elementEnvironment);
elementMap.nativeBasicData = nativeData;
InterceptorData interceptorData = new InterceptorData.readFromDataSource(
source, nativeData, elementMap.commonElements);
BackendUsage backendUsage = new BackendUsage.readFromDataSource(source);
RuntimeTypesNeed rtiNeed = new RuntimeTypesNeed.readFromDataSource(
source, elementMap.elementEnvironment);
JAllocatorAnalysis allocatorAnalysis =
new JAllocatorAnalysis.readFromDataSource(source, options);
NoSuchMethodData noSuchMethodData =
new NoSuchMethodData.readFromDataSource(source);
Set<ClassEntity> implementedClasses = source.readClasses().toSet();
Iterable<ClassEntity> liveNativeClasses = source.readClasses();
Iterable<MemberEntity> liveInstanceMembers = source.readMembers();
Iterable<MemberEntity> assignedInstanceMembers = source.readMembers();
Iterable<MemberEntity> processedMembers = source.readMembers();
Map<ClassEntity, Set<ClassEntity>> mixinUses =
source.readClassMap(() => source.readClasses().toSet());
Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses =
source.readClassMap(() => source.readClasses().toSet());
AnnotationsData annotationsData =
new AnnotationsData.readFromDataSource(source);
ClosureData closureData =
new ClosureData.readFromDataSource(elementMap, source);
OutputUnitData outputUnitData =
new OutputUnitData.readFromDataSource(source);
source.end(tag);
return new JsClosedWorld(elementMap,
nativeData: nativeData,
interceptorData: interceptorData,
backendUsage: backendUsage,
rtiNeed: rtiNeed,
allocatorAnalysis: allocatorAnalysis,
noSuchMethodData: noSuchMethodData,
implementedClasses: implementedClasses,
liveNativeClasses: liveNativeClasses,
liveInstanceMembers: liveInstanceMembers,
assignedInstanceMembers: assignedInstanceMembers,
processedMembers: processedMembers,
mixinUses: mixinUses,
typesImplementedBySubclasses: typesImplementedBySubclasses,
classHierarchy: classHierarchy,
abstractValueStrategy: abstractValueStrategy,
annotationsData: annotationsData,
globalLocalsMap: globalLocalsMap,
closureDataLookup: closureData,
outputUnitData: outputUnitData);
}
/// Serializes this [JsClosedWorld] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
elementMap.writeToDataSink(sink);
globalLocalsMap.writeToDataSink(sink);
classHierarchy.writeToDataSink(sink);
nativeData.writeToDataSink(sink);
interceptorData.writeToDataSink(sink);
backendUsage.writeToDataSink(sink);
rtiNeed.writeToDataSink(sink);
allocatorAnalysis.writeToDataSink(sink);
noSuchMethodData.writeToDataSink(sink);
sink.writeClasses(implementedClasses);
sink.writeClasses(liveNativeClasses);
sink.writeMembers(liveInstanceMembers);
sink.writeMembers(assignedInstanceMembers);
sink.writeMembers(processedMembers);
sink.writeClassMap(
mixinUses, (Set<ClassEntity> set) => sink.writeClasses(set));
sink.writeClassMap(typesImplementedBySubclasses,
(Set<ClassEntity> set) => sink.writeClasses(set));
annotationsData.writeToDataSink(sink);
closureDataLookup.writeToDataSink(sink);
outputUnitData.writeToDataSink(sink);
sink.end(tag);
}
@override
Sorter get sorter {
return _sorter ??= new KernelSorter(elementMap);
}
@override
AbstractValueDomain get abstractValueDomain {
return _abstractValueDomain;
@ -1236,3 +1348,16 @@ class KernelSorter implements Sorter {
a, definition1.location, b, definition2.location);
}
}
/// [LocalLookup] implementation used to deserialize [JsClosedWorld].
class LocalLookupImpl implements LocalLookup {
final GlobalLocalsMap _globalLocalsMap;
LocalLookupImpl(this._globalLocalsMap);
@override
Local getLocalByIndex(MemberEntity memberContext, int index) {
KernelToLocalsMapImpl map = _globalLocalsMap.getLocalsMap(memberContext);
return map.getLocalByIndex(index);
}
}

View file

@ -13,15 +13,60 @@ import '../elements/indexed.dart';
import '../elements/jumps.dart';
import '../elements/types.dart';
import '../ir/util.dart';
import '../serialization/serialization.dart';
import 'element_map.dart';
import 'elements.dart' show JGeneratorBody;
class GlobalLocalsMap {
/// Tag used for identifying serialized [GlobalLocalsMap] objects in a
/// debugging data stream.
static const String tag = 'global-locals-map';
final Map<MemberEntity, KernelToLocalsMap> _localsMaps;
GlobalLocalsMap() : _localsMaps = {};
GlobalLocalsMap.internal(this._localsMaps);
/// Deserializes a [GlobalLocalsMap] object from [source].
factory GlobalLocalsMap.readFromDataSource(DataSource source) {
source.begin(tag);
Map<MemberEntity, KernelToLocalsMap> _localsMaps = {};
int mapCount = source.readInt();
for (int i = 0; i < mapCount; i++) {
KernelToLocalsMap localsMap =
new KernelToLocalsMapImpl.readFromDataSource(source);
List<MemberEntity> members = source.readMembers();
for (MemberEntity member in members) {
_localsMaps[member] = localsMap;
}
}
source.end(tag);
return new GlobalLocalsMap.internal(_localsMaps);
}
/// Serializes this [GlobalLocalsMap] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
// [KernelToLocalsMap]s are shared between members and their nested
// closures, so we reverse [_localsMaps] to ensure that [KernelToLocalsMap]s
// are shared upon deserialization. The sharing is needed for correctness
// since captured variables will otherwise have distinct locals for their
// non-captured and captured uses.
Map<KernelToLocalsMap, List<MemberEntity>> reverseMap = {};
_localsMaps.forEach((MemberEntity member, KernelToLocalsMap localsMap) {
reverseMap.putIfAbsent(localsMap, () => []).add(member);
});
sink.writeInt(reverseMap.length);
reverseMap
.forEach((KernelToLocalsMap localsMap, List<MemberEntity> members) {
localsMap.writeToDataSink(sink);
sink.writeMembers(members);
});
sink.end(tag);
}
/// Returns the [KernelToLocalsMap] for [member].
KernelToLocalsMap getLocalsMap(MemberEntity member) {
// If element is a ConstructorBodyEntity, its localsMap is the same as for
@ -48,6 +93,10 @@ class GlobalLocalsMap {
}
class KernelToLocalsMapImpl implements KernelToLocalsMap {
/// Tag used for identifying serialized [KernelToLocalsMapImpl] objects in a
/// debugging data stream.
static const String tag = 'locals-map';
MemberEntity _currentMember;
final EntityDataMap<JLocal, LocalData> _locals =
new EntityDataMap<JLocal, LocalData>();
@ -56,6 +105,73 @@ class KernelToLocalsMapImpl implements KernelToLocalsMap {
Map<ir.TreeNode, JJumpTarget> _jumpTargetMap;
Iterable<ir.BreakStatement> _breaksAsContinue;
KernelToLocalsMapImpl(this._currentMember);
/// Deserializes a [KernelToLocalsMapImpl] object from [source].
KernelToLocalsMapImpl.readFromDataSource(DataSource source) {
source.begin(tag);
_currentMember = source.readMember();
int localsCount = source.readInt();
for (int i = 0; i < localsCount; i++) {
int index = source.readInt();
String name = source.readStringOrNull();
bool isRegularParameter = source.readBool();
ir.VariableDeclaration node = source.readTreeNode();
JLocal local = new JLocal(name, currentMember,
isRegularParameter: isRegularParameter);
LocalData data = new LocalData(node);
_locals.registerByIndex(index, local, data);
_variableMap[node] = local;
}
int jumpCount = source.readInt();
if (jumpCount > 0) {
_jumpTargetMap = {};
for (int i = 0; i < jumpCount; i++) {
JJumpTarget target = new JJumpTarget.readFromDataSource(source);
List<ir.TreeNode> nodes = source.readTreeNodes();
for (ir.TreeNode node in nodes) {
_jumpTargetMap[node] = target;
}
}
}
_breaksAsContinue = source.readTreeNodes();
source.end(tag);
}
/// Serializes this [KernelToLocalsMapImpl] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMember(currentMember);
sink.writeInt(_locals.size);
_locals.forEach((JLocal local, LocalData data) {
assert(local.memberContext == currentMember);
sink.writeInt(local.localIndex);
sink.writeStringOrNull(local.name);
sink.writeBool(local.isRegularParameter);
sink.writeTreeNode(data.node);
});
if (_jumpTargetMap != null) {
// [JJumpTarget]s are shared between nodes, so we reverse
// [_jumpTargetMap] to ensure that [JJumpTarget]s are shared upon
// deserialization. This sharing is needed for correctness since for
// instance a label statement containing a for loop both constitutes the
// same jump target and the SSA graph builder dependents on this property.
Map<JJumpTarget, List<ir.TreeNode>> reversedMap = {};
_jumpTargetMap.forEach((ir.TreeNode node, JJumpTarget target) {
reversedMap.putIfAbsent(target, () => []).add(node);
});
sink.writeInt(reversedMap.length);
reversedMap.forEach((JJumpTarget target, List<ir.TreeNode> nodes) {
target.writeToDataSink(sink);
sink.writeTreeNodes(nodes);
});
} else {
sink.writeInt(0);
}
sink.writeTreeNodes(_breaksAsContinue, allowNull: true);
sink.end(tag);
}
// TODO(johnniwinther): Compute this eagerly from the root of the member.
void _ensureJumpMap(ir.TreeNode node) {
if (_jumpTargetMap == null) {
@ -72,9 +188,12 @@ class KernelToLocalsMapImpl implements KernelToLocalsMap {
}
}
KernelToLocalsMapImpl(this._currentMember);
MemberEntity get currentMember => _currentMember;
Local getLocalByIndex(int index) {
return _locals.getEntity(index);
}
@override
JumpTarget getJumpTargetForBreak(ir.BreakStatement node) {
_ensureJumpMap(node.target);
@ -328,6 +447,10 @@ class JumpVisitor extends ir.Visitor {
}
class JJumpTarget extends JumpTarget {
/// Tag used for identifying serialized [JJumpTarget] objects in a
/// debugging data stream.
static const String tag = 'jump-target';
final MemberEntity memberContext;
final int nestingLevel;
List<LabelDefinition> _labels;
@ -337,6 +460,47 @@ class JJumpTarget extends JumpTarget {
JJumpTarget(this.memberContext, this.nestingLevel,
{this.isSwitch: false, this.isSwitchCase: false});
/// Deserializes a [JJumpTarget] object from [source].
factory JJumpTarget.readFromDataSource(DataSource source) {
source.begin(tag);
MemberEntity memberContext = source.readMember();
int nestingLevel = source.readInt();
bool isSwitch = source.readBool();
bool isSwitchCase = source.readBool();
JJumpTarget target = new JJumpTarget(memberContext, nestingLevel,
isSwitch: isSwitch, isSwitchCase: isSwitchCase);
int labelCount = source.readInt();
for (int i = 0; i < labelCount; i++) {
String labelName = source.readString();
bool isBreakTarget = source.readBool();
bool isContinueTarget = source.readBool();
target.addLabel(labelName,
isBreakTarget: isBreakTarget, isContinueTarget: isContinueTarget);
}
source.end(tag);
return target;
}
/// Serializes this [JJumpTarget] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeMember(memberContext);
sink.writeInt(nestingLevel);
sink.writeBool(isSwitch);
sink.writeBool(isSwitchCase);
if (_labels != null) {
sink.writeInt(_labels.length);
for (LabelDefinition definition in _labels) {
sink.writeString(definition.name);
sink.writeBool(definition.isBreakTarget);
sink.writeBool(definition.isContinueTarget);
}
} else {
sink.writeInt(0);
}
sink.end(tag);
}
bool isBreakTarget = false;
bool isContinueTarget = false;

View file

@ -399,7 +399,7 @@ class KClassEnvImpl implements KClassEnv {
}
if (!includeStatic && member.isStatic) return;
if (member.isNoSuchMethodForwarder) {
// TODO(sigmund): remove once #33665 is fixed.
// TODO(sigmund): remove once #33732 is fixed.
if (!includeNoSuchMethodForwarders ||
member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference) {

View file

@ -9,6 +9,7 @@ import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as js;
import '../js_backend/native_data.dart' show NativeBasicData;
import '../serialization/serialization.dart';
import '../universe/side_effects.dart' show SideEffects;
import 'js.dart';
@ -124,6 +125,10 @@ class NativeThrowBehavior {
* `null` may be returned.
*/
class NativeBehavior {
/// Tag used for identifying serialized [NativeBehavior] objects in a
/// debugging data stream.
static const String tag = 'native-behavior';
/// [DartType]s or [SpecialType]s returned or yielded by the native
/// element.
final List typesReturned = [];
@ -156,6 +161,88 @@ class NativeBehavior {
NativeBehavior.internal(this.sideEffects);
/// Deserializes a [NativeBehavior] object from [source].
factory NativeBehavior.readFromDataSource(DataSource source) {
source.begin(tag);
List readTypes() {
List types = [];
types.addAll(source.readDartTypes());
int specialCount = source.readInt();
for (int i = 0; i < specialCount; i++) {
String name = source.readString();
types.add(SpecialType.fromName(name));
}
return types;
}
List typesReturned = readTypes();
List typesInstantiated = readTypes();
String codeTemplateText = source.readStringOrNull();
SideEffects sideEffects = new SideEffects.readFromDataSource(source);
int throwBehavior = source.readInt();
bool isAllocation = source.readBool();
bool useGvn = source.readBool();
source.end(tag);
NativeBehavior behavior = new NativeBehavior.internal(sideEffects);
behavior.typesReturned.addAll(typesReturned);
behavior.typesInstantiated.addAll(typesInstantiated);
if (codeTemplateText != null) {
behavior.codeTemplateText = codeTemplateText;
behavior.codeTemplate = js.js.parseForeignJS(codeTemplateText);
}
switch (throwBehavior) {
case 0:
behavior.throwBehavior = NativeThrowBehavior.NEVER;
break;
case 1:
behavior.throwBehavior =
NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS;
break;
case 2:
behavior.throwBehavior = NativeThrowBehavior.MAY;
break;
case 3:
behavior.throwBehavior = NativeThrowBehavior.MUST;
break;
}
behavior.isAllocation = isAllocation;
behavior.useGvn = useGvn;
return behavior;
}
/// Serializes this [NativeBehavior] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
void writeTypes(List types) {
List<DartType> dartTypes = [];
List<SpecialType> specialTypes = [];
for (var type in types) {
if (type is DartType) {
dartTypes.add(type);
} else {
specialTypes.add(type);
}
}
sink.writeDartTypes(dartTypes);
sink.writeInt(specialTypes.length);
for (SpecialType type in specialTypes) {
sink.writeString(type.name);
}
}
writeTypes(typesReturned);
writeTypes(typesInstantiated);
sink.writeStringOrNull(codeTemplateText);
sideEffects.writeToDataSink(sink);
sink.writeInt(throwBehavior._bits);
sink.writeBool(isAllocation);
sink.writeBool(useGvn);
sink.end(tag);
}
String toString() {
return 'NativeBehavior('
'returns: ${typesReturned}'

View file

@ -11,6 +11,7 @@ import 'common.dart';
import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
import 'elements/entities.dart';
import 'elements/types.dart';
import 'serialization/serialization.dart';
/**
* An ordered set of the supertypes of a class. The supertypes of a class are
@ -30,12 +31,80 @@ import 'elements/types.dart';
* C: [C, B, A, Object]
*/
class OrderedTypeSet {
/// Tag used for identifying serialized [OrderedTypeSet] objects in a
/// debugging data stream.
static const String tag = 'ordered-type-set';
final List<Link<InterfaceType>> _levels;
final Link<InterfaceType> types;
final Link<InterfaceType> _supertypes;
OrderedTypeSet.internal(this._levels, this.types, this._supertypes);
/// Deserializes a [OrderedTypeSet] object from [source].
factory OrderedTypeSet.readFromDataSource(DataSource source) {
// TODO(johnniwinther): Make the deserialized type sets share their
// internal links like the original type sets do?
source.begin(tag);
int typesCount = source.readInt();
LinkBuilder<InterfaceType> typeLinkBuilder =
new LinkBuilder<InterfaceType>();
List<Link<InterfaceType>> links = [];
for (int i = 0; i < typesCount; i++) {
links.add(typeLinkBuilder.addLast(source.readDartType()));
}
Link<InterfaceType> types =
typeLinkBuilder.toLink(const Link<InterfaceType>());
links.add(const Link<InterfaceType>());
int supertypesCount = source.readInt();
LinkBuilder<InterfaceType> supertypeLinkBuilder =
new LinkBuilder<InterfaceType>();
for (int i = 0; i < supertypesCount; i++) {
supertypeLinkBuilder.addLast(source.readDartType());
}
Link<InterfaceType> supertypes =
supertypeLinkBuilder.toLink(const Link<InterfaceType>());
int levelCount = source.readInt();
List<Link<InterfaceType>> levels =
new List<Link<InterfaceType>>(levelCount);
for (int i = 0; i < levelCount; i++) {
levels[i] = links[source.readInt()];
}
source.end(tag);
return new OrderedTypeSet.internal(levels, types, supertypes);
}
/// Serializes this [OrderedTypeSet] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
List<InterfaceType> typeList = types.toList();
sink.writeInt(typeList.length);
for (InterfaceType type in typeList) {
sink.writeDartType(type);
}
List<InterfaceType> supertypeList = _supertypes.toList();
sink.writeInt(supertypeList.length);
for (InterfaceType supertype in supertypeList) {
sink.writeDartType(supertype);
}
List<int> levelList = [];
Link<InterfaceType> link = types;
while (link != null) {
int index = _levels.indexOf(link);
if (index != -1) {
levelList.add(index);
}
link = link.tail;
}
sink.writeInt(levelList.length);
for (int level in levelList) {
sink.writeInt(level);
}
sink.end(tag);
}
factory OrderedTypeSet.singleton(InterfaceType type) {
Link<InterfaceType> types =
new LinkEntry<InterfaceType>(type, const Link<InterfaceType>());

View file

@ -0,0 +1,332 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// Base implementation of [DataSink] using [DataSinkMixin] to implement
/// convenience methods.
abstract class AbstractDataSink extends DataSinkMixin implements DataSink {
/// If `true`, serialization of every data kind is preceded by a [DataKind]
/// value.
///
/// This is used for debugging data inconsistencies between serialization
/// and deserialization.
final bool useDataKinds;
/// Visitor used for serializing [DartType]s.
DartTypeWriter _dartTypeWriter;
/// Stack of tags used when [useDataKinds] is `true` to help debugging section
/// inconsistencies between serialization and deserialization.
List<String> _tags;
/// Map of [_MemberData] object for serialized kernel member nodes.
Map<ir.Member, _MemberData> _memberData = {};
AbstractDataSink({this.useDataKinds: false}) {
_dartTypeWriter = new DartTypeWriter(this);
}
void begin(String tag) {
if (useDataKinds) {
_tags ??= <String>[];
_tags.add(tag);
_begin(tag);
}
}
void end(Object tag) {
if (useDataKinds) {
_end(tag);
String existingTag = _tags.removeLast();
assert(existingTag == tag,
"Unexpected tag end. Expected $existingTag, found $tag.");
}
}
@override
void writeSourceSpan(SourceSpan value) {
_writeDataKind(DataKind.sourceSpan);
_writeUri(value.uri);
_writeInt(value.begin);
_writeInt(value.end);
}
@override
void writeDartType(DartType value, {bool allowNull: false}) {
_writeDataKind(DataKind.dartType);
_writeDartType(value, [], allowNull: allowNull);
}
void _writeDartType(
DartType value, List<FunctionTypeVariable> functionTypeVariables,
{bool allowNull: false}) {
if (value == null) {
if (!allowNull) {
throw new UnsupportedError("Missing DartType is not allowed.");
}
writeEnum(DartTypeKind.none);
} else {
_dartTypeWriter.visit(value, functionTypeVariables);
}
}
@override
void writeMemberNode(ir.Member value) {
_writeDataKind(DataKind.memberNode);
_writeMemberNode(value);
}
void _writeMemberNode(ir.Member value) {
ir.Class cls = value.enclosingClass;
if (cls != null) {
_writeEnum(MemberContextKind.cls);
_writeClassNode(cls);
_writeString(_computeMemberName(value));
} else {
_writeEnum(MemberContextKind.library);
_writeLibraryNode(value.enclosingLibrary);
_writeString(_computeMemberName(value));
}
}
@override
void writeClassNode(ir.Class value) {
_writeDataKind(DataKind.classNode);
_writeClassNode(value);
}
void _writeClassNode(ir.Class value) {
_writeLibraryNode(value.enclosingLibrary);
_writeString(value.name);
}
@override
void writeLibraryNode(ir.Library value) {
_writeDataKind(DataKind.libraryNode);
_writeLibraryNode(value);
}
void _writeLibraryNode(ir.Library value) {
_writeUri(value.importUri);
}
@override
void writeEnum(dynamic value) {
_writeDataKind(DataKind.enumValue);
_writeEnum(value);
}
@override
void writeBool(bool value) {
assert(value != null);
_writeDataKind(DataKind.bool);
_writeInt(value ? 1 : 0);
}
@override
void writeUri(Uri value) {
assert(value != null);
_writeDataKind(DataKind.uri);
_writeUri(value);
}
@override
void writeString(String value) {
assert(value != null);
_writeDataKind(DataKind.string);
_writeString(value);
}
@override
void writeInt(int value) {
assert(value != null);
assert(value >= 0 && value >> 30 == 0);
_writeDataKind(DataKind.int);
_writeInt(value);
}
void writeTreeNode(ir.TreeNode value) {
_writeDataKind(DataKind.treeNode);
_writeTreeNode(value);
}
void _writeTreeNode(ir.TreeNode value) {
if (value is ir.Class) {
_writeEnum(_TreeNodeKind.cls);
_writeClassNode(value);
} else if (value is ir.Member) {
_writeEnum(_TreeNodeKind.member);
_writeMemberNode(value);
} else if (value is ir.VariableDeclaration &&
value.parent is ir.FunctionDeclaration) {
_writeEnum(_TreeNodeKind.functionDeclarationVariable);
_writeTreeNode(value.parent);
} else if (value is ir.FunctionNode) {
_writeEnum(_TreeNodeKind.functionNode);
_writeFunctionNode(value);
} else if (value is ir.TypeParameter) {
_writeEnum(_TreeNodeKind.typeParameter);
_writeTypeParameter(value);
} else {
_writeEnum(_TreeNodeKind.node);
ir.TreeNode member = value;
while (member is! ir.Member) {
if (member == null) {
throw new UnsupportedError("No enclosing member of TreeNode "
"$value (${value.runtimeType})");
}
member = member.parent;
}
_writeMemberNode(member);
_MemberData memberData = _memberData[member] ??= new _MemberData(member);
int index = memberData.getIndexByTreeNode(value);
assert(index != null, "No index found for ${value.runtimeType}.");
_writeInt(index);
}
}
void _writeFunctionNode(ir.FunctionNode value) {
ir.TreeNode parent = value.parent;
if (parent is ir.Procedure) {
_writeEnum(_FunctionNodeKind.procedure);
_writeMemberNode(parent);
} else if (parent is ir.Constructor) {
_writeEnum(_FunctionNodeKind.constructor);
_writeMemberNode(parent);
} else if (parent is ir.FunctionExpression) {
_writeEnum(_FunctionNodeKind.functionExpression);
_writeTreeNode(parent);
} else if (parent is ir.FunctionDeclaration) {
_writeEnum(_FunctionNodeKind.functionDeclaration);
_writeTreeNode(parent);
} else {
throw new UnsupportedError(
"Unsupported FunctionNode parent ${parent.runtimeType}");
}
}
@override
void writeTypeParameterNode(ir.TypeParameter value) {
_writeDataKind(DataKind.typeParameterNode);
_writeTypeParameter(value);
}
void _writeTypeParameter(ir.TypeParameter value) {
ir.TreeNode parent = value.parent;
if (parent is ir.Class) {
_writeEnum(_TypeParameterKind.cls);
_writeClassNode(parent);
_writeInt(parent.typeParameters.indexOf(value));
} else if (parent is ir.FunctionNode) {
_writeEnum(_TypeParameterKind.functionNode);
_writeFunctionNode(parent);
_writeInt(parent.typeParameters.indexOf(value));
} else {
throw new UnsupportedError(
"Unsupported TypeParameter parent ${parent.runtimeType}");
}
}
void _writeDataKind(DataKind kind) {
if (useDataKinds) _writeEnum(kind);
}
void writeLibrary(IndexedLibrary value) {
writeInt(value.libraryIndex);
}
void writeClass(IndexedClass value) {
writeInt(value.classIndex);
}
void writeTypedef(IndexedTypedef value) {
writeInt(value.typedefIndex);
}
void writeMember(IndexedMember value) {
writeInt(value.memberIndex);
}
void writeLocal(Local local) {
if (local is JLocal) {
writeEnum(LocalKind.jLocal);
writeMember(local.memberContext);
writeInt(local.localIndex);
} else if (local is ThisLocal) {
writeEnum(LocalKind.thisLocal);
writeClass(local.enclosingClass);
} else if (local is BoxLocal) {
writeEnum(LocalKind.boxLocal);
writeClass(local.container);
} else if (local is AnonymousClosureLocal) {
writeEnum(LocalKind.anonymousClosureLocal);
writeClass(local.closureClass);
} else if (local is TypeVariableLocal) {
writeEnum(LocalKind.typeVariableLocal);
writeDartType(local.typeVariable);
} else {
throw new UnsupportedError("Unsupported local ${local.runtimeType}");
}
}
@override
void writeConstant(ConstantValue value) {
_writeDataKind(DataKind.constant);
_writeConstant(value);
}
void _writeConstant(ConstantValue value) {
_writeEnum(value.kind);
switch (value.kind) {
case ConstantValueKind.BOOL:
BoolConstantValue constant = value;
writeBool(constant.boolValue);
break;
case ConstantValueKind.INT:
IntConstantValue constant = value;
writeString(constant.intValue.toString());
break;
case ConstantValueKind.DOUBLE:
DoubleConstantValue constant = value;
ByteData data = new ByteData(8);
data.setFloat64(0, constant.doubleValue);
writeInt(data.getUint16(0));
writeInt(data.getUint16(2));
writeInt(data.getUint16(4));
writeInt(data.getUint16(6));
break;
case ConstantValueKind.STRING:
StringConstantValue constant = value;
writeString(constant.stringValue);
break;
case ConstantValueKind.NULL:
break;
default:
// TODO(johnniwinther): Support remaining constant values.
throw new UnsupportedError(
"Unexpected constant value kind ${value.kind}.");
}
}
/// Actual serialization of a section begin tag, implemented by subclasses.
void _begin(String tag);
/// Actual serialization of a section end tag, implemented by subclasses.
void _end(String tag);
/// Actual serialization of a URI value, implemented by subclasses.
void _writeUri(Uri value);
/// Actual serialization of a String value, implemented by subclasses.
void _writeString(String value);
/// Actual serialization of a non-negative integer value, implemented by
/// subclasses.
void _writeInt(int value);
/// Actual serialization of an enum value, implemented by subclasses.
void _writeEnum(dynamic value);
}

View file

@ -0,0 +1,418 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// Base implementation of [DataSource] using [DataSourceMixin] to implement
/// convenience methods.
abstract class AbstractDataSource extends DataSourceMixin
implements DataSource {
final bool useDataKinds;
ComponentLookup _componentLookup;
EntityLookup _entityLookup;
LocalLookup _localLookup;
AbstractDataSource({this.useDataKinds: false});
void begin(String tag) {
if (useDataKinds) _begin(tag);
}
void end(String tag) {
if (useDataKinds) _end(tag);
}
void registerComponentLookup(ComponentLookup componentLookup) {
assert(_componentLookup == null);
_componentLookup = componentLookup;
}
ComponentLookup get componentLookup {
assert(_componentLookup != null);
return _componentLookup;
}
void registerEntityLookup(EntityLookup entityLookup) {
assert(_entityLookup == null);
_entityLookup = entityLookup;
}
EntityLookup get entityLookup {
assert(_entityLookup != null);
return _entityLookup;
}
void registerLocalLookup(LocalLookup localLookup) {
assert(_localLookup == null);
_localLookup = localLookup;
}
LocalLookup get localLookup {
assert(_localLookup != null);
return _localLookup;
}
IndexedLibrary readLibrary() {
return getIndexedLibrary(readInt());
}
IndexedClass readClass() {
return getIndexedClass(readInt());
}
IndexedTypedef readTypedef() {
return getIndexedTypedef(readInt());
}
IndexedMember readMember() {
return getIndexedMember(readInt());
}
IndexedLibrary getIndexedLibrary(int libraryIndex) =>
entityLookup.getLibraryByIndex(libraryIndex);
IndexedClass getIndexedClass(int classIndex) =>
entityLookup.getClassByIndex(classIndex);
IndexedTypedef getIndexedTypedef(int typedefIndex) =>
entityLookup.getTypedefByIndex(typedefIndex);
IndexedMember getIndexedMember(int memberIndex) =>
entityLookup.getMemberByIndex(memberIndex);
IndexedTypeVariable getIndexedTypeVariable(int typeVariableIndex) =>
entityLookup.getTypeVariableByIndex(typeVariableIndex);
List<DartType> _readDartTypes(
List<FunctionTypeVariable> functionTypeVariables) {
int count = readInt();
List<DartType> types = new List<DartType>(count);
for (int index = 0; index < count; index++) {
types[index] = _readDartType(functionTypeVariables);
}
return types;
}
@override
SourceSpan readSourceSpan() {
_checkDataKind(DataKind.sourceSpan);
Uri uri = _readUri();
int begin = _readInt();
int end = _readInt();
return new SourceSpan(uri, begin, end);
}
@override
DartType readDartType({bool allowNull: false}) {
_checkDataKind(DataKind.dartType);
DartType type = _readDartType([]);
assert(type != null || allowNull);
return type;
}
DartType _readDartType(List<FunctionTypeVariable> functionTypeVariables) {
DartTypeKind kind = readEnum(DartTypeKind.values);
switch (kind) {
case DartTypeKind.none:
return null;
case DartTypeKind.voidType:
return const VoidType();
case DartTypeKind.typeVariable:
return new TypeVariableType(getIndexedTypeVariable(readInt()));
case DartTypeKind.functionTypeVariable:
int index = readInt();
assert(0 <= index && index < functionTypeVariables.length);
return functionTypeVariables[index];
case DartTypeKind.functionType:
int typeVariableCount = readInt();
List<FunctionTypeVariable> typeVariables =
new List<FunctionTypeVariable>.generate(typeVariableCount,
(int index) => new FunctionTypeVariable(index));
functionTypeVariables =
new List<FunctionTypeVariable>.from(functionTypeVariables)
..addAll(typeVariables);
for (int index = 0; index < typeVariableCount; index++) {
typeVariables[index].bound = _readDartType(functionTypeVariables);
}
DartType returnType = _readDartType(functionTypeVariables);
List<DartType> parameterTypes = _readDartTypes(functionTypeVariables);
List<DartType> optionalParameterTypes =
_readDartTypes(functionTypeVariables);
List<DartType> namedParameterTypes =
_readDartTypes(functionTypeVariables);
List<String> namedParameters =
new List<String>(namedParameterTypes.length);
for (int i = 0; i < namedParameters.length; i++) {
namedParameters[i] = readString();
}
return new FunctionType(
returnType,
parameterTypes,
optionalParameterTypes,
namedParameters,
namedParameterTypes,
typeVariables);
case DartTypeKind.interfaceType:
IndexedClass cls = getIndexedClass(readInt());
List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
return new InterfaceType(cls, typeArguments);
case DartTypeKind.typedef:
IndexedTypedef typedef = getIndexedTypedef(readInt());
List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
DartType unaliased = _readDartType(functionTypeVariables);
return new TypedefType(typedef, typeArguments, unaliased);
case DartTypeKind.dynamicType:
return const DynamicType();
case DartTypeKind.futureOr:
DartType typeArgument = _readDartType(functionTypeVariables);
return new FutureOrType(typeArgument);
}
throw new UnsupportedError("Unexpected DartTypeKind $kind");
}
_MemberData _readMemberData() {
MemberContextKind kind = _readEnum(MemberContextKind.values);
switch (kind) {
case MemberContextKind.cls:
_ClassData cls = _readClassData();
String name = _readString();
return cls.lookupMember(name);
case MemberContextKind.library:
_LibraryData library = _readLibraryData();
String name = _readString();
return library.lookupMember(name);
}
throw new UnsupportedError("Unsupported _MemberKind $kind");
}
@override
ir.Member readMemberNode() {
_checkDataKind(DataKind.memberNode);
return _readMemberData().node;
}
_ClassData _readClassData() {
_LibraryData library = _readLibraryData();
String name = _readString();
return library.lookupClass(name);
}
@override
ir.Class readClassNode() {
_checkDataKind(DataKind.classNode);
return _readClassData().node;
}
_LibraryData _readLibraryData() {
Uri canonicalUri = _readUri();
return componentLookup.getLibraryDataByUri(canonicalUri);
}
@override
ir.Library readLibraryNode() {
_checkDataKind(DataKind.libraryNode);
return _readLibraryData().node;
}
@override
E readEnum<E>(List<E> values) {
_checkDataKind(DataKind.enumValue);
return _readEnum(values);
}
@override
Uri readUri() {
_checkDataKind(DataKind.uri);
return _readUri();
}
@override
bool readBool() {
_checkDataKind(DataKind.bool);
int value = _readInt();
assert(value == 0 || value == 1);
return value == 1;
}
@override
String readString() {
_checkDataKind(DataKind.string);
return _readString();
}
@override
int readInt() {
_checkDataKind(DataKind.int);
return _readInt();
}
@override
ir.TreeNode readTreeNode() {
_checkDataKind(DataKind.treeNode);
return _readTreeNode();
}
@override
ConstantValue readConstant() {
_checkDataKind(DataKind.constant);
return _readConstant();
}
ConstantValue _readConstant() {
ConstantValueKind kind = _readEnum(ConstantValueKind.values);
ConstantValue constant;
switch (kind) {
case ConstantValueKind.BOOL:
bool value = readBool();
constant = new BoolConstantValue(value);
break;
case ConstantValueKind.INT:
BigInt value = BigInt.parse(readString());
constant = new IntConstantValue(value);
break;
case ConstantValueKind.DOUBLE:
ByteData data = new ByteData(8);
data.setUint16(0, readInt());
data.setUint16(2, readInt());
data.setUint16(4, readInt());
data.setUint16(6, readInt());
double value = data.getFloat64(0);
constant = new DoubleConstantValue(value);
break;
case ConstantValueKind.STRING:
String value = readString();
constant = new StringConstantValue(value);
break;
case ConstantValueKind.NULL:
constant = const NullConstantValue();
break;
default:
// TODO(johnniwinther): Support remaining constant values.
throw new UnsupportedError("Unexpected constant value kind ${kind}.");
}
return constant;
}
ir.TreeNode _readTreeNode() {
_TreeNodeKind kind = _readEnum(_TreeNodeKind.values);
switch (kind) {
case _TreeNodeKind.cls:
return _readClassData().node;
case _TreeNodeKind.member:
return _readMemberData().node;
case _TreeNodeKind.functionDeclarationVariable:
ir.FunctionDeclaration functionDeclaration = _readTreeNode();
return functionDeclaration.variable;
case _TreeNodeKind.functionNode:
return _readFunctionNode();
case _TreeNodeKind.typeParameter:
return _readTypeParameter();
case _TreeNodeKind.node:
_MemberData data = _readMemberData();
int index = _readInt();
ir.TreeNode treeNode = data.getTreeNodeByIndex(index);
assert(treeNode != null,
"No TreeNode found for index $index in ${data.node}.$_errorContext");
return treeNode;
}
throw new UnsupportedError("Unexpected _TreeNodeKind $kind");
}
ir.FunctionNode _readFunctionNode() {
_FunctionNodeKind kind = _readEnum(_FunctionNodeKind.values);
switch (kind) {
case _FunctionNodeKind.procedure:
ir.Procedure procedure = _readMemberData().node;
return procedure.function;
case _FunctionNodeKind.constructor:
ir.Constructor constructor = _readMemberData().node;
return constructor.function;
case _FunctionNodeKind.functionExpression:
ir.FunctionExpression functionExpression = _readTreeNode();
return functionExpression.function;
case _FunctionNodeKind.functionDeclaration:
ir.FunctionDeclaration functionDeclaration = _readTreeNode();
return functionDeclaration.function;
}
throw new UnsupportedError("Unexpected _FunctionNodeKind $kind");
}
@override
ir.TypeParameter readTypeParameterNode() {
_checkDataKind(DataKind.typeParameterNode);
return _readTypeParameter();
}
ir.TypeParameter _readTypeParameter() {
_TypeParameterKind kind = _readEnum(_TypeParameterKind.values);
switch (kind) {
case _TypeParameterKind.cls:
ir.Class cls = _readClassData().node;
return cls.typeParameters[_readInt()];
case _TypeParameterKind.functionNode:
ir.FunctionNode functionNode = _readFunctionNode();
return functionNode.typeParameters[_readInt()];
}
throw new UnsupportedError("Unexpected _TypeParameterKind kind $kind");
}
void _checkDataKind(DataKind expectedKind) {
if (!useDataKinds) return;
DataKind actualKind = _readEnum(DataKind.values);
assert(
actualKind == expectedKind,
"Invalid data kind. "
"Expected $expectedKind, found $actualKind.$_errorContext");
}
@override
Local readLocal() {
LocalKind kind = readEnum(LocalKind.values);
switch (kind) {
case LocalKind.jLocal:
MemberEntity memberContext = readMember();
int localIndex = readInt();
return localLookup.getLocalByIndex(memberContext, localIndex);
case LocalKind.thisLocal:
ClassEntity cls = readClass();
return new ThisLocal(cls);
case LocalKind.boxLocal:
ClassEntity cls = readClass();
return new BoxLocal(cls);
case LocalKind.anonymousClosureLocal:
ClassEntity cls = readClass();
return new AnonymousClosureLocal(cls);
case LocalKind.typeVariableLocal:
TypeVariableType typeVariable = readDartType();
return new TypeVariableLocal(typeVariable);
}
throw new UnsupportedError("Unexpected local kind $kind");
}
/// Actual deserialization of a section begin tag, implemented by subclasses.
void _begin(String tag);
/// Actual deserialization of a section end tag, implemented by subclasses.
void _end(String tag);
/// Actual deserialization of a string value, implemented by subclasses.
String _readString();
/// Actual deserialization of a non-negative integer value, implemented by
/// subclasses.
int _readInt();
/// Actual deserialization of a URI value, implemented by subclasses.
Uri _readUri();
/// Actual deserialization of an enum value in [values], implemented by
/// subclasses.
E _readEnum<E>(List<E> values);
/// Returns a string representation of the current state of the data source
/// useful for debugging in consistencies between serialization and
/// deserialization.
String get _errorContext;
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// [DataSink] that writes data as a sequence of bytes.
///
/// This data sink works together with [BinarySource].
class BinarySink extends AbstractDataSink {
final Sink<List<int>> sink;
BufferedSink _bufferedSink;
BinarySink(this.sink, {bool useDataKinds: false})
: _bufferedSink = new BufferedSink(sink),
super(useDataKinds: useDataKinds);
void _begin(String tag) {
// TODO(johnniwinther): Support tags in binary serialization?
}
void _end(String tag) {
// TODO(johnniwinther): Support tags in binary serialization?
}
@override
void _writeUri(Uri value) {
_writeString(value.toString());
}
@override
void _writeString(String value) {
List<int> bytes = utf8.encode(value);
_writeInt(bytes.length);
_bufferedSink.addBytes(bytes);
}
@override
void _writeInt(int value) {
assert(value >= 0 && value >> 30 == 0);
if (value < 0x80) {
_bufferedSink.addByte(value);
} else if (value < 0x4000) {
_bufferedSink.addByte2((value >> 8) | 0x80, value & 0xFF);
} else {
_bufferedSink.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF,
(value >> 8) & 0xFF, value & 0xFF);
}
}
@override
void _writeEnum(dynamic value) {
_writeInt(value.index);
}
void close() {
_bufferedSink.flushAndDestroy();
_bufferedSink = null;
sink.close();
}
}

View file

@ -0,0 +1,67 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// [DataSource] that reads data from a sequence of bytes.
///
/// This data source works together with [BinarySink].
class BinarySourceImpl extends AbstractDataSource {
int _byteOffset = 0;
final List<int> _bytes;
BinarySourceImpl(this._bytes, {bool useDataKinds: false})
: super(useDataKinds: useDataKinds);
void _begin(String tag) {}
void _end(String tag) {}
int _readByte() => _bytes[_byteOffset++];
@override
String _readString() {
int length = _readInt();
List<int> bytes = new Uint8List(length);
bytes.setRange(0, bytes.length, _bytes, _byteOffset);
_byteOffset += bytes.length;
return utf8.decode(bytes);
}
@override
int _readInt() {
var byte = _readByte();
if (byte & 0x80 == 0) {
// 0xxxxxxx
return byte;
} else if (byte & 0x40 == 0) {
// 10xxxxxx
return ((byte & 0x3F) << 8) | _readByte();
} else {
// 11xxxxxx
return ((byte & 0x3F) << 24) |
(_readByte() << 16) |
(_readByte() << 8) |
_readByte();
}
}
@override
Uri _readUri() {
String text = _readString();
return Uri.parse(text);
}
@override
E _readEnum<E>(List<E> values) {
int index = _readInt();
assert(
0 <= index && index < values.length,
"Invalid data kind index. "
"Expected one of $values, found index $index.");
return values[index];
}
@override
String get _errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
}

View file

@ -0,0 +1,176 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// Enum values used for identifying different kinds of serialized data.
///
/// This is used to for debugging data inconsistencies between serialization
/// and deserialization.
enum DataKind {
bool,
int,
string,
enumValue,
uri,
libraryNode,
classNode,
memberNode,
treeNode,
typeParameterNode,
dartType,
sourceSpan,
constant,
}
/// Enum used for identifying the enclosing entity of a member in serialization.
enum MemberContextKind { library, cls }
/// Enum used for identifying [Local] subclasses in serialization.
enum LocalKind {
jLocal,
thisLocal,
boxLocal,
anonymousClosureLocal,
typeVariableLocal,
}
/// Enum used for identifying [ir.TreeNode] subclasses in serialization.
enum _TreeNodeKind {
cls,
member,
node,
functionNode,
typeParameter,
functionDeclarationVariable
}
/// Enum used for identifying [ir.FunctionNode] context in serialization.
enum _FunctionNodeKind {
procedure,
constructor,
functionExpression,
functionDeclaration,
}
/// Enum used for identifying [ir.TypeParameter] context in serialization.
enum _TypeParameterKind {
cls,
functionNode,
}
/// Class used for encoding tags in [ObjectSink] and [ObjectSource].
class Tag {
final String value;
Tag(this.value);
int get hashCode => value.hashCode * 13;
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! Tag) return false;
return value == other.value;
}
String toString() => 'Tag($value)';
}
/// Enum used for identifying [DartType] subclasses in serialization.
enum DartTypeKind {
none,
voidType,
typeVariable,
functionTypeVariable,
functionType,
interfaceType,
typedef,
dynamicType,
futureOr
}
/// Visitor that serializes [DartType] object together with [AbstractDataSink].
class DartTypeWriter
implements DartTypeVisitor<void, List<FunctionTypeVariable>> {
final AbstractDataSink _sink;
DartTypeWriter(this._sink);
void visit(covariant DartType type,
List<FunctionTypeVariable> functionTypeVariables) =>
type.accept(this, functionTypeVariables);
void visitTypes(
List<DartType> types, List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeInt(types.length);
for (DartType type in types) {
_sink._writeDartType(type, functionTypeVariables);
}
}
void visitVoidType(covariant VoidType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.voidType);
}
void visitTypeVariableType(covariant TypeVariableType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.typeVariable);
IndexedTypeVariable typeVariable = type.element;
_sink.writeInt(typeVariable.typeVariableIndex);
}
void visitFunctionTypeVariable(covariant FunctionTypeVariable type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.functionTypeVariable);
int index = functionTypeVariables.indexOf(type);
assert(index != -1);
_sink.writeInt(index);
}
void visitFunctionType(covariant FunctionType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.functionType);
functionTypeVariables =
new List<FunctionTypeVariable>.from(functionTypeVariables)
..addAll(type.typeVariables);
_sink.writeInt(type.typeVariables.length);
for (FunctionTypeVariable variable in type.typeVariables) {
_sink._writeDartType(variable.bound, functionTypeVariables);
}
_sink._writeDartType(type.returnType, functionTypeVariables);
visitTypes(type.parameterTypes, functionTypeVariables);
visitTypes(type.optionalParameterTypes, functionTypeVariables);
visitTypes(type.namedParameterTypes, functionTypeVariables);
for (String namedParameter in type.namedParameters) {
_sink.writeString(namedParameter);
}
}
void visitInterfaceType(covariant InterfaceType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.interfaceType);
_sink.writeClass(type.element);
visitTypes(type.typeArguments, functionTypeVariables);
}
void visitTypedefType(covariant TypedefType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.typedef);
_sink.writeTypedef(type.element);
visitTypes(type.typeArguments, functionTypeVariables);
_sink._writeDartType(type.unaliased, functionTypeVariables);
}
void visitDynamicType(covariant DynamicType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.dynamicType);
}
void visitFutureOrType(covariant FutureOrType type,
List<FunctionTypeVariable> functionTypeVariables) {
_sink.writeEnum(DartTypeKind.futureOr);
_sink._writeDartType(type.typeArgument, functionTypeVariables);
}
}

View file

@ -0,0 +1,159 @@
// Copyright (c) 2018, 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.
part of 'serialization.dart';
/// Helper for looking up object library data from an [ir.Component] node.
class ComponentLookup {
final ir.Component _component;
/// Cache of [_LibraryData] for libraries in [_component].
Map<Uri, _LibraryData> _libraryMap;
ComponentLookup(this._component);
/// Returns the [_LibraryData] object for the library with the [canonicalUri].
_LibraryData getLibraryDataByUri(Uri canonicalUri) {
if (_libraryMap == null) {
_libraryMap = {};
for (ir.Library library in _component.libraries) {
_libraryMap[library.importUri] = new _LibraryData(library);
}
}
return _libraryMap[canonicalUri];
}
}
/// Returns a name uniquely identifying a member within its enclosing library
/// or class.
String _computeMemberName(ir.Member member) {
if (member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference) {
// TODO(33732): Handle noSuchMethod forwarders for private members from
// other libraries.
return null;
}
String name = member.name.name;
if (member is ir.Procedure && member.kind == ir.ProcedureKind.Setter) {
name += "=";
}
return name;
}
/// Helper for looking up classes and members from an [ir.Library] node.
class _LibraryData {
/// The [ir.Library] that defines the library.
final ir.Library node;
/// Cache of [_ClassData] for classes in this library.
Map<String, _ClassData> _classes;
/// Cache of [_MemberData] for members in this library.
Map<String, _MemberData> _members;
_LibraryData(this.node);
/// Returns the [_ClassData] for the class [name] in this library.
_ClassData lookupClass(String name) {
if (_classes == null) {
_classes = {};
for (ir.Class cls in node.classes) {
assert(!_classes.containsKey(cls.name),
"Duplicate class '${cls.name}' in $_classes trying to add $cls.");
_classes[cls.name] = new _ClassData(cls);
}
}
return _classes[name];
}
/// Returns the [_MemberData] for the member uniquely identified by [name] in
/// this library.
_MemberData lookupMember(String name) {
if (_members == null) {
_members = {};
for (ir.Member member in node.members) {
String name = _computeMemberName(member);
if (name == null) continue;
assert(!_members.containsKey(name),
"Duplicate member '$name' in $_members trying to add $member.");
_members[name] = new _MemberData(member);
}
}
return _members[name];
}
String toString() => '_LibraryData($node(${identityHashCode(node)}))';
}
/// Helper for looking up members from an [ir.Class] node.
class _ClassData {
/// The [ir.Class] that defines the class.
final ir.Class node;
/// Cache of [_MemberData] for members in this class.
Map<String, _MemberData> _members;
_ClassData(this.node);
/// Returns the [_MemberData] for the member uniquely identified by [name] in
/// this class.
_MemberData lookupMember(String name) {
if (_members == null) {
_members = {};
for (ir.Member member in node.members) {
String name = _computeMemberName(member);
if (name == null) continue;
assert(!_members.containsKey(name),
"Duplicate member '$name' in $_members trying to add $member.");
_members[name] = new _MemberData(member);
}
}
return _members[name];
}
String toString() => '_ClassData($node(${identityHashCode(node)}))';
}
/// Helper for looking up child [ir.TreeNode]s of a [ir.Member] node.
class _MemberData {
/// The [ir.Member] that defines the member.
final ir.Member node;
/// Cached index to [ir.TreeNode] map used for deserialization of
/// [ir.TreeNode]s.
Map<int, ir.TreeNode> _indexToNodeMap;
/// Cached [ir.TreeNode] to index map used for serialization of
/// [ir.TreeNode]s.
Map<ir.TreeNode, int> _nodeToIndexMap;
_MemberData(this.node);
void _ensureMaps() {
if (_indexToNodeMap == null) {
_indexToNodeMap = {};
_nodeToIndexMap = {};
node.accept(
new _TreeNodeIndexerVisitor(_indexToNodeMap, _nodeToIndexMap));
}
}
/// Returns the [ir.TreeNode] corresponding to [index] in this member.
ir.TreeNode getTreeNodeByIndex(int index) {
_ensureMaps();
ir.TreeNode treeNode = _indexToNodeMap[index];
assert(treeNode != null, "No TreeNode found for index $index in $node.");
return treeNode;
}
/// Returns the index corresponding to [ir.TreeNode] in this member.
int getIndexByTreeNode(ir.TreeNode node) {
_ensureMaps();
int index = _nodeToIndexMap[node];
assert(index != null, "No index found for ${node.runtimeType}.");
return index;
}
String toString() => '_MemberData($node(${identityHashCode(node)}))';
}

Some files were not shown because too many files have changed in this diff Show more