mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 17:31:18 +00:00
Merge commit '7fd78ed5b606e64d30ec201de9adce6fdf8856ba' into analyzer
This commit is contained in:
commit
5665636983
|
@ -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
|
||||
|
|
|
@ -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{} \{\}}.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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('''
|
||||
|
|
|
@ -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';
|
||||
|
|
48
pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
Normal file
48
pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
Normal 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>>>>'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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"}'));
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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('''
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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].
|
||||
|
|
|
@ -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)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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'''
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -758,7 +758,7 @@ foo
|
|||
Future<List<int>> bar() {}
|
||||
''', r'''
|
||||
foo
|
||||
Future<List<int>> bar() async {}
|
||||
Future<List<int>> bar(int x) {}
|
||||
''');
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
''');
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -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'));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)';
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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}'
|
||||
|
|
|
@ -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>());
|
||||
|
|
332
pkg/compiler/lib/src/serialization/abstract_sink.dart
Normal file
332
pkg/compiler/lib/src/serialization/abstract_sink.dart
Normal 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);
|
||||
}
|
418
pkg/compiler/lib/src/serialization/abstract_source.dart
Normal file
418
pkg/compiler/lib/src/serialization/abstract_source.dart
Normal 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;
|
||||
}
|
60
pkg/compiler/lib/src/serialization/binary_sink.dart
Normal file
60
pkg/compiler/lib/src/serialization/binary_sink.dart
Normal 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();
|
||||
}
|
||||
}
|
67
pkg/compiler/lib/src/serialization/binary_source.dart
Normal file
67
pkg/compiler/lib/src/serialization/binary_source.dart
Normal 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}.';
|
||||
}
|
176
pkg/compiler/lib/src/serialization/helpers.dart
Normal file
176
pkg/compiler/lib/src/serialization/helpers.dart
Normal 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);
|
||||
}
|
||||
}
|
159
pkg/compiler/lib/src/serialization/member_data.dart
Normal file
159
pkg/compiler/lib/src/serialization/member_data.dart
Normal 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
Loading…
Reference in a new issue