Version 1.9.0-dev.7.0
svn merge -r 43494:43548 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@43552 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 34531c6..9bac7d9 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -589,7 +589,8 @@
}
/**
- * Returns `true` if there is a subscription for the given [server] and [file].
+ * Returns `true` if there is a subscription for the given [service] and
+ * [file].
*/
bool hasAnalysisSubscription(AnalysisService service, String file) {
Set<String> files = analysisServices[service];
@@ -699,9 +700,7 @@
*/
void scheduleOperation(ServerOperation operation) {
addOperation(operation);
- if (!performOperationPending) {
- _schedulePerformOperation();
- }
+ _schedulePerformOperation();
}
/**
@@ -929,6 +928,15 @@
});
}
+ void test_flushResolvedUnit(String file) {
+ if (AnalysisEngine.isDartFileName(file)) {
+ AnalysisContextImpl context = getAnalysisContext(file);
+ Source source = getSource(file);
+ DartEntry dartEntry = context.getReadableSourceEntryOrNull(source);
+ dartEntry.flushAstStructures();
+ }
+ }
+
/**
* Implementation for `analysis.updateContent`.
*/
@@ -967,6 +975,7 @@
throw new AnalysisException('Illegal change type');
}
_overlayState.setContents(source, newContents);
+ // Update all contexts.
for (InternalAnalysisContext context in folderMap.values) {
if (context.handleContentsChanged(
source,
@@ -974,6 +983,28 @@
newContents,
true)) {
schedulePerformAnalysisOperation(context);
+ } else {
+ // When the client sends any change for a source, we should resend
+ // subscribed notifications, even if there were no changes in the
+ // source contents.
+ // TODO(scheglov) consider checking if there are subscriptions.
+ if (AnalysisEngine.isDartFileName(file)) {
+ CompilationUnit dartUnit =
+ context.ensureAnyResolvedDartUnit(source);
+ if (dartUnit != null) {
+ AnalysisErrorInfo errorInfo = context.getErrors(source);
+ scheduleNotificationOperations(
+ this,
+ file,
+ errorInfo.lineInfo,
+ context,
+ null,
+ dartUnit,
+ errorInfo.errors);
+ } else {
+ schedulePerformAnalysisOperation(context);
+ }
+ }
}
}
});
@@ -1008,7 +1039,9 @@
* Schedules [performOperation] exection.
*/
void _schedulePerformOperation() {
- assert(!performOperationPending);
+ if (performOperationPending) {
+ return;
+ }
/*
* TODO (danrubel) Rip out this workaround once the underlying problem
* is fixed. Currently, the VM and dart:io do not deliver content
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 07a4fdc..ec612a5 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -20,6 +20,68 @@
import 'package:analyzer/src/generated/source.dart';
+/**
+ * Schedules sending notifications for the given [file] using the resolved
+ * [resolvedDartUnit].
+ */
+void scheduleNotificationOperations(AnalysisServer server, String file,
+ LineInfo lineInfo, AnalysisContext context, CompilationUnit parsedDartUnit,
+ CompilationUnit resolvedDartUnit, List<AnalysisError> errors) {
+ // Only send notifications if the current context is the preferred
+ // context for the file. This avoids redundant notification messages
+ // being sent to the client (see dartbug.com/22210).
+ // TODO(paulberry): note that there is a small risk that this will cause
+ // notifications to be lost if the preferred context for a file changes
+ // while analysis is in progress (e.g. because the client sent an
+ // analysis.setAnalysisRoots message).
+ if (server.getAnalysisContext(file) != context) {
+ return;
+ }
+ // Dart
+ CompilationUnit dartUnit =
+ resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
+ if (resolvedDartUnit != null) {
+ if (server.hasAnalysisSubscription(
+ protocol.AnalysisService.HIGHLIGHTS,
+ file)) {
+ server.scheduleOperation(
+ new _DartHighlightsOperation(file, resolvedDartUnit));
+ }
+ if (server.hasAnalysisSubscription(
+ protocol.AnalysisService.NAVIGATION,
+ file)) {
+ server.scheduleOperation(
+ new _DartNavigationOperation(file, resolvedDartUnit));
+ }
+ if (server.hasAnalysisSubscription(
+ protocol.AnalysisService.OCCURRENCES,
+ file)) {
+ server.scheduleOperation(
+ new _DartOccurrencesOperation(file, resolvedDartUnit));
+ }
+ if (server.hasAnalysisSubscription(
+ protocol.AnalysisService.OVERRIDES,
+ file)) {
+ server.scheduleOperation(
+ new _DartOverridesOperation(file, resolvedDartUnit));
+ }
+ }
+ if (dartUnit != null) {
+ if (server.hasAnalysisSubscription(
+ protocol.AnalysisService.OUTLINE,
+ file)) {
+ server.scheduleOperation(
+ new _DartOutlineOperation(file, lineInfo, dartUnit));
+ }
+ }
+ // errors
+ if (server.shouldSendErrorsNotificationFor(file)) {
+ server.scheduleOperation(
+ new _NotificationErrorsOperation(file, lineInfo, errors));
+ }
+}
+
+
void sendAnalysisNotificationErrors(AnalysisServer server, String file,
LineInfo lineInfo, List<AnalysisError> errors) {
try {
@@ -173,61 +235,17 @@
ChangeNotice notice = notices[i];
Source source = notice.source;
String file = source.fullName;
- // Only send notifications if the current context is the preferred
- // context for the file. This avoids redundant notification messages
- // being sent to the client (see dartbug.com/22210).
- // TODO(paulberry): note that there is a small risk that this will cause
- // notifications to be lost if the preferred context for a file changes
- // while analysis is in progress (e.g. because the client sent an
- // analysis.setAnalysisRoots message).
- if (server.getAnalysisContext(file) != context) {
- continue;
- }
// Dart
CompilationUnit parsedDartUnit = notice.parsedDartUnit;
CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
- CompilationUnit dartUnit =
- resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
- if (resolvedDartUnit != null) {
- if (server.hasAnalysisSubscription(
- protocol.AnalysisService.HIGHLIGHTS,
- file)) {
- server.addOperation(
- new _DartHighlightsOperation(file, resolvedDartUnit));
- }
- if (server.hasAnalysisSubscription(
- protocol.AnalysisService.NAVIGATION,
- file)) {
- server.addOperation(
- new _DartNavigationOperation(file, resolvedDartUnit));
- }
- if (server.hasAnalysisSubscription(
- protocol.AnalysisService.OCCURRENCES,
- file)) {
- server.addOperation(
- new _DartOccurrencesOperation(file, resolvedDartUnit));
- }
- if (server.hasAnalysisSubscription(
- protocol.AnalysisService.OVERRIDES,
- file)) {
- server.addOperation(
- new _DartOverridesOperation(file, resolvedDartUnit));
- }
- }
- if (dartUnit != null) {
- if (server.hasAnalysisSubscription(
- protocol.AnalysisService.OUTLINE,
- file)) {
- LineInfo lineInfo = notice.lineInfo;
- server.addOperation(
- new _DartOutlineOperation(file, lineInfo, dartUnit));
- }
- }
- // errors
- if (server.shouldSendErrorsNotificationFor(file)) {
- server.addOperation(
- new _NotificationErrorsOperation(file, notice.lineInfo, notice.errors));
- }
+ scheduleNotificationOperations(
+ server,
+ file,
+ notice.lineInfo,
+ context,
+ parsedDartUnit,
+ resolvedDartUnit,
+ notice.errors);
// done
server.fileAnalyzed(notice);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
index 53ef0ec..8121738 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
@@ -185,7 +185,7 @@
completion.write(')');
CompletionSuggestion suggestion = new CompletionSuggestion(
CompletionSuggestionKind.ARGUMENT_LIST,
- COMPLETION_RELEVANCE_HIGH,
+ DART_RELEVANCE_HIGH,
completion.toString(),
completion.length,
0,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
index 5435730..0e72827 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
@@ -178,7 +178,7 @@
if (elem is ClassElement) {
importedClassMap[name] = elem;
}
- _addSuggestion(elem, COMPLETION_RELEVANCE_DEFAULT);
+ _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
});
}
@@ -202,7 +202,7 @@
if (elem is ClassElement) {
importedClassMap[name] = elem;
}
- _addSuggestion(elem, COMPLETION_RELEVANCE_DEFAULT);
+ _addSuggestion(elem, DART_RELEVANCE_DEFAULT);
});
} else {
// Exclude elements from prefixed imports
@@ -230,7 +230,7 @@
if (completion != null && completion.length > 0) {
suggestion = new CompletionSuggestion(
CompletionSuggestionKind.INVOCATION,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
completion,
completion.length,
0,
@@ -258,7 +258,7 @@
element.isPublic &&
!excludedLibs.contains(element.library) &&
!_importedCompletions.contains(element.displayName)) {
- _addSuggestion(element, COMPLETION_RELEVANCE_LOW);
+ _addSuggestion(element, DART_RELEVANCE_LOW);
}
}
});
@@ -334,7 +334,7 @@
@override
void visitClassElement(ClassElement element) {
- cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+ cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
}
@override
@@ -349,16 +349,16 @@
@override
void visitFunctionElement(FunctionElement element) {
- cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+ cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
}
@override
void visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
- cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+ cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
}
@override
void visitTopLevelVariableElement(TopLevelVariableElement element) {
- cache._addSuggestion(element, COMPLETION_RELEVANCE_DEFAULT);
+ cache._addSuggestion(element, DART_RELEVANCE_DEFAULT);
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 44eacd6..54bb27d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -23,12 +23,21 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/scanner.dart';
-// TODO (danrubel) these are temporary constants as we transition completion
-// relevance from CompletionRelevance.LOW/DEFAULT/HIGH to int.
-// These should be removed in a subsequent CL
-const int COMPLETION_RELEVANCE_LOW = 500;
-const int COMPLETION_RELEVANCE_DEFAULT = 1000;
-const int COMPLETION_RELEVANCE_HIGH = 2000;
+// Relevance highest to lowest
+const int DART_RELEVANCE_HIGH = 2000;
+const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
+const int DART_RELEVANCE_PARAMETER = 1059;
+const int DART_RELEVANCE_INHERITED_FIELD = 1058;
+const int DART_RELEVANCE_LOCAL_FIELD = 1058;
+const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
+const int DART_RELEVANCE_INHERITED_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
+const int DART_RELEVANCE_LOCAL_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
+const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
+const int DART_RELEVANCE_KEYWORD = 1055;
+const int DART_RELEVANCE_DEFAULT = 1000;
+const int DART_RELEVANCE_LOW = 500;
/**
* The base class for computing code completion suggestions.
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
index edbdd8e..7291fc6 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
@@ -111,7 +111,8 @@
/**
* Add imported element suggestions.
*/
- void _addElementSuggestions(List<Element> elements) {
+ void _addElementSuggestions(List<Element> elements, {int relevance:
+ DART_RELEVANCE_DEFAULT}) {
elements.forEach((Element elem) {
if (elem is! ClassElement) {
if (typesOnly) {
@@ -126,7 +127,7 @@
}
}
}
- addSuggestion(elem);
+ addSuggestion(elem, relevance: relevance);
});
}
@@ -149,14 +150,26 @@
String name = inheritedTypes.removeLast();
ClassElement elem = cache.importedClassMap[name];
if (visited.add(name) && elem != null) {
- _addElementSuggestions(elem.fields);
- _addElementSuggestions(elem.accessors);
- _addElementSuggestions(elem.methods);
+ _addElementSuggestions(
+ elem.fields,
+ relevance: DART_RELEVANCE_INHERITED_FIELD);
+ _addElementSuggestions(
+ elem.accessors,
+ relevance: DART_RELEVANCE_INHERITED_ACCESSOR);
+ _addElementSuggestions(
+ elem.methods,
+ relevance: DART_RELEVANCE_INHERITED_METHOD);
elem.allSupertypes.forEach((InterfaceType type) {
if (visited.add(type.name) && type.element != null) {
- _addElementSuggestions(type.element.fields);
- _addElementSuggestions(type.element.accessors);
- _addElementSuggestions(type.element.methods);
+ _addElementSuggestions(
+ type.element.fields,
+ relevance: DART_RELEVANCE_INHERITED_FIELD);
+ _addElementSuggestions(
+ type.element.accessors,
+ relevance: DART_RELEVANCE_INHERITED_ACCESSOR);
+ _addElementSuggestions(
+ type.element.methods,
+ relevance: DART_RELEVANCE_INHERITED_METHOD);
}
});
}
@@ -185,7 +198,7 @@
request.suggestions.add(suggestion);
}
} else {
- if (suggestion.relevance != COMPLETION_RELEVANCE_LOW) {
+ if (suggestion.relevance != DART_RELEVANCE_LOW) {
request.suggestions.add(suggestion);
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
index 6d7dd95..9913a63 100644
--- a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
@@ -144,9 +144,15 @@
if (node is PrefixedIdentifier) {
SimpleIdentifier prefix = node.prefix;
if (prefix != null) {
- Element element = prefix.bestElement;
- if (element != null) {
- return element.accept(this);
+ if (prefix.propagatedType != null) {
+ InterfaceTypeSuggestionBuilder.suggestionsFor(
+ request,
+ prefix.propagatedType);
+ } else {
+ Element element = prefix.bestElement;
+ if (element != null) {
+ return element.accept(this);
+ }
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
index a222062..b9588be 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
@@ -116,18 +116,18 @@
if (firstDirective is! LibraryDirective) {
if (firstDirective != null) {
if (request.offset <= firstDirective.offset) {
- _addSuggestions([Keyword.LIBRARY], COMPLETION_RELEVANCE_HIGH);
+ _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
}
} else {
if (request.offset <= startOfDeclarations) {
- _addSuggestions([Keyword.LIBRARY], COMPLETION_RELEVANCE_HIGH);
+ _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
}
}
}
if (request.offset <= startOfDeclarations) {
_addSuggestions(
[Keyword.EXPORT, Keyword.IMPORT, Keyword.PART],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
if (request.offset >= endOfDirectives) {
_addSuggestions(
@@ -138,7 +138,7 @@
Keyword.FINAL,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
}
@@ -190,17 +190,17 @@
// Very simplistic suggestion because analyzer will warn if
// the extends / with / implements keywords are out of order
if (node.extendsClause == null) {
- _addSuggestion(Keyword.EXTENDS, COMPLETION_RELEVANCE_HIGH);
+ _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH);
} else if (node.withClause == null) {
- _addSuggestion(Keyword.WITH, COMPLETION_RELEVANCE_HIGH);
+ _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH);
}
if (node.implementsClause == null) {
- _addSuggestion(Keyword.IMPLEMENTS, COMPLETION_RELEVANCE_HIGH);
+ _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
}
}
void _addSuggestion(Keyword keyword, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
+ DART_RELEVANCE_DEFAULT]) {
String completion = keyword.syntax;
request.suggestions.add(
new CompletionSuggestion(
@@ -214,7 +214,7 @@
}
void _addSuggestions(List<Keyword> keywords, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
+ DART_RELEVANCE_KEYWORD]) {
keywords.forEach((Keyword keyword) {
_addSuggestion(keyword, relevance);
});
diff --git a/pkg/analysis_server/lib/src/services/completion/local_computer.dart b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
index 0460537..4a7584f 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
@@ -160,7 +160,7 @@
if (completion != null && completion.length > 0 && completion != '_') {
CompletionSuggestion suggestion = new CompletionSuggestion(
CompletionSuggestionKind.IDENTIFIER,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
completion,
completion.length,
0,
@@ -207,8 +207,11 @@
@override
void declaredClass(ClassDeclaration declaration) {
bool isDeprecated = _isDeprecated(declaration);
- CompletionSuggestion suggestion =
- _addSuggestion(declaration.name, NO_RETURN_TYPE, isDeprecated);
+ CompletionSuggestion suggestion = _addSuggestion(
+ declaration.name,
+ NO_RETURN_TYPE,
+ isDeprecated,
+ DART_RELEVANCE_DEFAULT);
if (suggestion != null) {
suggestion.element = _createElement(
protocol.ElementKind.CLASS,
@@ -222,8 +225,11 @@
@override
void declaredClassTypeAlias(ClassTypeAlias declaration) {
bool isDeprecated = _isDeprecated(declaration);
- CompletionSuggestion suggestion =
- _addSuggestion(declaration.name, NO_RETURN_TYPE, isDeprecated);
+ CompletionSuggestion suggestion = _addSuggestion(
+ declaration.name,
+ NO_RETURN_TYPE,
+ isDeprecated,
+ DART_RELEVANCE_DEFAULT);
if (suggestion != null) {
suggestion.element = _createElement(
protocol.ElementKind.CLASS_TYPE_ALIAS,
@@ -241,8 +247,12 @@
}
bool isDeprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl);
TypeName type = fieldDecl.fields.type;
- CompletionSuggestion suggestion =
- _addSuggestion(varDecl.name, type, isDeprecated, classDecl: fieldDecl.parent);
+ CompletionSuggestion suggestion = _addSuggestion(
+ varDecl.name,
+ type,
+ isDeprecated,
+ DART_RELEVANCE_LOCAL_FIELD,
+ classDecl: fieldDecl.parent);
if (suggestion != null) {
suggestion.element = _createElement(
protocol.ElementKind.FIELD,
@@ -260,22 +270,29 @@
TypeName returnType = declaration.returnType;
bool isDeprecated = _isDeprecated(declaration);
protocol.ElementKind kind;
+ int defaultRelevance = DART_RELEVANCE_DEFAULT;
if (declaration.isGetter) {
kind = protocol.ElementKind.GETTER;
+ defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
} else if (declaration.isSetter) {
if (excludeVoidReturn) {
return;
}
kind = protocol.ElementKind.SETTER;
returnType = NO_RETURN_TYPE;
+ defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
} else {
if (excludeVoidReturn && _isVoid(returnType)) {
return;
}
kind = protocol.ElementKind.FUNCTION;
+ defaultRelevance = DART_RELEVANCE_LOCAL_FUNCTION;
}
- CompletionSuggestion suggestion =
- _addSuggestion(declaration.name, returnType, isDeprecated);
+ CompletionSuggestion suggestion = _addSuggestion(
+ declaration.name,
+ returnType,
+ isDeprecated,
+ defaultRelevance);
if (suggestion != null) {
FormalParameterList param = declaration.functionExpression.parameters;
suggestion.element = _createElement(
@@ -296,8 +313,11 @@
void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
bool isDeprecated = _isDeprecated(declaration);
TypeName returnType = declaration.returnType;
- CompletionSuggestion suggestion =
- _addSuggestion(declaration.name, returnType, isDeprecated);
+ CompletionSuggestion suggestion = _addSuggestion(
+ declaration.name,
+ returnType,
+ isDeprecated,
+ DART_RELEVANCE_DEFAULT);
if (suggestion != null) {
// TODO (danrubel) determine parameters and return type
suggestion.element = _createElement(
@@ -319,7 +339,8 @@
if (typesOnly) {
return;
}
- CompletionSuggestion suggestion = _addSuggestion(name, type, false);
+ CompletionSuggestion suggestion =
+ _addSuggestion(name, type, false, DART_RELEVANCE_LOCAL_VARIABLE);
if (suggestion != null) {
suggestion.element =
_createElement(protocol.ElementKind.LOCAL_VARIABLE, name, returnType: type);
@@ -334,27 +355,32 @@
protocol.ElementKind kind;
String parameters;
TypeName returnType = declaration.returnType;
+ int defaultRelevance = DART_RELEVANCE_DEFAULT;
if (declaration.isGetter) {
kind = protocol.ElementKind.GETTER;
parameters = null;
+ defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
} else if (declaration.isSetter) {
if (excludeVoidReturn) {
return;
}
kind = protocol.ElementKind.SETTER;
returnType = NO_RETURN_TYPE;
+ defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR;
} else {
if (excludeVoidReturn && _isVoid(returnType)) {
return;
}
kind = protocol.ElementKind.METHOD;
parameters = declaration.parameters.toSource();
+ defaultRelevance = DART_RELEVANCE_LOCAL_METHOD;
}
bool isDeprecated = _isDeprecated(declaration);
CompletionSuggestion suggestion = _addSuggestion(
declaration.name,
returnType,
isDeprecated,
+ defaultRelevance,
classDecl: declaration.parent);
if (suggestion != null) {
suggestion.element = _createElement(
@@ -375,7 +401,8 @@
if (typesOnly) {
return;
}
- CompletionSuggestion suggestion = _addSuggestion(name, type, false);
+ CompletionSuggestion suggestion =
+ _addSuggestion(name, type, false, DART_RELEVANCE_PARAMETER);
if (suggestion != null) {
suggestion.element =
_createElement(protocol.ElementKind.PARAMETER, name, returnType: type);
@@ -389,8 +416,11 @@
return;
}
bool isDeprecated = _isDeprecated(varList) || _isDeprecated(varDecl);
- CompletionSuggestion suggestion =
- _addSuggestion(varDecl.name, varList.type, isDeprecated);
+ CompletionSuggestion suggestion = _addSuggestion(
+ varDecl.name,
+ varList.type,
+ isDeprecated,
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
if (suggestion != null) {
suggestion.element = _createElement(
protocol.ElementKind.TOP_LEVEL_VARIABLE,
@@ -436,13 +466,13 @@
}
CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName returnType,
- bool isDeprecated, {ClassDeclaration classDecl}) {
+ bool isDeprecated, int defaultRelevance, {ClassDeclaration classDecl}) {
if (id != null) {
String completion = id.name;
if (completion != null && completion.length > 0 && completion != '_') {
CompletionSuggestion suggestion = new CompletionSuggestion(
CompletionSuggestionKind.INVOCATION,
- isDeprecated ? COMPLETION_RELEVANCE_LOW : COMPLETION_RELEVANCE_DEFAULT,
+ isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
completion,
completion.length,
0,
diff --git a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
index e7860ab..7bfeaab 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
@@ -126,17 +126,6 @@
}
@override
- bool visitExpressionStatement(ExpressionStatement node) {
- Expression expression = node.expression;
- if (expression is SimpleIdentifier) {
- if (expression.end < offset) {
- return finished;
- }
- }
- return visitNode(node);
- }
-
- @override
bool visitForEachStatement(ForEachStatement node) {
SimpleIdentifier id;
TypeName type;
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index ef2902b..3a6d6ef 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/services/completion/completion_target.dart';
import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/scanner.dart';
/**
* An [AstVisitor] for determining whether top level suggestions or invocation
@@ -193,6 +194,12 @@
}
@override
+ void visitConditionalExpression(ConditionalExpression node) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+
+ @override
visitConstructorName(ConstructorName node) {
// some PrefixedIdentifier nodes are transformed into
// ConstructorName nodes during the resolution process.
@@ -216,6 +223,14 @@
}
@override
+ void visitDefaultFormalParameter(DefaultFormalParameter node) {
+ if (identical(entity, node.defaultValue)) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
+
+ @override
void visitDoStatement(DoStatement node) {
if (identical(entity, node.condition)) {
optype.includeReturnValueSuggestions = true;
@@ -247,6 +262,15 @@
@override
void visitExpressionStatement(ExpressionStatement node) {
+ // Given f[], the parser drops the [] from the expression statement
+ // but the [] token is the CompletionTarget entity
+ if (entity is Token) {
+ Token token = entity;
+ if (token.lexeme == '[]' && offset == token.offset + 1) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
}
@override
@@ -258,6 +282,17 @@
@override
void visitForEachStatement(ForEachStatement node) {
+ if (identical(entity, node.identifier)) {
+ optype.includeTypeNameSuggestions = true;
+ }
+ if (identical(entity, node.loopVariable)) {
+ optype.includeTypeNameSuggestions = true;
+ }
+ if (identical(entity, node.inKeyword) && offset <= node.inKeyword.offset) {
+ if (node.identifier == null && node.loopVariable == null) {
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
if (identical(entity, node.iterable)) {
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
@@ -307,6 +342,12 @@
}
@override
+ void visitIndexExpression(IndexExpression node) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+
+ @override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
if (identical(entity, node.constructorName)) {
optype.includeTypeNameSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index b90b026..ba6c396 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -23,7 +23,7 @@
*/
CompletionSuggestion createSuggestion(Element element,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: COMPLETION_RELEVANCE_DEFAULT}) {
+ int relevance: DART_RELEVANCE_DEFAULT}) {
String nameForType(DartType type) {
if (type == null) {
@@ -58,7 +58,7 @@
bool isDeprecated = element.isDeprecated;
CompletionSuggestion suggestion = new CompletionSuggestion(
kind,
- isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance,
+ isDeprecated ? DART_RELEVANCE_LOW : relevance,
completion,
completion.length,
0,
@@ -186,7 +186,7 @@
/**
* Add a suggestion based upon the given element.
*/
- void addSuggestion(Element element) {
+ void addSuggestion(Element element, {int relevance: DART_RELEVANCE_DEFAULT}) {
if (element.isPrivate) {
LibraryElement elementLibrary = element.library;
LibraryElement unitLibrary = request.unit.element.library;
@@ -205,7 +205,7 @@
!_completions.add(completion)) {
return;
}
- CompletionSuggestion suggestion = createSuggestion(element, kind: kind);
+ CompletionSuggestion suggestion = createSuggestion(element, kind: kind, relevance: relevance);
if (suggestion != null) {
request.suggestions.add(suggestion);
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 48390a2..0648eb3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -140,22 +140,7 @@
}
String eol = utils.endOfLine;
// prepare location for declaration
- AstNode target_;
- {
- List<AstNode> nodes = _findNodes(occurrences);
- AstNode commonParent = getNearestCommonAncestor(nodes);
- if (commonParent is Block) {
- List<AstNode> firstParents = getParents(nodes[0]);
- int commonIndex = firstParents.indexOf(commonParent);
- target_ = firstParents[commonIndex + 1];
- } else {
- target_ = _getEnclosingExpressionBody(commonParent);
- if (target_ == null) {
- target_ = commonParent.getAncestor((node) => node is Statement);
- }
- }
- }
- AstNode target = target_;
+ AstNode target = _findDeclarationTarget(occurrences);
// insert variable declaration
if (target is Statement) {
String prefix = utils.getNodePrefix(target);
@@ -314,6 +299,32 @@
}
/**
+ * Return the [AstNode] to defined the variable before.
+ * It should be accessible by all the given [occurrences].
+ */
+ AstNode _findDeclarationTarget(List<SourceRange> occurrences) {
+ List<AstNode> nodes = _findNodes(occurrences);
+ AstNode commonParent = getNearestCommonAncestor(nodes);
+ // Block
+ if (commonParent is Block) {
+ List<AstNode> firstParents = getParents(nodes[0]);
+ int commonIndex = firstParents.indexOf(commonParent);
+ return firstParents[commonIndex + 1];
+ }
+ // ExpressionFunctionBody
+ AstNode expressionBody = _getEnclosingExpressionBody(commonParent);
+ if (expressionBody != null) {
+ return expressionBody;
+ }
+ // single Statement
+ AstNode target = commonParent.getAncestor((node) => node is Statement);
+ while (target.parent is! Block) {
+ target = target.parent;
+ }
+ return target;
+ }
+
+ /**
* Returns [AstNode]s at the offsets of the given [SourceRange]s.
*/
List<AstNode> _findNodes(List<SourceRange> ranges) {
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 1fbcaa3..f4d5bca 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -87,4 +87,43 @@
expect(filesErrors[barPath], isEmpty);
});
}
+
+ test_sendNoticesAfterNopChange() async {
+ createProject();
+ addTestFile('');
+ await server.onAnalysisComplete;
+ // add an overlay
+ server.updateContent('1', {
+ testFile: new AddContentOverlay('main() {} main() {}')
+ });
+ await server.onAnalysisComplete;
+ // clear errors and make a no-op change
+ filesErrors.clear();
+ server.updateContent('2', {
+ testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')])
+ });
+ await server.onAnalysisComplete;
+ // errors should have been resent
+ expect(filesErrors, isNotEmpty);
+ }
+
+ test_sendNoticesAfterNopChange_flushedUnit() async {
+ createProject();
+ addTestFile('');
+ await server.onAnalysisComplete;
+ // add an overlay
+ server.updateContent('1', {
+ testFile: new AddContentOverlay('main() {} main() {}')
+ });
+ await server.onAnalysisComplete;
+ // clear errors and make a no-op change
+ filesErrors.clear();
+ server.test_flushResolvedUnit(testFile);
+ server.updateContent('2', {
+ testFile: new ChangeContentOverlay([new SourceEdit(0, 4, 'main')])
+ });
+ await server.onAnalysisComplete;
+ // errors should have been resent
+ expect(filesErrors, isNotEmpty);
+ }
}
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index a7d7f56..aef1641 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -294,7 +294,7 @@
v.!1length;
v.!2getKeys;
}
-}''', <String>["1+length", "2-getKeys"], failingTests: '1');
+}''', <String>["1+length", "2-getKeys"]);
// Type propagation.
buildTests('testCommentSnippets052', '''
@@ -305,7 +305,7 @@
v.!1toUpperCase;
v.!2getKeys;
}
-}''', <String>["1+toUpperCase", "2-getKeys"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2-getKeys"]);
// Type propagation.
buildTests('testCommentSnippets053', '''
@@ -316,7 +316,7 @@
v.!1toUpperCase;
v.!2getKeys;
}
-}''', <String>["1+toUpperCase", "2-getKeys"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2-getKeys"]);
buildTests('testCommentSnippets054', '''
class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
@@ -326,7 +326,7 @@
v.!2toUpperCase;
v.!3getKeys;
}
-}''', <String>["1+isEmpty", "2+toUpperCase", "3-getKeys"], failingTests: '12');
+}''', <String>["1+isEmpty", "2+toUpperCase", "3-getKeys"]);
buildTests('testCommentSnippets055', '''
class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
@@ -345,16 +345,16 @@
return;
}
v.!1toUpperCase;
-}''', <String>["1+toUpperCase"], failingTests: '1');
+}''', <String>["1+toUpperCase"]);
// Type propagation.
buildTests('testCommentSnippets057', '''
class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}}
void f(var v) {
- if ((v as String).length == 0) {
+ if ((v as String).!2length == 0) {
v.!1toUpperCase;
}
-}''', <String>["1+toUpperCase"], failingTests: '1');
+}''', <String>["1+toUpperCase", "2+length"]);
buildTests('testCommentSnippets058', '''
typedef vo!2id callback(int k);
@@ -388,7 +388,7 @@
v.!1toUpperCase;
assert(v is String);
v.!2toUpperCase;
-}''', <String>["1-toUpperCase", "2+toUpperCase"], failingTests: '2');
+}''', <String>["1-toUpperCase", "2+toUpperCase"]);
buildTests('testCommentSnippets064', '''
class Spline {
@@ -756,8 +756,7 @@
buildTests('testCommentSnippets090', '''
class X { f() { var a = 'x'; a.!1 }}''',
- <String>["1+length"],
- failingTests: '1');
+ <String>["1+length"]);
}
void buildCompletionTests() {
@@ -2246,8 +2245,7 @@
buildTests(
'test035',
'''class Y {final x='hi';mth() {x.!1length;}}''',
- <String>["1+length"],
- failingTests: '1');
+ <String>["1+length"]);
// TODO(scheglov) decide what to do with Type for untyped field (not
// supported by the new store)
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index ded3d0d..08fa7e6 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -262,8 +262,8 @@
}
void assertHasResult(CompletionSuggestionKind kind, String completion,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated
- = false, bool isPotential = false]) {
+ [int relevance = DART_RELEVANCE_DEFAULT, bool isDeprecated = false,
+ bool isPotential = false]) {
var cs;
suggestions.forEach((s) {
if (s.completion == completion) {
@@ -445,11 +445,11 @@
assertHasResult(
CompletionSuggestionKind.KEYWORD,
'import',
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
assertHasResult(
CompletionSuggestionKind.KEYWORD,
'class',
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
});
}
@@ -469,9 +469,18 @@
expect(replacementOffset, equals(completionOffset));
expect(replacementLength, equals(0));
assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
- assertHasResult(CompletionSuggestionKind.INVOCATION, 'a');
- assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
- assertHasResult(CompletionSuggestionKind.INVOCATION, 'x');
+ assertHasResult(
+ CompletionSuggestionKind.INVOCATION,
+ 'a',
+ DART_RELEVANCE_LOCAL_FIELD);
+ assertHasResult(
+ CompletionSuggestionKind.INVOCATION,
+ 'b',
+ DART_RELEVANCE_LOCAL_VARIABLE);
+ assertHasResult(
+ CompletionSuggestionKind.INVOCATION,
+ 'x',
+ DART_RELEVANCE_LOCAL_METHOD);
});
}
@@ -486,7 +495,10 @@
expect(replacementLength, equals(4));
// Suggestions based upon imported elements are partially filtered
//assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
- assertHasResult(CompletionSuggestionKind.INVOCATION, 'test');
+ assertHasResult(
+ CompletionSuggestionKind.INVOCATION,
+ 'test',
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
assertNoResult('HtmlElement');
});
}
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index fd63c42..a77ccf8 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -10,7 +10,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_execution.dart';
import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -31,13 +31,14 @@
main() {
group('ExecutionDomainHandler', () {
+ MemoryResourceProvider provider = new MemoryResourceProvider();
AnalysisServer server;
ExecutionDomainHandler handler;
setUp(() {
server = new AnalysisServer(
new MockServerChannel(),
- PhysicalResourceProvider.INSTANCE,
+ provider,
new MockPackageMapProvider(),
null,
new AnalysisServerOptions(),
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 9bf0f76..2b3cad1 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -8,7 +8,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:unittest/unittest.dart';
@@ -21,7 +21,7 @@
setUp(() {
var serverChannel = new MockServerChannel();
- var resourceProvider = PhysicalResourceProvider.INSTANCE;
+ var resourceProvider = new MemoryResourceProvider();
server = new AnalysisServer(
serverChannel,
resourceProvider,
diff --git a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart b/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
index e07cae5..4db0ad3 100644
--- a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
@@ -62,26 +62,26 @@
return computeFull((bool result) {
assertSuggestClass(
'A',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestClass(
'B',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestClass(
'PB',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestTopLevelVar(
'T1',
null,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind.IDENTIFIER);
assertSuggestFunction(
'F1',
'PB',
false,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind.IDENTIFIER);
assertNotSuggested('C');
assertNotSuggested('D');
@@ -115,36 +115,36 @@
return computeFull((bool result) {
assertSuggestClass(
'A',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestClass(
'B',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestClass(
'PB',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestTopLevelVar(
'T1',
null,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind.IDENTIFIER);
assertSuggestFunction(
'F1',
'PB',
false,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind.IDENTIFIER);
assertSuggestClass(
'Clz',
- relevance: COMPLETION_RELEVANCE_DEFAULT,
+ relevance: DART_RELEVANCE_DEFAULT,
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestFunctionTypeAlias(
'F2',
null,
false,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind.IDENTIFIER);
assertNotSuggested('C');
assertNotSuggested('D');
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index f4f03ef..341b397 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -68,7 +68,7 @@
manager = new DartCompletionManager.create(context, searchEngine, source);
suggestion1 = new CompletionSuggestion(
CompletionSuggestionKind.INVOCATION,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
"suggestion1",
1,
1,
@@ -76,7 +76,7 @@
false);
suggestion2 = new CompletionSuggestion(
CompletionSuggestionKind.IDENTIFIER,
- COMPLETION_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_DEFAULT,
"suggestion2",
2,
2,
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 783d1a0..2764b587 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -14,7 +14,6 @@
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/imported_computer.dart';
import 'package:analysis_server/src/services/completion/invocation_computer.dart';
-import 'package:analysis_server/src/services/completion/local_computer.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/local_memory_index.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
@@ -115,8 +114,8 @@
CompletionSuggestion assertSuggest(String completion,
{CompletionSuggestionKind csKind: CompletionSuggestionKind.INVOCATION,
- int relevance: COMPLETION_RELEVANCE_DEFAULT, protocol.ElementKind elemKind:
- null, bool isDeprecated: false, bool isPotential: false}) {
+ int relevance: DART_RELEVANCE_DEFAULT, protocol.ElementKind elemKind: null,
+ bool isDeprecated: false, bool isPotential: false}) {
CompletionSuggestion cs =
getSuggest(completion: completion, csKind: csKind, elemKind: elemKind);
if (cs == null) {
@@ -126,7 +125,7 @@
}
expect(cs.kind, equals(csKind));
if (isDeprecated) {
- expect(cs.relevance, equals(COMPLETION_RELEVANCE_LOW));
+ expect(cs.relevance, equals(DART_RELEVANCE_LOW));
} else {
expect(cs.relevance, equals(relevance));
}
@@ -149,7 +148,7 @@
paramTypes,
cs.parameterNames,
cs.parameterTypes);
- expect(cs.relevance, COMPLETION_RELEVANCE_HIGH);
+ expect(cs.relevance, DART_RELEVANCE_HIGH);
}
void assertSuggestArgumentList_params(List<String> expectedNames,
@@ -181,7 +180,7 @@
}
CompletionSuggestion assertSuggestClass(String name, {int relevance:
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
CompletionSuggestion cs = assertSuggest(
name,
@@ -199,7 +198,7 @@
}
CompletionSuggestion assertSuggestClassTypeAlias(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
CompletionSuggestion cs =
assertSuggest(name, csKind: kind, relevance: relevance);
@@ -214,7 +213,7 @@
}
CompletionSuggestion assertSuggestField(String name, String type,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+ {int relevance: DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
CompletionSuggestion cs = assertSuggest(
name,
@@ -236,7 +235,7 @@
}
CompletionSuggestion assertSuggestFunction(String name, String returnType,
- [bool isDeprecated = false, int relevance = COMPLETION_RELEVANCE_DEFAULT,
+ [bool isDeprecated = false, int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
CompletionSuggestion cs = assertSuggest(
name,
@@ -261,9 +260,8 @@
}
CompletionSuggestion assertSuggestFunctionTypeAlias(String name,
- String returnType, bool isDeprecated, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
- CompletionSuggestionKind.INVOCATION]) {
+ String returnType, bool isDeprecated, [int relevance = DART_RELEVANCE_DEFAULT,
+ CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
CompletionSuggestion cs = assertSuggest(
name,
csKind: kind,
@@ -289,7 +287,7 @@
}
CompletionSuggestion assertSuggestGetter(String name, String returnType,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
+ {int relevance: DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind:
CompletionSuggestionKind.INVOCATION, bool isDeprecated: false}) {
CompletionSuggestion cs = assertSuggest(
name,
@@ -311,7 +309,7 @@
}
CompletionSuggestion assertSuggestLabel(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.IDENTIFIER]) {
CompletionSuggestion cs =
assertSuggest(name, csKind: kind, relevance: relevance);
@@ -328,7 +326,7 @@
}
CompletionSuggestion assertSuggestLibraryPrefix(String prefix, [int relevance
- = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ = DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
// Library prefix should only be suggested by ImportedComputer
if (computer is ImportedComputer) {
@@ -346,29 +344,8 @@
}
}
- CompletionSuggestion assertSuggestLocalVariable(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
- CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- // Local variables should only be suggested by LocalComputer
- if (computer is LocalComputer) {
- CompletionSuggestion cs =
- assertSuggest(name, csKind: kind, relevance: relevance);
- expect(cs.returnType, returnType != null ? returnType : 'dynamic');
- protocol.Element element = cs.element;
- expect(element, isNotNull);
- expect(element.kind, equals(protocol.ElementKind.LOCAL_VARIABLE));
- expect(element.name, equals(name));
- expect(element.parameters, isNull);
- expect(element.returnType, returnType != null ? returnType : 'dynamic');
- assertHasNoParameterInfo(cs);
- return cs;
- } else {
- return assertNotSuggested(name);
- }
- }
-
CompletionSuggestion assertSuggestMethod(String name, String declaringType,
- String returnType, {int relevance: COMPLETION_RELEVANCE_DEFAULT,
+ String returnType, {int relevance: DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
bool isDeprecated: false}) {
CompletionSuggestion cs = assertSuggest(
@@ -392,7 +369,7 @@
}
CompletionSuggestion assertSuggestNamedConstructor(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
+ String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
if (computer is InvocationComputer) {
CompletionSuggestion cs =
@@ -414,29 +391,12 @@
}
CompletionSuggestion assertSuggestParameter(String name, String returnType,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
- CompletionSuggestionKind.INVOCATION]) {
- // Parameters should only be suggested by LocalComputer
- if (computer is LocalComputer) {
- CompletionSuggestion cs =
- assertSuggest(name, csKind: kind, relevance: relevance);
- expect(cs.returnType, returnType != null ? returnType : 'dynamic');
- protocol.Element element = cs.element;
- expect(element, isNotNull);
- expect(element.kind, equals(protocol.ElementKind.PARAMETER));
- expect(element.name, equals(name));
- expect(element.parameters, isNull);
- expect(
- element.returnType,
- equals(returnType != null ? returnType : 'dynamic'));
- return cs;
- } else {
- return assertNotSuggested(name);
- }
+ {int relevance: DART_RELEVANCE_PARAMETER}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestSetter(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
CompletionSuggestion cs = assertSuggest(
name,
@@ -458,7 +418,7 @@
}
CompletionSuggestion assertSuggestTopLevelVar(String name, String returnType,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ [int relevance = DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
CompletionSuggestion cs =
assertSuggest(name, csKind: kind, relevance: relevance);
@@ -474,7 +434,7 @@
}
void assertSuggestTopLevelVarGetterSetter(String name, String returnType,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+ [int relevance = DART_RELEVANCE_DEFAULT]) {
if (computer is ImportedComputer) {
assertSuggestGetter(name, returnType);
assertSuggestSetter(name);
@@ -624,22 +584,8 @@
// Subclasses override
}
- CompletionSuggestion assertLocalSuggestMethod(String name,
- String declaringType, String returnType, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestMethod(
- name,
- declaringType,
- returnType,
- relevance: relevance);
- } else {
- return assertNotSuggested(name);
- }
- }
-
CompletionSuggestion assertSuggestImportedClass(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
if (computer is ImportedComputer) {
return assertSuggestClass(name, relevance: relevance, kind: kind);
@@ -649,13 +595,13 @@
}
CompletionSuggestion assertSuggestImportedField(String name, String type,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+ {int relevance: DART_RELEVANCE_INHERITED_FIELD}) {
return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestImportedFunction(String name,
String returnType, [bool isDeprecated = false, int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
if (computer is ImportedComputer) {
return assertSuggestFunction(
@@ -671,7 +617,7 @@
CompletionSuggestion assertSuggestImportedFunctionTypeAlias(String name,
String returnType, [bool isDeprecated = false, int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
if (computer is ImportedComputer) {
return assertSuggestFunctionTypeAlias(
@@ -686,39 +632,23 @@
}
CompletionSuggestion assertSuggestImportedGetter(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is ImportedComputer) {
- return assertSuggestGetter(name, returnType, relevance: relevance);
- } else {
- return assertNotSuggested(name);
- }
+ String returnType, {int relevance: DART_RELEVANCE_INHERITED_ACCESSOR}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestImportedMethod(String name,
- String declaringType, String returnType, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is ImportedComputer) {
- return assertSuggestMethod(
- name,
- declaringType,
- returnType,
- relevance: relevance);
- } else {
- return assertNotSuggested(name);
- }
+ String declaringType, String returnType, {int relevance:
+ DART_RELEVANCE_INHERITED_METHOD}) {
+ return assertNotSuggested(name);
}
- CompletionSuggestion assertSuggestImportedSetter(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is ImportedComputer) {
- return assertSuggestSetter(name, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ CompletionSuggestion assertSuggestImportedSetter(String name, {int relevance:
+ DART_RELEVANCE_INHERITED_ACCESSOR}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestImportedTopLevelVar(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT,
+ String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
if (computer is ImportedComputer) {
return assertSuggestTopLevelVar(name, returnType, relevance, kind);
@@ -728,7 +658,7 @@
}
CompletionSuggestion assertSuggestInvocationClass(String name, [int relevance
- = COMPLETION_RELEVANCE_DEFAULT]) {
+ = DART_RELEVANCE_DEFAULT]) {
if (computer is InvocationComputer) {
return assertSuggestClass(name, relevance: relevance);
} else {
@@ -737,13 +667,13 @@
}
CompletionSuggestion assertSuggestInvocationField(String name, String type,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestInvocationGetter(String name,
- String returnType, {int relevance: COMPLETION_RELEVANCE_DEFAULT,
- bool isDeprecated: false}) {
+ String returnType, {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated:
+ false}) {
if (computer is InvocationComputer) {
return assertSuggestGetter(
name,
@@ -757,7 +687,7 @@
CompletionSuggestion assertSuggestInvocationMethod(String name,
String declaringType, String returnType, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
+ DART_RELEVANCE_DEFAULT]) {
if (computer is InvocationComputer) {
return assertSuggestMethod(
name,
@@ -770,7 +700,7 @@
}
CompletionSuggestion assertSuggestInvocationSetter(String name, [int relevance
- = COMPLETION_RELEVANCE_DEFAULT]) {
+ = DART_RELEVANCE_DEFAULT]) {
if (computer is InvocationComputer) {
return assertSuggestSetter(name);
} else {
@@ -779,7 +709,7 @@
}
CompletionSuggestion assertSuggestInvocationTopLevelVar(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+ String returnType, [int relevance = DART_RELEVANCE_DEFAULT]) {
if (computer is InvocationComputer) {
return assertSuggestTopLevelVar(name, returnType, relevance);
} else {
@@ -788,79 +718,60 @@
}
CompletionSuggestion assertSuggestLocalClass(String name, {int relevance:
- COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalClassTypeAlias(String name,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestClassTypeAlias(name, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalField(String name, String type,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_LOCAL_FIELD, bool deprecated: false}) {
return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalFunction(String name,
- String returnType, [bool isDeprecated = false, int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestFunction(name, returnType, isDeprecated, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ String returnType, {bool deprecated: false, int relevance:
+ DART_RELEVANCE_LOCAL_FUNCTION}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalFunctionTypeAlias(String name,
- String returnType, [bool isDeprecated = false, int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestFunctionTypeAlias(
- name,
- returnType,
- isDeprecated,
- relevance);
- } else {
- return assertNotSuggested(name);
- }
+ String returnType, {bool deprecated: false, int relevance:
+ DART_RELEVANCE_DEFAULT}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalGetter(String name, String returnType,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_LOCAL_ACCESSOR, bool deprecated: false}) {
return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalMethod(String name,
String declaringType, String returnType, {int relevance:
- COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ DART_RELEVANCE_LOCAL_METHOD, bool deprecated: false}) {
return assertNotSuggested(name);
}
- CompletionSuggestion assertSuggestLocalSetter(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestSetter(name, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ CompletionSuggestion assertSuggestLocalSetter(String name, {int relevance:
+ DART_RELEVANCE_LOCAL_ACCESSOR}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalTopLevelVar(String name,
- String returnType, [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
- if (computer is LocalComputer) {
- return assertSuggestTopLevelVar(name, returnType, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ String returnType, {int relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE}) {
+ return assertNotSuggested(name);
+ }
+
+ CompletionSuggestion assertSuggestLocalVariable(String name,
+ String returnType, {int relevance: DART_RELEVANCE_LOCAL_VARIABLE}) {
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestNonLocalClass(String name, [int relevance =
- COMPLETION_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
+ DART_RELEVANCE_DEFAULT, CompletionSuggestionKind kind =
CompletionSuggestionKind.INVOCATION]) {
return assertSuggestImportedClass(name, relevance, kind);
}
@@ -1230,8 +1141,8 @@
assertSuggestLocalClass('X');
assertSuggestLocalClass('Z');
- assertLocalSuggestMethod('a', 'X', null);
- assertLocalSuggestMethod('b', 'X', 'void');
+ assertSuggestLocalMethod('a', 'X', null);
+ assertSuggestLocalMethod('b', 'X', 'void');
assertSuggestLocalFunction('localF', null);
assertSuggestLocalVariable('f', null);
// Don't suggest locals out of scope
@@ -1312,8 +1223,8 @@
assertSuggestLocalClass('X');
assertSuggestLocalClass('Z');
- assertLocalSuggestMethod('a', 'X', null);
- assertLocalSuggestMethod('b', 'X', 'void');
+ assertSuggestLocalMethod('a', 'X', null);
+ assertSuggestLocalMethod('b', 'X', 'void');
assertSuggestLocalVariable('f', null);
// Don't suggest locals out of scope
assertNotSuggested('r');
@@ -1324,8 +1235,8 @@
assertNotSuggested('_B');
//assertSuggestImportedClass('C');
// hidden element suggested as low relevance
- assertSuggestImportedClass('D', COMPLETION_RELEVANCE_LOW);
- assertSuggestImportedFunction('D1', null, true, COMPLETION_RELEVANCE_LOW);
+ assertSuggestImportedClass('D', DART_RELEVANCE_LOW);
+ assertSuggestImportedFunction('D1', null, true, DART_RELEVANCE_LOW);
assertSuggestLocalFunction('D2', 'Z');
//assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
@@ -1548,7 +1459,7 @@
expect(request.replacementLength, 0);
CompletionSuggestion suggestionA = assertSuggestLocalClass(
'A',
- relevance: COMPLETION_RELEVANCE_LOW,
+ relevance: DART_RELEVANCE_LOW,
isDeprecated: true);
if (suggestionA != null) {
expect(suggestionA.element.isDeprecated, isTrue);
@@ -1621,35 +1532,120 @@
});
}
- test_ConditionalExpression_empty() {
- // SimpleIdentifier PrefixIdentifier IfStatement
+ test_ConditionalExpression_elseExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
addTestSource('''
- class A {var b; X _c; foo() {A a; if (^) something}}''');
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T1 : T^}}''');
computeFast();
return computeFull((bool result) {
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
- assertSuggestLocalField('b', null);
- assertSuggestLocalField('_c', 'X');
- assertSuggestImportedClass('Object');
- assertSuggestLocalClass('A');
- assertNotSuggested('==');
+ // top level results are partially filtered based on first char
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
});
}
- test_ConditionalExpression_invocation() {
- // SimpleIdentifier PrefixIdentifier IfStatement
+ test_ConditionalExpression_elseExpression_empty() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
addTestSource('''
- main() {var a; if (a.^) something}''');
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T1 : ^}}''');
computeFast();
return computeFull((bool result) {
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
- assertSuggestInvocationMethod('toString', 'Object', 'String');
- //TODO (danrubel) type for '_c' should be 'X' not null
- assertNotSuggested('Object');
- assertNotSuggested('A');
- assertNotSuggested('==');
+ assertNotSuggested('x');
+ assertSuggestLocalVariable('f', null);
+ assertSuggestLocalMethod('foo', 'C', null);
+ assertSuggestLocalClass('C');
+ assertSuggestLocalFunction('F2', null);
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ assertSuggestImportedClass('A');
+ assertSuggestImportedFunction('F1', null);
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ });
+ }
+
+ test_ConditionalExpression_partial_thenExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T^}}''');
+ computeFast();
+ return computeFull((bool result) {
+ // top level results are partially filtered based on first char
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ });
+ }
+
+ test_ConditionalExpression_partial_thenExpression_empty() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? ^}}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNotSuggested('x');
+ assertSuggestLocalVariable('f', null);
+ assertSuggestLocalMethod('foo', 'C', null);
+ assertSuggestLocalClass('C');
+ assertSuggestLocalFunction('F2', null);
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ assertSuggestImportedClass('A');
+ assertSuggestImportedFunction('F1', null);
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ });
+ }
+
+ test_ConditionalExpression_thenExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T^ : c}}''');
+ computeFast();
+ return computeFull((bool result) {
+ // top level results are partially filtered based on first char
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
});
}
@@ -1763,6 +1759,25 @@
});
}
+ test_DefaultFormalParameter_named_expression() {
+ // DefaultFormalParameter FormalParameterList MethodDeclaration
+ addTestSource('''
+ foo() { }
+ void bar() { }
+ class A {a(blat: ^) { }}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestLocalFunction('foo', null);
+ assertSuggestLocalMethod('a', 'A', null);
+ assertSuggestLocalClass('A');
+ assertSuggestImportedClass('String');
+ assertSuggestImportedFunction('identical', 'bool');
+ assertNotSuggested('bar');
+ });
+ }
+
test_ExpressionStatement_identifier() {
// SimpleIdentifier ExpressionStatement Block
addSource('/testA.dart', '''
@@ -1838,6 +1853,7 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
+ assertSuggestParameter('args', null);
assertSuggestLocalVariable('foo', 'int');
assertSuggestImportedClass('Object');
});
@@ -1850,11 +1866,62 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
+ assertSuggestParameter('args', null);
assertSuggestLocalVariable('foo', null);
assertSuggestImportedClass('Object');
});
}
+ test_ForEachStatement_iterable() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (int foo in ^) {}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestParameter('args', null);
+ assertSuggestImportedClass('Object');
+ });
+ }
+
+ test_ForEachStatement_loopVariable() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ in args) {}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertNotSuggested('args');
+ assertSuggestImportedClass('String');
+ });
+ }
+
+ test_ForEachStatement_loopVariable_type() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ foo in args) {}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertSuggestImportedClass('String');
+ });
+ }
+
+ test_ForEachStatement_loopVariable_type2() {
+ // DeclaredIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (S^ foo in args) {}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertSuggestImportedClass('String');
+ });
+ }
+
test_FormalParameterList() {
// FormalParameterList MethodDeclaration
addTestSource('''
@@ -1945,7 +2012,7 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- var f = assertSuggestLocalFunction('foo', 'String', false);
+ var f = assertSuggestLocalFunction('foo', 'String', deprecated: false);
if (f != null) {
expect(f.element.isPrivate, isFalse);
}
@@ -1956,6 +2023,22 @@
});
}
+ test_IfStatement() {
+ // SimpleIdentifier IfStatement
+ addTestSource('''
+ class A {var b; X _c; foo() {A a; if (true) ^}}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestLocalField('b', null);
+ assertSuggestLocalField('_c', 'X');
+ assertSuggestImportedClass('Object');
+ assertSuggestLocalClass('A');
+ assertNotSuggested('==');
+ });
+ }
+
test_IfStatement_condition() {
// SimpleIdentifier IfStatement Block BlockFunctionBody
addTestSource('''
@@ -1972,6 +2055,38 @@
});
}
+ test_IfStatement_empty() {
+ // SimpleIdentifier IfStatement
+ addTestSource('''
+ class A {var b; X _c; foo() {A a; if (^) something}}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestLocalField('b', null);
+ assertSuggestLocalField('_c', 'X');
+ assertSuggestImportedClass('Object');
+ assertSuggestLocalClass('A');
+ assertNotSuggested('==');
+ });
+ }
+
+ test_IfStatement_invocation() {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('''
+ main() {var a; if (a.^) something}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestInvocationMethod('toString', 'Object', 'String');
+ //TODO (danrubel) type for '_c' should be 'X' not null
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ });
+ }
+
test_ImportDirective_dart() {
// SimpleStringLiteral ImportDirective
addTestSource('''
@@ -1983,6 +2098,54 @@
});
}
+ test_IndexExpression() {
+ // ExpressionStatement Block
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} f[^]}}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNotSuggested('x');
+ assertSuggestLocalVariable('f', null);
+ assertSuggestLocalMethod('foo', 'C', null);
+ assertSuggestLocalClass('C');
+ assertSuggestLocalFunction('F2', null);
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ assertSuggestImportedClass('A');
+ assertSuggestImportedFunction('F1', null);
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ });
+ }
+
+ test_IndexExpression2() {
+ // SimpleIdentifier IndexExpression ExpressionStatement Block
+ addSource('/testA.dart', '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} f[T^]}}''');
+ computeFast();
+ return computeFull((bool result) {
+ // top level results are partially filtered based on first char
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ });
+ }
+
test_InstanceCreationExpression_imported() {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addSource('/testA.dart', '''
@@ -2189,8 +2352,8 @@
CompletionSuggestion getterF = assertSuggestLocalGetter(
'f',
'X',
- relevance: COMPLETION_RELEVANCE_LOW,
- isDeprecated: true);
+ relevance: DART_RELEVANCE_LOW,
+ deprecated: true);
if (getterF != null) {
expect(getterF.element.isDeprecated, isTrue);
expect(getterF.element.isPrivate, isFalse);
@@ -2218,8 +2381,8 @@
CompletionSuggestion getterF = assertSuggestLocalField(
'f',
'X',
- relevance: COMPLETION_RELEVANCE_LOW,
- isDeprecated: true);
+ relevance: DART_RELEVANCE_LOW,
+ deprecated: true);
if (getterF != null) {
expect(getterF.element.isDeprecated, isTrue);
expect(getterF.element.isPrivate, isFalse);
@@ -2246,8 +2409,8 @@
'a',
'A',
'Z',
- relevance: COMPLETION_RELEVANCE_LOW,
- isDeprecated: true);
+ relevance: DART_RELEVANCE_LOW,
+ deprecated: true);
if (methodA != null) {
expect(methodA.element.isDeprecated, isTrue);
expect(methodA.element.isPrivate, isFalse);
diff --git a/pkg/analysis_server/test/services/completion/imported_computer_test.dart b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
index 9c20f67..d67c2d8 100644
--- a/pkg/analysis_server/test/services/completion/imported_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
@@ -107,10 +107,30 @@
@override
CompletionSuggestion assertSuggestImportedField(String name, String type,
- [int relevance = COMPLETION_RELEVANCE_DEFAULT]) {
+ {int relevance: DART_RELEVANCE_INHERITED_FIELD}) {
return assertSuggestField(name, type, relevance: relevance);
}
+ CompletionSuggestion assertSuggestImportedGetter(String name,
+ String returnType, {int relevance: DART_RELEVANCE_INHERITED_ACCESSOR}) {
+ return assertSuggestGetter(name, returnType, relevance: relevance);
+ }
+
+ CompletionSuggestion assertSuggestImportedMethod(String name,
+ String declaringType, String returnType, {int relevance:
+ DART_RELEVANCE_INHERITED_METHOD}) {
+ return assertSuggestMethod(
+ name,
+ declaringType,
+ returnType,
+ relevance: relevance);
+ }
+
+ CompletionSuggestion assertSuggestImportedSetter(String name, {int relevance:
+ DART_RELEVANCE_INHERITED_ACCESSOR}) {
+ return assertSuggestSetter(name, relevance);
+ }
+
bool isCached(List<CompletionSuggestion> suggestions, String completion) =>
suggestions.any((CompletionSuggestion s) => s.completion == completion);
@@ -349,7 +369,8 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -373,7 +394,8 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -397,7 +419,8 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -422,7 +445,8 @@
''');
computeFast();
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, isEmpty);
expect(suggestion.parameterTypes, isEmpty);
expect(suggestion.requiredParameterCount, 0);
@@ -443,7 +467,8 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -467,7 +492,8 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestImportedMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -500,7 +526,7 @@
}
''');
return computeFull((bool result) {
- assertSuggestMethod('m', 'M2', 'void');
+ assertSuggestImportedMethod('m', 'M2', 'void');
});
}
@@ -564,7 +590,7 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestField('x', 'int');
+ CompletionSuggestion suggestion = assertSuggestImportedField('x', 'int');
assertHasNoParameterInfo(suggestion);
});
}
@@ -582,7 +608,7 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestGetter('x', 'int');
+ CompletionSuggestion suggestion = assertSuggestImportedGetter('x', 'int');
assertHasNoParameterInfo(suggestion);
});
}
@@ -600,7 +626,7 @@
}
''');
return computeFull((bool result) {
- CompletionSuggestion suggestion = assertSuggestSetter('x');
+ CompletionSuggestion suggestion = assertSuggestImportedSetter('x');
assertHasNoParameterInfo(suggestion);
});
}
diff --git a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
index ddfb327..6b9886b 100644
--- a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
@@ -25,7 +25,7 @@
@override
CompletionSuggestion assertSuggestInvocationField(String name, String type,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
return assertSuggestField(
name,
type,
@@ -132,6 +132,41 @@
});
}
+ test_local() {
+ addTestSource('foo() {String x = "bar"; x.^}');
+ return computeFull((bool result) {
+ assertSuggestGetter('length', 'int');
+ });
+ }
+
+ test_local_is() {
+ addTestSource('foo() {var x; if (x is String) x.^}');
+ return computeFull((bool result) {
+ assertSuggestGetter('length', 'int');
+ });
+ }
+
+ test_local_propogatedType() {
+ addTestSource('foo() {var x = "bar"; x.^}');
+ return computeFull((bool result) {
+ assertSuggestGetter('length', 'int');
+ });
+ }
+
+ test_param() {
+ addTestSource('foo(String x) {x.^}');
+ return computeFull((bool result) {
+ assertSuggestGetter('length', 'int');
+ });
+ }
+
+ test_param_is() {
+ addTestSource('foo(x) {if (x is String) x.^}');
+ return computeFull((bool result) {
+ assertSuggestGetter('length', 'int');
+ });
+ }
+
test_method_parameters_mixed_required_and_named() {
addTestSource('''
class C {
diff --git a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart b/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
index 9075d36..c51d186 100644
--- a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
@@ -22,7 +22,7 @@
class KeywordComputerTest extends AbstractCompletionTest {
void assertSuggestKeywords(Iterable<Keyword> expectedKeywords, [int relevance
- = COMPLETION_RELEVANCE_DEFAULT]) {
+ = DART_RELEVANCE_KEYWORD]) {
Set<Keyword> actualKeywords = new Set<Keyword>();
request.suggestions.forEach((CompletionSuggestion s) {
if (s.kind == CompletionSuggestionKind.KEYWORD) {
@@ -76,7 +76,7 @@
Keyword.FINAL,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_after_class2() {
@@ -90,7 +90,7 @@
Keyword.FINAL,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_after_import() {
@@ -107,7 +107,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_after_import2() {
@@ -124,7 +124,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_before_import() {
@@ -132,7 +132,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.EXPORT, Keyword.IMPORT, Keyword.LIBRARY, Keyword.PART],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class() {
@@ -140,7 +140,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class2() {
@@ -148,7 +148,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class3() {
@@ -156,7 +156,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_extends() {
@@ -164,7 +164,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.IMPLEMENTS, Keyword.WITH],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_extends2() {
@@ -172,7 +172,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.IMPLEMENTS, Keyword.WITH],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_extends3() {
@@ -180,7 +180,7 @@
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.IMPLEMENTS, Keyword.WITH],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_extends_name() {
@@ -192,7 +192,7 @@
test_class_implements() {
addTestSource('class A ^ implements foo');
expect(computeFast(), isTrue);
- assertSuggestKeywords([Keyword.EXTENDS], COMPLETION_RELEVANCE_HIGH);
+ assertSuggestKeywords([Keyword.EXTENDS], DART_RELEVANCE_HIGH);
}
test_class_implements2() {
@@ -201,7 +201,7 @@
// TODO (danrubel) refinement: don't suggest implements
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_implements3() {
@@ -210,7 +210,7 @@
// TODO (danrubel) refinement: don't suggest implements
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_class_implements_name() {
@@ -228,19 +228,19 @@
test_class_with() {
addTestSource('class A extends foo with bar ^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+ assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
}
test_class_with2() {
addTestSource('class A extends foo with bar i^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+ assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
}
test_class_with3() {
addTestSource('class A extends foo with bar i^ { }');
expect(computeFast(), isTrue);
- assertSuggestKeywords([Keyword.IMPLEMENTS], COMPLETION_RELEVANCE_HIGH);
+ assertSuggestKeywords([Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
}
test_class_with_name() {
@@ -264,7 +264,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_function_body() {
@@ -350,7 +350,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_library_name() {
@@ -405,7 +405,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_partial_class() {
@@ -423,7 +423,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
test_partial_class2() {
@@ -440,7 +440,7 @@
Keyword.PART,
Keyword.TYPEDEF,
Keyword.VAR],
- COMPLETION_RELEVANCE_HIGH);
+ DART_RELEVANCE_HIGH);
}
void _appendKeywords(StringBuffer msg, Iterable<Keyword> keywords) {
diff --git a/pkg/analysis_server/test/services/completion/local_computer_test.dart b/pkg/analysis_server/test/services/completion/local_computer_test.dart
index 86b54ab..433ff77 100644
--- a/pkg/analysis_server/test/services/completion/local_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_computer_test.dart
@@ -22,7 +22,7 @@
@override
CompletionSuggestion assertSuggestLocalClass(String name, {int relevance:
- COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
return assertSuggestClass(
name,
relevance: relevance,
@@ -30,35 +30,108 @@
}
@override
+ CompletionSuggestion assertSuggestLocalClassTypeAlias(String name,
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
+ return assertSuggestClassTypeAlias(name, relevance);
+ }
+
+ @override
CompletionSuggestion assertSuggestLocalField(String name, String type,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_LOCAL_FIELD, bool deprecated: false}) {
return assertSuggestField(
name,
type,
relevance: relevance,
- isDeprecated: isDeprecated);
+ isDeprecated: deprecated);
+ }
+
+ @override
+ CompletionSuggestion assertSuggestLocalFunction(String name,
+ String returnType, {bool deprecated: false, int relevance:
+ DART_RELEVANCE_LOCAL_FUNCTION}) {
+ return assertSuggestFunction(name, returnType, deprecated, relevance);
+ }
+
+ @override
+ CompletionSuggestion assertSuggestLocalFunctionTypeAlias(String name,
+ String returnType, {bool deprecated: false, int relevance:
+ DART_RELEVANCE_DEFAULT}) {
+ return assertSuggestFunctionTypeAlias(
+ name,
+ returnType,
+ deprecated,
+ relevance);
}
@override
CompletionSuggestion assertSuggestLocalGetter(String name, String returnType,
- {int relevance: COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_LOCAL_ACCESSOR, bool deprecated: false}) {
return assertSuggestGetter(
name,
returnType,
relevance: relevance,
- isDeprecated: isDeprecated);
+ isDeprecated: deprecated);
}
@override
CompletionSuggestion assertSuggestLocalMethod(String name,
String declaringType, String returnType, {int relevance:
- COMPLETION_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
+ DART_RELEVANCE_LOCAL_METHOD, bool deprecated: false}) {
return assertSuggestMethod(
name,
declaringType,
returnType,
relevance: relevance,
- isDeprecated: isDeprecated);
+ isDeprecated: deprecated);
+ }
+
+ @override
+ CompletionSuggestion assertSuggestLocalSetter(String name, {int relevance:
+ DART_RELEVANCE_LOCAL_ACCESSOR}) {
+ return assertSuggestSetter(name, relevance);
+ }
+
+ @override
+ CompletionSuggestion assertSuggestLocalTopLevelVar(String name,
+ String returnType, {int relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE}) {
+ return assertSuggestTopLevelVar(name, returnType, relevance);
+ }
+
+ @override
+ CompletionSuggestion assertSuggestLocalVariable(String name,
+ String returnType, {int relevance: DART_RELEVANCE_LOCAL_VARIABLE}) {
+ // Local variables should only be suggested by LocalComputer
+ CompletionSuggestion cs = assertSuggest(
+ name,
+ csKind: CompletionSuggestionKind.INVOCATION,
+ relevance: relevance);
+ expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+ Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(ElementKind.LOCAL_VARIABLE));
+ expect(element.name, equals(name));
+ expect(element.parameters, isNull);
+ expect(element.returnType, returnType != null ? returnType : 'dynamic');
+ assertHasNoParameterInfo(cs);
+ return cs;
+ }
+
+ CompletionSuggestion assertSuggestParameter(String name, String returnType,
+ {int relevance: DART_RELEVANCE_PARAMETER}) {
+ CompletionSuggestion cs = assertSuggest(
+ name,
+ csKind: CompletionSuggestionKind.INVOCATION,
+ relevance: relevance);
+ expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+ Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(ElementKind.PARAMETER));
+ expect(element.name, equals(name));
+ expect(element.parameters, isNull);
+ expect(
+ element.returnType,
+ equals(returnType != null ? returnType : 'dynamic'));
+ return cs;
}
fail_mixin_ordering() {
@@ -373,7 +446,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -391,7 +464,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -409,7 +482,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -427,7 +500,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, isEmpty);
expect(suggestion.parameterTypes, isEmpty);
expect(suggestion.requiredParameterCount, 0);
@@ -442,7 +515,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -460,7 +533,7 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestFunction('m', 'void');
+ CompletionSuggestion suggestion = assertSuggestLocalFunction('m', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -480,7 +553,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -500,7 +574,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -520,7 +595,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -540,7 +616,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, isEmpty);
expect(suggestion.parameterTypes, isEmpty);
expect(suggestion.requiredParameterCount, 0);
@@ -557,7 +634,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
@@ -577,7 +655,8 @@
}
''');
expect(computeFast(), isTrue);
- CompletionSuggestion suggestion = assertSuggestMethod('m', 'A', 'void');
+ CompletionSuggestion suggestion =
+ assertSuggestLocalMethod('m', 'A', 'void');
expect(suggestion.parameterNames, hasLength(2));
expect(suggestion.parameterNames[0], 'x');
expect(suggestion.parameterTypes[0], 'dynamic');
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index 9e6d8e0..ce7a5ba 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -46,12 +46,30 @@
void assertOpType({bool invocation: false, bool returnValue: false,
bool typeNames: false, bool voidReturn: false, bool statementLabel: false,
bool caseLabel: false}) {
- expect(visitor.includeInvocationSuggestions, equals(invocation));
- expect(visitor.includeReturnValueSuggestions, equals(returnValue));
- expect(visitor.includeTypeNameSuggestions, equals(typeNames));
- expect(visitor.includeVoidReturnSuggestions, equals(voidReturn));
- expect(visitor.includeStatementLabelSuggestions, equals(statementLabel));
- expect(visitor.includeCaseLabelSuggestions, equals(caseLabel));
+ expect(
+ visitor.includeInvocationSuggestions,
+ equals(invocation),
+ reason: 'invocation');
+ expect(
+ visitor.includeReturnValueSuggestions,
+ equals(returnValue),
+ reason: 'returnValue');
+ expect(
+ visitor.includeTypeNameSuggestions,
+ equals(typeNames),
+ reason: 'typeNames');
+ expect(
+ visitor.includeVoidReturnSuggestions,
+ equals(voidReturn),
+ reason: 'voidReturn');
+ expect(
+ visitor.includeStatementLabelSuggestions,
+ equals(statementLabel),
+ reason: 'statementLabel');
+ expect(
+ visitor.includeCaseLabelSuggestions,
+ equals(caseLabel),
+ reason: 'caseLabel');
}
test_Annotation() {
@@ -285,16 +303,34 @@
assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
- test_ConditionalExpression_empty() {
- // SimpleIdentifier PrefixIdentifier IfStatement
- addTestSource('class A {foo() {A a; if (^) something}}');
+ test_ConditionalExpression_elseExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T1 : T^}}');
assertOpType(returnValue: true, typeNames: true);
}
- test_ConditionalExpression_invocation() {
- // SimpleIdentifier PrefixIdentifier IfStatement
- addTestSource('main() {var a; if (a.^) something}');
- assertOpType(invocation: true);
+ test_ConditionalExpression_elseExpression_empty() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T1 : ^}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_partial_thenExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T^}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_partial_thenExpression_empty() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? ^}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_ConditionalExpression_thenExpression() {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addTestSource('class C {foo(){var f; {var x;} return a ? T^ : c}}');
+ assertOpType(returnValue: true, typeNames: true);
}
test_ConstructorName() {
@@ -340,6 +376,12 @@
assertOpType(statementLabel: true, caseLabel: true);
}
+ test_DefaultFormalParameter_named_expression() {
+ // DefaultFormalParameter FormalParameterList MethodDeclaration
+ addTestSource('class A {a(blat: ^) { }}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
test_DoStatement() {
// SimpleIdentifier DoStatement Block
addTestSource('main() {do{} while(^x);}');
@@ -402,6 +444,42 @@
assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
+ test_ForEachStatement_iterable() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (int foo in ^) {}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_ForEachStatement_loopVariable() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ in args) {}}');
+ assertOpType(typeNames: true);
+ }
+
+ test_ForEachStatement_loopVariable_name() {
+ // DeclaredIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (String ^ in args) {}}');
+ assertOpType();
+ }
+
+ test_ForEachStatement_loopVariable_name2() {
+ // DeclaredIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (String f^ in args) {}}');
+ assertOpType();
+ }
+
+ test_ForEachStatement_loopVariable_type() {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ foo in args) {}}');
+ assertOpType(typeNames: true);
+ }
+
+ test_ForEachStatement_loopVariable_type2() {
+ // DeclaredIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (S^ foo in args) {}}');
+ assertOpType(typeNames: true);
+ }
+
test_FormalParameterList() {
// FormalParameterList MethodDeclaration
addTestSource('class A {a(^) { }}');
@@ -453,6 +531,18 @@
assertOpType(returnValue: true, typeNames: true);
}
+ test_IfStatement_empty() {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('class A {foo() {A a; if (^) something}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_IfStatement_invocation() {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('main() {var a; if (a.^) something}');
+ assertOpType(invocation: true);
+ }
+
test_ImplementsClause() {
// ImplementsClause ClassDeclaration
addTestSource('class x implements ^\n{}');
@@ -467,6 +557,16 @@
assertOpType();
}
+ test_IndexExpression() {
+ addTestSource('class C {foo(){var f; {var x;} f[^]}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_IndexExpression2() {
+ addTestSource('class C {foo(){var f; {var x;} f[T^]}}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
test_InstanceCreationExpression_imported() {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addTestSource('class C {foo(){var f; {var x;} new ^}}');
@@ -476,19 +576,13 @@
test_InstanceCreationExpression_keyword() {
// InstanceCreationExpression ExpressionStatement Block
addTestSource('class C {foo(){var f; {var x;} new^ }}');
- assertOpType(
- returnValue: true,
- typeNames: true,
- voidReturn: true);
+ assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
test_InstanceCreationExpression_keyword2() {
// InstanceCreationExpression ExpressionStatement Block
addTestSource('class C {foo(){var f; {var x;} new^ C();}}');
- assertOpType(
- returnValue: true,
- typeNames: true,
- voidReturn: true);
+ assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
test_InterpolationExpression() {
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index e8ced6a..efe7091 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -768,6 +768,30 @@
''');
}
+ test_singleExpression_inIfElseIf() {
+ indexTestUnit('''
+main(int p) {
+ if (p == 1) {
+ print(1);
+ } else if (p == 2) {
+ print(2);
+ }
+}
+''');
+ _createRefactoringForString('2');
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+main(int p) {
+ var res = 2;
+ if (p == 1) {
+ print(1);
+ } else if (p == res) {
+ print(res);
+ }
+}
+''');
+ }
+
test_singleExpression_inMethod() {
indexTestUnit('''
class A {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index fbd1d39..af7eb92 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1856,6 +1856,39 @@
}
@override
+ CompilationUnit ensureAnyResolvedDartUnit(Source source) {
+ SourceEntry sourceEntry = _cache.get(source);
+ if (sourceEntry is! DartEntry) {
+ return null;
+ }
+ DartEntry dartEntry = sourceEntry;
+ // Check if there is a resolved unit.
+ CompilationUnit unit = dartEntry.anyResolvedCompilationUnit;
+ if (unit != null) {
+ return unit;
+ }
+ // Invalidate the flushed RESOLVED_UNIT to force it eventually.
+ bool shouldBeScheduled = false;
+ List<Source> librariesContaining = dartEntry.containingLibraries;
+ for (Source librarySource in librariesContaining) {
+ if (dartEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) ==
+ CacheState.FLUSHED) {
+ dartEntry.setStateInLibrary(
+ DartEntry.RESOLVED_UNIT,
+ librarySource,
+ CacheState.INVALID);
+ shouldBeScheduled = true;
+ }
+ }
+ if (shouldBeScheduled) {
+ _workManager.add(source, SourcePriority.UNKNOWN);
+ }
+ // We cannot provide a resolved unit right now,
+ // but the future analysis will.
+ return null;
+ }
+
+ @override
bool exists(Source source) {
if (source == null) {
return false;
@@ -2184,16 +2217,12 @@
!_tryPoorMansIncrementalResolution(source, newContents)) {
_sourceChanged(source);
}
- if (sourceEntry != null) {
- sourceEntry.modificationTime =
- _contentCache.getModificationStamp(source);
- sourceEntry.setValue(SourceEntry.CONTENT, newContents);
- }
+ sourceEntry.modificationTime =
+ _contentCache.getModificationStamp(source);
+ sourceEntry.setValue(SourceEntry.CONTENT, newContents);
} else {
- if (sourceEntry != null) {
- sourceEntry.modificationTime =
- _contentCache.getModificationStamp(source);
- }
+ sourceEntry.modificationTime =
+ _contentCache.getModificationStamp(source);
}
} else if (originalContents != null) {
_incrementalAnalysisCache =
@@ -2201,17 +2230,15 @@
changed = newContents != originalContents;
// We are removing the overlay for the file, check if the file's
// contents is the same as it was in the overlay.
- if (sourceEntry != null) {
- try {
- TimestampedData<String> fileContents = getContents(source);
- String fileContentsData = fileContents.data;
- if (fileContentsData == originalContents) {
- sourceEntry.modificationTime = fileContents.modificationTime;
- sourceEntry.setValue(SourceEntry.CONTENT, fileContentsData);
- changed = false;
- }
- } catch (e) {
+ try {
+ TimestampedData<String> fileContents = getContents(source);
+ String fileContentsData = fileContents.data;
+ if (fileContentsData == originalContents) {
+ sourceEntry.modificationTime = fileContents.modificationTime;
+ sourceEntry.setValue(SourceEntry.CONTENT, fileContentsData);
+ changed = false;
}
+ } catch (e) {
}
// If not the same content (e.g. the file is being closed without save),
// then force analysis.
@@ -2226,6 +2253,31 @@
return changed;
}
+ /**
+ * Invalidates hints in the given [librarySource] and included parts.
+ */
+ void invalidateLibraryHints(Source librarySource) {
+ SourceEntry sourceEntry = _cache.get(librarySource);
+ if (sourceEntry is! DartEntry) {
+ return;
+ }
+ DartEntry dartEntry = sourceEntry;
+ // Prepare sources to invalidate hints in.
+ List<Source> sources = <Source>[librarySource];
+ sources.addAll(dartEntry.getValue(DartEntry.INCLUDED_PARTS));
+ // Invalidate hints.
+ for (Source source in sources) {
+ DartEntry dartEntry = _cache.get(source);
+ if (dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource) ==
+ CacheState.VALID) {
+ dartEntry.setStateInLibrary(
+ DartEntry.HINTS,
+ librarySource,
+ CacheState.INVALID);
+ }
+ }
+ }
+
@override
bool isClientLibrary(Source librarySource) {
SourceEntry sourceEntry = _getReadableSourceEntry(librarySource);
@@ -5043,19 +5095,9 @@
if (libraryElement == null) {
return false;
}
- // prepare the existing library units
- Map<Source, CompilationUnit> units = <Source, CompilationUnit>{};
- for (CompilationUnitElement unitElement in libraryElement.units) {
- Source unitSource = unitElement.source;
- CompilationUnit unit =
- getResolvedCompilationUnit2(unitSource, librarySource);
- if (unit == null) {
- return false;
- }
- units[unitSource] = unit;
- }
// prepare the existing unit
- CompilationUnit oldUnit = units[unitSource];
+ CompilationUnit oldUnit =
+ getResolvedCompilationUnit2(unitSource, librarySource);
if (oldUnit == null) {
return false;
}
@@ -5063,9 +5105,9 @@
Stopwatch perfCounter = new Stopwatch()..start();
PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
typeProvider,
- units,
unitSource,
dartEntry,
+ oldUnit,
analysisOptions.incrementalApi);
bool success = resolver.resolve(newCode);
AnalysisEngine.instance.instrumentationService.logPerformance(
@@ -5083,14 +5125,13 @@
incrementalResolutionValidation_lastUnit = oldUnit;
return false;
}
- // prepare notices
- units.forEach((Source source, CompilationUnit unit) {
- DartEntry dartEntry = _cache.get(source);
- LineInfo lineInfo = getLineInfo(source);
- ChangeNoticeImpl notice = _getNotice(source);
- notice.resolvedDartUnit = unit;
+ // prepare notice
+ {
+ LineInfo lineInfo = getLineInfo(unitSource);
+ ChangeNoticeImpl notice = _getNotice(unitSource);
+ notice.resolvedDartUnit = oldUnit;
notice.setErrors(dartEntry.allErrors, lineInfo);
- });
+ }
// OK
return true;
}
@@ -9613,7 +9654,6 @@
LibraryElement library = element.library;
if (library != null) {
IncrementalResolver resolver = new IncrementalResolver(
- <Source, CompilationUnit>{},
element,
cache.offset,
cache.oldLength,
@@ -9703,6 +9743,13 @@
CompilationUnit computeResolvableCompilationUnit(Source source);
/**
+ * Return any resolved [CompilationUnit] for the given [source] if not
+ * flushed, otherwise return `null` and ensures that the [CompilationUnit]
+ * will be eventually returned to the client from [performAnalysisTask].
+ */
+ CompilationUnit ensureAnyResolvedDartUnit(Source source);
+
+ /**
* Return context that owns the given source.
*
* @param source the source whose context is to be returned
@@ -9725,7 +9772,7 @@
* is the updated contents. If [notify] is true, a source changed event is
* triggered.
*
- * Normally it should not be necessary for clinets to call this function,
+ * Normally it should not be necessary for clients to call this function,
* since it will be automatically invoked in response to a call to
* [applyChanges] or [setContents]. However, if this analysis context is
* sharing its content cache with other contexts, then the client must
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 50bba03..06026b3 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -7,6 +7,8 @@
import "dart:math" as math;
import 'dart:collection';
+import 'package:analyzer/src/generated/static_type_analyzer.dart';
+
import 'ast.dart';
import 'constant.dart';
import 'element.dart';
@@ -5885,10 +5887,9 @@
}
}
DartType staticReturnType = getStaticType(returnExpression);
- if (staticReturnType != null &&
- _enclosingFunction.isAsynchronous &&
- staticReturnType.element != _typeProvider.futureType.element) {
- return _typeProvider.futureType.substitute4(<DartType>[staticReturnType]);
+ if (staticReturnType != null && _enclosingFunction.isAsynchronous) {
+ return _typeProvider.futureType.substitute4(
+ <DartType>[StaticTypeAnalyzer.flattenFutures(_typeProvider, staticReturnType)]);
}
return staticReturnType;
}
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 152bb47..038d0f0 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -787,11 +787,6 @@
*/
class IncrementalResolver {
/**
- * All resolved units of the [_definingLibrary].
- */
- final Map<Source, CompilationUnit> _units;
-
- /**
* The element of the compilation unit being resolved.
*/
final CompilationUnitElement _definingUnit;
@@ -854,7 +849,7 @@
* Initialize a newly created incremental resolver to resolve a node in the
* given source in the given library.
*/
- IncrementalResolver(this._units, this._definingUnit, this._updateOffset,
+ IncrementalResolver(this._definingUnit, this._updateOffset,
this._updateEndOld, this._updateEndNew) {
_updateDelta = _updateEndNew - _updateEndOld;
_definingLibrary = _definingUnit.library;
@@ -887,7 +882,7 @@
_resolveReferences(rootNode);
// verify
_verify(rootNode);
- _generateHints(rootNode);
+ _context.invalidateLibraryHints(_librarySource);
_generateLints(rootNode);
// update entry errors
_updateEntry();
@@ -978,33 +973,6 @@
throw new AnalysisException("Cannot resolve node: no resolvable node");
}
- void _generateHints(AstNode node) {
- LoggingTimer timer = logger.startTimer();
- try {
- RecordingErrorListener errorListener = new RecordingErrorListener();
- // prepare a list of the library units
- List<CompilationUnit> units;
- {
- CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
- _units[_source] = unit;
- units = _units.values.toList();
- }
- // run the generator
- AnalysisContext analysisContext = _definingLibrary.context;
- HintGenerator hintGenerator =
- new HintGenerator(units, analysisContext, errorListener);
- hintGenerator.generateForLibrary();
- // remember hints
- for (Source source in _units.keys) {
- List<AnalysisError> hints = errorListener.getErrorsForSource(source);
- DartEntry entry = _context.getReadableSourceEntryOrNull(source);
- entry.setValueInLibrary(DartEntry.HINTS, _librarySource, hints);
- }
- } finally {
- timer.stop('generate hints');
- }
- }
-
void _generateLints(AstNode node) {
LoggingTimer timer = logger.startTimer();
try {
@@ -1189,9 +1157,9 @@
class PoorMansIncrementalResolver {
final TypeProvider _typeProvider;
- final Map<Source, CompilationUnit> _units;
final Source _unitSource;
final DartEntry _entry;
+ final CompilationUnit _oldUnit;
CompilationUnitElement _unitElement;
int _updateOffset;
@@ -1202,26 +1170,25 @@
List<AnalysisError> _newScanErrors = <AnalysisError>[];
List<AnalysisError> _newParseErrors = <AnalysisError>[];
- PoorMansIncrementalResolver(this._typeProvider, this._units, this._unitSource,
- this._entry, bool resolveApiChanges) {
+ PoorMansIncrementalResolver(this._typeProvider, this._unitSource,
+ this._entry, this._oldUnit, bool resolveApiChanges) {
_resolveApiChanges = resolveApiChanges;
}
/**
- * Attempts to update [oldUnit] to the state corresponding to [newCode].
+ * Attempts to update [_oldUnit] to the state corresponding to [newCode].
* Returns `true` if success, or `false` otherwise.
- * The [oldUnit] might be damaged.
+ * The [_oldUnit] might be damaged.
*/
bool resolve(String newCode) {
logger.enter('diff/resolve $_unitSource');
try {
// prepare old unit
- CompilationUnit oldUnit = _units[_unitSource];
- if (!_areCurlyBracketsBalanced(oldUnit.beginToken)) {
+ if (!_areCurlyBracketsBalanced(_oldUnit.beginToken)) {
logger.log('Unbalanced number of curly brackets in the old unit.');
return false;
}
- _unitElement = oldUnit.element;
+ _unitElement = _oldUnit.element;
// prepare new unit
CompilationUnit newUnit = _parseUnit(newCode);
if (!_areCurlyBracketsBalanced(newUnit.beginToken)) {
@@ -1230,9 +1197,9 @@
}
// find difference
_TokenPair firstPair =
- _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken);
+ _findFirstDifferentToken(_oldUnit.beginToken, newUnit.beginToken);
_TokenPair lastPair =
- _findLastDifferentToken(oldUnit.endToken, newUnit.endToken);
+ _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken);
if (firstPair != null && lastPair != null) {
int firstOffsetOld = firstPair.oldToken.offset;
int firstOffsetNew = firstPair.newToken.offset;
@@ -1248,10 +1215,10 @@
_updateOffset = beginOffsetOld - 1;
_updateEndOld = endOffsetOld;
_updateEndNew = endOffsetNew;
- _updateDelta = newUnit.length - oldUnit.length;
+ _updateDelta = newUnit.length - _oldUnit.length;
// A Dart documentation comment change.
if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) {
- bool success = _resolveComment(oldUnit, newUnit, firstPair);
+ bool success = _resolveComment(_oldUnit, newUnit, firstPair);
logger.log('Documentation comment resolved: $success');
return success;
}
@@ -1261,7 +1228,6 @@
_shiftTokens(firstPair.oldToken);
{
IncrementalResolver incrementalResolver = new IncrementalResolver(
- _units,
_unitElement,
_updateOffset,
_updateEndOld,
@@ -1277,7 +1243,7 @@
}
// Find nodes covering the "old" and "new" token ranges.
AstNode oldNode =
- _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld);
+ _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld);
AstNode newNode =
_findNodeCovering(newUnit, beginOffsetNew, endOffsetNew);
logger.log(() => 'oldNode: $oldNode');
@@ -1325,7 +1291,7 @@
Token oldBeginToken = _getBeginTokenNotComment(oldNode);
Token newBeginToken = _getBeginTokenNotComment(newNode);
if (oldBeginToken.previous.type == TokenType.EOF) {
- oldUnit.beginToken = newBeginToken;
+ _oldUnit.beginToken = newBeginToken;
} else {
oldBeginToken.previous.setNext(newBeginToken);
}
@@ -1334,7 +1300,6 @@
}
// perform incremental resolution
IncrementalResolver incrementalResolver = new IncrementalResolver(
- _units,
_unitElement,
_updateOffset,
_updateEndOld,
@@ -1402,7 +1367,6 @@
NodeReplacer.replace(oldComment, newComment);
// update elements
IncrementalResolver incrementalResolver = new IncrementalResolver(
- _units,
_unitElement,
_updateOffset,
_updateEndOld,
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 99a51ce..7b461df 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -175,6 +175,34 @@
}
/**
+ * The Dart Language Specification, 16.29 (Await Expressions):
+ *
+ * Let flatten(T) = flatten(S) if T = Future<S>, and T otherwise. The
+ * static type of [the expression "await e"] is flatten(T) where T is the
+ * static type of e.
+ */
+ @override
+ Object visitAwaitExpression(AwaitExpression node) {
+ DartType staticExpressionType = _getStaticType(node.expression);
+ if (staticExpressionType == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticExpressionType = _dynamicType;
+ }
+ DartType staticType = flattenFutures(_typeProvider, staticExpressionType);
+ _recordStaticType(node, staticType);
+ DartType propagatedExpressionType = node.expression.propagatedType;
+ if (propagatedExpressionType != null) {
+ DartType propagatedType =
+ flattenFutures(_typeProvider, propagatedExpressionType);
+ if (propagatedType != null &&
+ propagatedType.isMoreSpecificThan(staticType)) {
+ _recordPropagatedType(node, propagatedType);
+ }
+ }
+ return null;
+ }
+
+ /**
* The Dart Language Specification, 12.20: <blockquote>The static type of a logical boolean
* expression is `bool`.</blockquote>
*
@@ -1772,6 +1800,19 @@
}
/**
+ * Implements the function "flatten" defined in the spec: "Let flatten(T) =
+ * flatten(S) if T = Future<S>, and T otherwise."
+ */
+ static DartType flattenFutures(TypeProvider typeProvider, DartType type) {
+ if (type is InterfaceType &&
+ type.element == typeProvider.futureType.element &&
+ type.typeArguments.length > 0) {
+ return flattenFutures(typeProvider, type.typeArguments[0]);
+ }
+ return type;
+ }
+
+ /**
* Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
* implement those tags.
*
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index ff1e30a..f95e230 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -507,7 +507,13 @@
}
visitBlockFunctionBody(BlockFunctionBody node) {
- token(node.keyword, followedBy: nonBreakingSpace);
+ // sync[*] or async[*]
+ token(node.keyword);
+ token(node.star);
+ if (node.keyword != null) {
+ nonBreakingSpace();
+ }
+
visit(node.block);
}
@@ -836,6 +842,7 @@
}
visitForEachStatement(ForEachStatement node) {
+ token(node.awaitKeyword, followedBy: nonBreakingSpace);
token(node.forKeyword);
space();
token(node.leftParenthesis);
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index a30c5f6..0089eb8 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -6048,6 +6048,11 @@
fail("Unexpected invocation of dispose");
}
@override
+ CompilationUnit ensureAnyResolvedDartUnit(Source source) {
+ fail("Unexpected invocation of ensureAnyResolvedDartUnit");
+ return null;
+ }
+ @override
bool exists(Source source) {
fail("Unexpected invocation of exists");
return false;
@@ -6210,6 +6215,7 @@
void setContents(Source source, String contents) {
fail("Unexpected invocation of setContents");
}
+
@override
void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
DataDescriptor rowDesc, CacheState state)) {
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 90106a9..5e41ef6 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -2506,13 +2506,14 @@
int updateOffset = edit.offset;
int updateEndOld = updateOffset + edit.length;
int updateOldNew = updateOffset + edit.replacement.length;
- IncrementalResolver resolver =
- new IncrementalResolver(<Source, CompilationUnit>{
- source: newUnit
- }, unit.element, updateOffset, updateEndOld, updateOldNew);
+ IncrementalResolver resolver = new IncrementalResolver(
+ unit.element,
+ updateOffset,
+ updateEndOld,
+ updateOldNew);
bool success = resolver.resolve(newNode);
expect(success, isTrue);
- List<AnalysisError> newErrors = analysisContext.getErrors(source).errors;
+ List<AnalysisError> newErrors = analysisContext.computeErrors(source);
// resolve "newCode" from scratch
CompilationUnit fullNewUnit;
{
@@ -3211,8 +3212,13 @@
// a._foo();
}
''');
+ // no hints right now, because we delay hints computing
+ {
+ List<AnalysisError> errors = analysisContext.getErrors(source).errors;
+ expect(errors, isEmpty);
+ }
// a new hint should be added
- List<AnalysisError> errors = analysisContext.getErrors(source).errors;
+ List<AnalysisError> errors = analysisContext.computeErrors(source);
expect(errors, hasLength(1));
expect(errors[0].errorCode.type, ErrorType.HINT);
// the same hint should be reported using a ChangeNotice
@@ -3458,7 +3464,7 @@
_resetWithIncremental(true);
analysisContext2.setContents(source, newCode);
CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
- List<AnalysisError> newErrors = analysisContext.getErrors(source).errors;
+ List<AnalysisError> newErrors = analysisContext.computeErrors(source);
// check for expected failure
if (!expectedSuccess) {
expect(newUnit.element, isNot(same(oldUnitElement)));
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 680045a..3238e50 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -487,6 +487,19 @@
verify([source]);
}
+ void test_async_return_flattens_futures() {
+ Source source = addSource('''
+import 'dart:async';
+Future<int> f() async {
+ return g();
+}
+Future<Future<int>> g() => null;
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_async_with_return() {
Source source = addSource('''
f() async {
@@ -540,6 +553,32 @@
verify([source]);
}
+ void test_await_flattened() {
+ Source source = addSource('''
+import 'dart:async';
+Future<Future<int>> ffi() => null;
+f() async {
+ int b = await ffi();
+}
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_await_simple() {
+ Source source = addSource('''
+import 'dart:async';
+Future<int> fi() => null;
+f() async {
+ int a = await fi();
+}
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_awaitInWrongContext_async() {
Source source = addSource(r'''
f(x, y) async {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 17c8e69..b2f48d0 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -9851,6 +9851,30 @@
_listener.assertNoErrors();
}
+ void test_visitAwaitExpression_flattened() {
+ // await e, where e has type Future<Future<int>>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ InterfaceType futureFutureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[futureIntType]);
+ Expression node =
+ AstFactory.awaitExpression(_resolvedVariable(futureFutureIntType, 'e'));
+ expect(_analyze(node), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAwaitExpression_simple() {
+ // await e, where e has type Future<int>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ Expression node =
+ AstFactory.awaitExpression(_resolvedVariable(futureIntType, 'e'));
+ expect(_analyze(node), same(intType));
+ _listener.assertNoErrors();
+ }
+
void test_visitBinaryExpression_equals() {
// 2 == 3
Expression node = AstFactory.binaryExpression(
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index bf70201..c0ea73e 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -54,6 +54,32 @@
assertErrors(source, [StaticWarningCode.AMBIGUOUS_IMPORT]);
}
+ void test_await_flattened() {
+ Source source = addSource('''
+import 'dart:async';
+Future<Future<int>> ffi() => null;
+f() async {
+ Future<int> b = await ffi(); // Warning: int not assignable to Future<int>
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_await_simple() {
+ Source source = addSource('''
+import 'dart:async';
+Future<int> fi() => null;
+f() async {
+ String a = await fi(); // Warning: int not assignable to String
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
void test_expectedOneListTypeArgument() {
Source source = addSource(r'''
main() {
diff --git a/pkg/analyzer/test/services/data/cu_tests.data b/pkg/analyzer/test/services/data/cu_tests.data
index 9f9e803..0c5ae6b 100644
--- a/pkg/analyzer/test/services/data/cu_tests.data
+++ b/pkg/analyzer/test/services/data/cu_tests.data
@@ -308,18 +308,16 @@
this.c0123456789012345678901234, this.d0123456789012345678901234);
}
>>>
-main() async {
-}
-<<<
-main() async {
-}
->>>
-main() async => 0;
-<<<
-main() async => 0;
->>>
enum Foo { BAR, BAZ }
<<<
enum Foo {
BAR, BAZ
}
+>>>
+get x sync* {}
+<<<
+get x sync* {}
+>>>
+get x async* {}
+<<<
+get x async* {}
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/data/stmt_tests.data b/pkg/analyzer/test/services/data/stmt_tests.data
index d1cf4cc..ef98247 100644
--- a/pkg/analyzer/test/services/data/stmt_tests.data
+++ b/pkg/analyzer/test/services/data/stmt_tests.data
@@ -205,3 +205,59 @@
00000000000000000000000000000000000000000000000000000000000,
111);
}
+>>>
+foo() async => 42;
+<<<
+foo() async => 42;
+>>>
+main() async {
+ await window.animationFrame;
+}
+<<<
+main() async {
+ await window.animationFrame;
+}
+>>>
+main() async* {
+ await window.animationFrame;
+}
+<<<
+main() async* {
+ await window.animationFrame;
+}
+>>>
+foo() async* {
+ var elements = await _post('elements', by);
+ int i = 0;
+ for (var element in elements) {
+ yield new WebElement._(driver, element['ELEMENT'], this, by, i);
+ i++;
+ }
+}
+<<<
+foo() async* {
+ var elements = await _post('elements', by);
+ int i = 0;
+ for (var element in elements) {
+ yield new WebElement._(driver, element['ELEMENT'], this, by, i);
+ i++;
+ }
+}
+>>>
+b06a() async { await for (var o in st) {} }
+<<<
+b06a() async {
+ await for (var o in st) {}
+}
+>>>
+b07a() sync* { yield 0; }
+<<<
+b07a() sync* {
+ yield 0;
+}
+>>>
+b08a() sync* { yield* []; }
+<<<
+b08a() sync* {
+ yield* [];
+}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 173f421..a99134f 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -2395,6 +2395,22 @@
@override
InterfaceType get stringType => stringClass.computeType(compiler);
+
+ @override
+ InterfaceType iterableType([DartType elementType = const DynamicType()]) {
+ return iterableClass.computeType(compiler)
+ .createInstantiation([elementType]);
+ }
+
+ @override
+ InterfaceType futureType([DartType elementType = const DynamicType()]) {
+ return futureClass.computeType(compiler).createInstantiation([elementType]);
+ }
+
+ @override
+ InterfaceType streamType([DartType elementType = const DynamicType()]) {
+ return streamClass.computeType(compiler).createInstantiation([elementType]);
+ }
}
typedef void InternalErrorFunction(Spannable location, String message);
diff --git a/pkg/compiler/lib/src/core_types.dart b/pkg/compiler/lib/src/core_types.dart
index 291978d..ba71b3f 100644
--- a/pkg/compiler/lib/src/core_types.dart
+++ b/pkg/compiler/lib/src/core_types.dart
@@ -40,4 +40,16 @@
/// [keyType] and [valueType] as its type arguments.
InterfaceType mapType([DartType keyType = const DynamicType(),
DartType valueType = const DynamicType()]);
+
+ /// Returns an instance of the `Iterable` type defined in 'dart:core' with
+ /// [elementType] as its type argument.
+ InterfaceType iterableType([DartType elementType = const DynamicType()]);
+
+ /// Returns an instance of the `Future` type defined in 'dart:async' with
+ /// [elementType] as its type argument.
+ InterfaceType futureType([DartType elementType = const DynamicType()]);
+
+ /// Returns an instance of the `Stream` type defined in 'dart:async' with
+ /// [elementType] as its type argument.
+ InterfaceType streamType([DartType elementType = const DynamicType()]);
}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index cbf4ef5..335a92b 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -14,6 +14,7 @@
import '../util/util.dart';
import 'cps_ir_nodes.dart';
import '../types/types.dart' show TypeMask, TypesTask;
+import '../core_types.dart' show CoreTypes;
import '../types/constants.dart' show computeTypeMask;
import '../elements/elements.dart' show ClassElement, Element, Entity,
FieldElement, FunctionElement, ParameterElement;
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index c90f777..dc36d80 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -53,6 +53,7 @@
TypeMask get listType => inferrer.listType;
TypeMask get mapType => inferrer.mapType;
+ // TODO(karlklose): remove compiler here.
TypeMaskSystem(dart2js.Compiler compiler)
: inferrer = compiler.typesTask,
classWorld = compiler.world;
@@ -92,8 +93,6 @@
* by Wegman, Zadeck.
*/
class TypePropagator<T> extends PassMixin {
- // TODO(karlklose): remove reference to _compiler. It is currently used to
- // compute [TypeMask]s.
final types.DartTypes _dartTypes;
// The constant system is used for evaluation of expressions with constant
@@ -103,7 +102,6 @@
final dart2js.InternalErrorFunction _internalError;
final Map<Node, _AbstractValue> _types;
-
TypePropagator(this._dartTypes,
this._constantSystem,
this._typeSystem,
@@ -307,42 +305,43 @@
final Set<Definition> defWorkset = new Set<Definition>();
final dart2js.ConstantSystem constantSystem;
- final TypeSystem typeSystem;
+ final TypeSystem<T> typeSystem;
final dart2js.InternalErrorFunction internalError;
final types.DartTypes _dartTypes;
- _AbstractValue unknownDynamic;
+ _AbstractValue<T> unknownDynamic;
- _AbstractValue unknown([T t]) {
+ _AbstractValue<T> unknown([T t]) {
if (t == null) {
return unknownDynamic;
} else {
- return new _AbstractValue.unknown(t);
+ return new _AbstractValue<T>.unknown(t);
}
}
- _AbstractValue nonConst([T type]) {
+ _AbstractValue<T> nonConst([T type]) {
if (type == null) {
type = typeSystem.dynamicType;
}
- return new _AbstractValue.nonConst(type);
+ return new _AbstractValue<T>.nonConst(type);
}
- _AbstractValue constantValue(ConstantValue constant, T type) {
- return new _AbstractValue(constant, type);
+ _AbstractValue<T> constantValue(ConstantValue constant, T type) {
+ return new _AbstractValue<T>(constant, type);
}
// Stores the current lattice value for nodes. Note that it contains not only
// definitions as keys, but also expressions such as method invokes.
// Access through [getValue] and [setValue].
- final Map<Node, _AbstractValue> values;
+ final Map<Node, _AbstractValue<T>> values;
_TypePropagationVisitor(this.constantSystem,
TypeSystem typeSystem,
this.values,
this.internalError,
this._dartTypes)
- : this.unknownDynamic = new _AbstractValue.unknown(typeSystem.dynamicType),
+ : this.unknownDynamic =
+ new _AbstractValue<T>.unknown(typeSystem.dynamicType),
this.typeSystem = typeSystem;
void analyze(ExecutableDefinition root) {
@@ -387,17 +386,17 @@
/// Returns the lattice value corresponding to [node], defaulting to unknown.
///
/// Never returns null.
- _AbstractValue getValue(Node node) {
- _AbstractValue value = values[node];
+ _AbstractValue<T> getValue(Node node) {
+ _AbstractValue<T> value = values[node];
return (value == null) ? unknown() : value;
}
/// Joins the passed lattice [updateValue] to the current value of [node],
/// and adds it to the definition work set if it has changed and [node] is
/// a definition.
- void setValue(Node node, _AbstractValue updateValue) {
- _AbstractValue oldValue = getValue(node);
- _AbstractValue newValue = updateValue.join(oldValue, typeSystem);
+ void setValue(Node node, _AbstractValue<T> updateValue) {
+ _AbstractValue<T> oldValue = getValue(node);
+ _AbstractValue<T> newValue = updateValue.join(oldValue, typeSystem);
if (oldValue == newValue) {
return;
}
@@ -472,7 +471,7 @@
// continuation. Note that this is effectively a phi node in SSA terms.
for (int i = 0; i < node.arguments.length; i++) {
Definition def = node.arguments[i].definition;
- _AbstractValue cell = getValue(def);
+ _AbstractValue<T> cell = getValue(def);
setValue(cont.parameters[i], cell);
}
}
@@ -483,13 +482,13 @@
/// Sets the value of both the current node and the target continuation
/// parameter.
- void setValues(_AbstractValue updateValue) {
+ void setValues(_AbstractValue<T> updateValue) {
setValue(node, updateValue);
Parameter returnValue = cont.parameters[0];
setValue(returnValue, updateValue);
}
- _AbstractValue lhs = getValue(node.receiver.definition);
+ _AbstractValue<T> lhs = getValue(node.receiver.definition);
if (lhs.isUnknown) {
// This may seem like a missed opportunity for evaluating short-circuiting
// boolean operations; we are currently skipping these intentionally since
@@ -523,7 +522,7 @@
} else if (node.selector.argumentCount == 1) {
// Binary operator.
- _AbstractValue rhs = getValue(node.arguments[0].definition);
+ _AbstractValue<T> rhs = getValue(node.arguments[0].definition);
if (!rhs.isConstant) {
setValues(rhs);
return;
@@ -541,7 +540,7 @@
setValues(nonConst());
} else {
T type = typeSystem.typeOf(result);
- setValues(new _AbstractValue(result, type));
+ setValues(new _AbstractValue<T>(result, type));
}
}
@@ -568,7 +567,7 @@
Continuation cont = node.continuation.definition;
setReachable(cont);
- void setValues(_AbstractValue updateValue) {
+ void setValues(_AbstractValue<T> updateValue) {
setValue(node, updateValue);
Parameter returnValue = cont.parameters[0];
setValue(returnValue, updateValue);
@@ -595,7 +594,7 @@
});
LiteralDartString dartString = new LiteralDartString(allStrings.join());
ConstantValue constant = new StringConstantValue(dartString);
- setValues(new _AbstractValue(constant, type));
+ setValues(new _AbstractValue<T>(constant, type));
} else {
setValues(nonConst(type));
}
@@ -603,7 +602,7 @@
void visitBranch(Branch node) {
IsTrue isTrue = node.condition;
- _AbstractValue conditionCell = getValue(isTrue.value.definition);
+ _AbstractValue<T> conditionCell = getValue(isTrue.value.definition);
if (conditionCell.isUnknown) {
return; // And come back later.
@@ -630,7 +629,7 @@
Continuation cont = node.continuation.definition;
setReachable(cont);
- void setValues(_AbstractValue updateValue) {
+ void setValues(_AbstractValue<T> updateValue) {
setValue(node, updateValue);
Parameter returnValue = cont.parameters[0];
setValue(returnValue, updateValue);
@@ -641,7 +640,7 @@
setValues(nonConst());
}
- _AbstractValue cell = getValue(node.receiver.definition);
+ _AbstractValue<T> cell = getValue(node.receiver.definition);
if (cell.isUnknown) {
return; // And come back later.
} else if (cell.isNonConst) {
@@ -655,7 +654,7 @@
types.DartType constantType = constant.getType(_dartTypes.coreTypes);
T type = typeSystem.boolType;
- _AbstractValue result;
+ _AbstractValue<T> result;
if (constant.isNull &&
checkedType != _dartTypes.coreTypes.nullType &&
checkedType != _dartTypes.coreTypes.objectType) {
@@ -775,8 +774,8 @@
// JavaScript specific nodes.
void visitIdentical(Identical node) {
- _AbstractValue leftConst = getValue(node.left.definition);
- _AbstractValue rightConst = getValue(node.right.definition);
+ _AbstractValue<T> leftConst = getValue(node.left.definition);
+ _AbstractValue<T> rightConst = getValue(node.right.definition);
ConstantValue leftValue = leftConst.constant;
ConstantValue rightValue = rightConst.constant;
if (leftConst.isUnknown || rightConst.isUnknown) {
@@ -797,7 +796,7 @@
PrimitiveConstantValue right = rightValue;
ConstantValue result =
new BoolConstantValue(left.primitiveValue == right.primitiveValue);
- setValue(node, new _AbstractValue(result, typeSystem.boolType));
+ setValue(node, new _AbstractValue<T>(result, typeSystem.boolType));
}
}
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index a055e95..b7c4bba 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -1157,16 +1157,16 @@
/// Enum for the synchronous/asynchronous function body modifiers.
class AsyncMarker {
/// The default function body marker.
- static AsyncMarker SYNC = const AsyncMarker._();
+ static const AsyncMarker SYNC = const AsyncMarker._();
/// The `sync*` function body marker.
- static AsyncMarker SYNC_STAR = const AsyncMarker._(isYielding: true);
+ static const AsyncMarker SYNC_STAR = const AsyncMarker._(isYielding: true);
/// The `async` function body marker.
- static AsyncMarker ASYNC = const AsyncMarker._(isAsync: true);
+ static const AsyncMarker ASYNC = const AsyncMarker._(isAsync: true);
/// The `async*` function body marker.
- static AsyncMarker ASYNC_STAR =
+ static const AsyncMarker ASYNC_STAR =
const AsyncMarker._(isAsync: true, isYielding: true);
/// Is `true` if this marker defines the function body to have an
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index edb9c57..b3ec3fd 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -93,6 +93,8 @@
String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
+ final Annotations annotations = new Annotations();
+
/// List of [FunctionElement]s that we want to inline always. This list is
/// filled when resolution is complete by looking up in [internalLibrary].
List<FunctionElement> functionsToAlwaysInline;
@@ -459,7 +461,7 @@
resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
patchResolverTask = new PatchResolverTask(compiler);
functionCompiler = USE_CPS_IR
- ? new CspFunctionCompiler(compiler, this)
+ ? new CpsFunctionCompiler(compiler, this)
: new SsaFunctionCompiler(this, generateSourceMap);
}
@@ -1805,6 +1807,7 @@
} else if (uri == DART_HTML) {
htmlLibraryIsLoaded = true;
}
+ annotations.onLibraryScanned(library);
});
}
@@ -2333,6 +2336,65 @@
}
}
+/// Handling of special annotations for tests.
+class Annotations {
+ static final Uri PACKAGE_EXPECT =
+ new Uri(scheme: 'package', path: 'expect/expect.dart');
+
+ ClassElement expectNoInliningClass;
+ ClassElement expectTrustTypeAnnotationsClass;
+ ClassElement expectAssumeDynamicClass;
+
+ void onLibraryScanned(LibraryElement library) {
+ if (library.canonicalUri == PACKAGE_EXPECT) {
+ expectNoInliningClass = library.find('NoInlining');
+ expectTrustTypeAnnotationsClass = library.find('TrustTypeAnnotations');
+ expectAssumeDynamicClass = library.find('AssumeDynamic');
+ if (expectNoInliningClass == null ||
+ expectTrustTypeAnnotationsClass == null ||
+ expectAssumeDynamicClass == null) {
+ // This is not the package you're looking for.
+ expectNoInliningClass = null;
+ expectTrustTypeAnnotationsClass = null;
+ expectAssumeDynamicClass = null;
+ }
+ }
+ }
+
+ /// Returns `true` if inlining is disabled for [element].
+ bool noInlining(Element element) {
+ return _hasAnnotation(element, expectNoInliningClass);
+ }
+
+ /// Returns `true` if parameter and returns types should be trusted for
+ /// [element].
+ bool trustTypeAnnotations(Element element) {
+ return _hasAnnotation(element, expectTrustTypeAnnotationsClass);
+ }
+
+ /// Returns `true` if inference of parameter types is disabled for [element].
+ bool assumeDynamic(Element element) {
+ return _hasAnnotation(element, expectAssumeDynamicClass);
+ }
+
+ /// Returns `true` if [element] is annotated with [annotationClass].
+ bool _hasAnnotation(Element element, ClassElement annotationClass) {
+ if (annotationClass == null) return false;
+ for (Link<MetadataAnnotation> link = element.metadata;
+ !link.isEmpty;
+ link = link.tail) {
+ ConstantValue value = link.head.constant.value;
+ if (value.isConstructedObject) {
+ ConstructedConstantValue constructedConstant = value;
+ if (constructedConstant.type.element == annotationClass) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
final JavaScriptBackend backend;
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index f930b90..1237350 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -83,7 +83,8 @@
return new js.Fun(parameters, new js.Block(accumulator));
}
- js.Expression visit(tree_ir.Expression node) {
+ @override
+ js.Expression visitExpression(tree_ir.Expression node) {
js.Expression result = node.accept(this);
if (result == null) {
glue.reportInternalError('$node did not produce code.');
@@ -141,9 +142,9 @@
@override
js.Expression visitConditional(tree_ir.Conditional node) {
return new js.Conditional(
- visit(node.condition),
- visit(node.thenExpression),
- visit(node.elseExpression));
+ visitExpression(node.condition),
+ visitExpression(node.thenExpression),
+ visitExpression(node.elseExpression));
}
js.Expression buildConstant(ConstantValue constant) {
@@ -166,6 +167,7 @@
return buildConstant(glue.getConstantForVariable(parameter).value);
}
+ // TODO(karlklose): get rid of the selector argument.
js.Expression buildStaticInvoke(Selector selector,
Element target,
List<js.Expression> arguments) {
@@ -182,21 +184,31 @@
return js.propertyCall(interceptorLibrary, selector.name, arguments);
} else {
js.Expression elementAccess = glue.staticFunctionAccess(target);
- List<js.Expression> compiledArguments =
- selector.makeArgumentsList(target.implementation,
- arguments,
- compileConstant);
- return new js.Call(elementAccess, compiledArguments);
+ return new js.Call(elementAccess, arguments);
}
}
+ List<js.Expression> compileStaticArgumentList(
+ Selector selector,
+ Element target, /* TODO(karlklose): this should be the signature. */
+ List<tree_ir.Expression> arguments) {
+ return selector.makeArgumentsList(
+ target.implementation,
+ visitArguments(arguments),
+ compileConstant);
+ }
+
@override
js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
+ checkStaticTargetIsValid(node, node.target);
+
if (node.constant != null) return giveup(node);
registry.registerInstantiatedClass(node.target.enclosingClass);
- return buildStaticInvoke(node.selector,
- node.target,
- visitArguments(node.arguments));
+ Selector selector = node.selector;
+ FunctionElement target = node.target;
+ List<js.Expression> arguments =
+ compileStaticArgumentList(selector, target, node.arguments);
+ return buildStaticInvoke(selector, target, arguments);
}
void registerMethodInvoke(tree_ir.InvokeMethod node) {
@@ -224,14 +236,32 @@
visitArguments(node.arguments));
}
+ /// Checks that the target of the static call is not an [ErroneousElement].
+ ///
+ /// This helper should be removed and the code to generate the CPS IR for
+ /// the dart2js backend should construct a call to a helper that throw an
+ /// appropriate error message instead of the static call.
+ ///
+ /// See [SsaBuilder.visitStaticSend] as an example how to do this.
+ void checkStaticTargetIsValid(tree_ir.Node node, Element target) {
+ if (target.isErroneous) {
+ giveup(node, 'cannot generate error handling code'
+ ' for call to unresolved target');
+ }
+ }
+
@override
js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) {
+ checkStaticTargetIsValid(node, node.target);
+
if (node.target is! FunctionElement) {
giveup(node, 'static getters and setters are not supported.');
}
- return buildStaticInvoke(node.selector,
- node.target,
- visitArguments(node.arguments));
+ Selector selector = node.selector;
+ FunctionElement target = node.target;
+ List<js.Expression> arguments =
+ compileStaticArgumentList(selector, target, node.arguments);
+ return buildStaticInvoke(selector, target, arguments);
}
@override
@@ -275,8 +305,9 @@
entries[2 * i] = visitExpression(node.entries[i].key);
entries[2 * i + 1] = visitExpression(node.entries[i].value);
}
- List<js.Expression> args =
- <js.Expression>[new js.ArrayInitializer(entries)];
+ List<js.Expression> args = entries.isEmpty
+ ? <js.Expression>[]
+ : <js.Expression>[new js.ArrayInitializer(entries)];
return buildStaticInvoke(
new Selector.call(constructor.name, constructor.library, 2),
constructor,
@@ -285,7 +316,10 @@
@override
js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
- return new js.Binary(node.operator, visit(node.left), visit(node.right));
+ return new js.Binary(
+ node.operator,
+ visitExpression(node.left),
+ visitExpression(node.right));
}
@override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index d50f32a..4797173 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -32,7 +32,7 @@
import '../../cps_ir/cps_ir_nodes_sexpr.dart';
import 'js_tree_builder.dart';
-class CspFunctionCompiler implements FunctionCompiler {
+class CpsFunctionCompiler implements FunctionCompiler {
final IrBuilderTask irBuilderTask;
final ConstantSystem constantSystem;
final Compiler compiler;
@@ -45,7 +45,7 @@
Tracer get tracer => compiler.tracer;
- CspFunctionCompiler(Compiler compiler, JavaScriptBackend backend)
+ CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend)
: irBuilderTask = new IrBuilderTask(compiler),
fallbackCompiler = new ssa.SsaFunctionCompiler(backend, true),
constantSystem = backend.constantSystem,
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
index 30d81ed..6e37f27 100644
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
@@ -6,6 +6,7 @@
import '../../dart2jslib.dart' show Compiler;
import '../../dart_types.dart' show DartType;
+import '../../elements/elements.dart' show ClassElement;
import '../../js/js.dart' as js;
import '../../js_backend/js_backend.dart' show
JavaScriptBackend,
@@ -32,6 +33,7 @@
import '../model.dart';
+
class ModelEmitter {
final Compiler compiler;
final Namer namer;
@@ -209,8 +211,7 @@
program.typeToInterceptorMap));
}
- globals.add(new js.Property(js.string(MANGLED_GLOBAL_NAMES),
- js.js('Object.create(null)', [])));
+ globals.add(emitMangledGlobalNames());
globals.add(emitGetTypeFromName());
@@ -234,6 +235,24 @@
return new js.Block(statements);
}
+ js.Property emitMangledGlobalNames() {
+ List<js.Property> names = <js.Property>[];
+
+ // We want to keep the original names for the most common core classes when
+ // calling toString on them.
+ List<ClassElement> nativeClassesNeedingUnmangledName =
+ [compiler.intClass, compiler.doubleClass, compiler.numClass,
+ compiler.stringClass, compiler.boolClass, compiler.nullClass,
+ compiler.listClass];
+ nativeClassesNeedingUnmangledName.forEach((element) {
+ names.add(new js.Property(js.string(namer.getNameOfClass(element)),
+ js.string(element.name)));
+ });
+
+ return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
+ new js.ObjectInitializer(names));
+ }
+
List<js.Property> emitLoadUrisAndHashes(Map<String, List<Fragment>> loadMap) {
js.ArrayInitializer outputUris(List<Fragment> fragments) {
return js.stringArray(fragments.map((DeferredFragment fragment) =>
@@ -428,7 +447,7 @@
}
js.Expression fieldName = js.string(field.name);
js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName);
- String setterName = "${namer.setterPrefix}${field.name}";
+ String setterName = "${namer.setterPrefix}${field.accessorName}";
return new StubMethod(setterName, code);
}
@@ -785,7 +804,7 @@
if (typeof descriptor[2] !== 'function') {
constructor = compileMixinConstructor(name, prototype, descriptor);
for (var i = 4; i < descriptor.length; i += 2) {
- parseFunctionDescriptor(prototype, descriptor, descriptor[i + 1]);
+ parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
}
} else {
constructor = descriptor[2];
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 206a035..af2b302 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -2478,10 +2478,15 @@
LocalFunctionElementX function = new LocalFunctionElementX(
name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
enclosingElement);
- function.functionSignatureCache =
- SignatureResolver.analyze(compiler, node.parameters, node.returnType,
- function, registry, createRealParameters: true);
ResolverTask.processAsyncMarker(compiler, function);
+ function.functionSignatureCache = SignatureResolver.analyze(
+ compiler,
+ node.parameters,
+ node.returnType,
+ function,
+ registry,
+ createRealParameters: true,
+ isFunctionExpression: !inFunctionDeclaration);
checkLocalDefinitionName(node, function);
registry.defineFunction(node, function);
if (doAddToScope) {
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index 530be43..948a0cb 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -261,13 +261,16 @@
* real parameters implementing the [ParameterElement] interface. Otherwise,
* the parameters will only implement [FormalElement].
*/
- static FunctionSignature analyze(Compiler compiler,
- NodeList formalParameters,
- Node returnNode,
- FunctionTypedElement element,
- ResolutionRegistry registry,
- {MessageKind defaultValuesError,
- bool createRealParameters: false}) {
+ static FunctionSignature analyze(
+ Compiler compiler,
+ NodeList formalParameters,
+ Node returnNode,
+ FunctionTypedElement element,
+ ResolutionRegistry registry,
+ {MessageKind defaultValuesError,
+ bool createRealParameters: false,
+ bool isFunctionExpression: false}) {
+
SignatureResolver visitor = new SignatureResolver(compiler, element,
registry, defaultValuesError: defaultValuesError,
createRealParameters: createRealParameters);
@@ -308,7 +311,27 @@
registry.registerIsCheck(returnType);
}
} else {
- returnType = visitor.resolveReturnType(returnNode);
+ AsyncMarker asyncMarker = AsyncMarker.SYNC;
+ if (isFunctionExpression) {
+ // Use async marker to determine the return type of function
+ // expressions.
+ FunctionElement function = element;
+ asyncMarker = function.asyncMarker;
+ }
+ switch (asyncMarker) {
+ case AsyncMarker.SYNC:
+ returnType = visitor.resolveReturnType(returnNode);
+ break;
+ case AsyncMarker.SYNC_STAR:
+ returnType = compiler.coreTypes.iterableType();
+ break;
+ case AsyncMarker.ASYNC:
+ returnType = compiler.coreTypes.futureType();
+ break;
+ case AsyncMarker.ASYNC_STAR:
+ returnType = compiler.coreTypes.streamType();
+ break;
+ }
}
if (element.isSetter && (requiredParameterCount != 1 ||
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 1921450..a688778 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -6,7 +6,6 @@
import '../constants/expressions.dart';
import '../constants/values.dart' as values;
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
import '../dart_types.dart' show DartType, GenericType;
import '../elements/elements.dart';
import '../universe/universe.dart';
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index f338269..6bec813 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -1629,15 +1629,20 @@
DartType resultType = analyze(node.expression);
if (!node.hasStar) {
if (currentAsyncMarker.isAsync) {
- resultType =
- compiler.streamClass.thisType.createInstantiation(
- <DartType>[resultType]);
+ resultType = compiler.coreTypes.streamType(resultType);
} else {
- resultType =
- compiler.iterableClass.thisType.createInstantiation(
- <DartType>[resultType]);
+ resultType = compiler.coreTypes.iterableType(resultType);
+ }
+ } else {
+ if (currentAsyncMarker.isAsync) {
+ // The static type of expression must be assignable to Stream.
+ checkAssignable(node, resultType, compiler.coreTypes.streamType());
+ } else {
+ // The static type of expression must be assignable to Iterable.
+ checkAssignable(node, resultType, compiler.coreTypes.iterableType());
}
}
+ // The static type of the result must be assignable to the declared type.
checkAssignable(node, resultType, expectedReturnType);
return const StatementType();
}
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 4945189..909b000 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -176,6 +176,9 @@
useJsBackend(js_backend.JavaScriptBackend backend) {
backend.assembleCode(null);
+ backend.annotations.noInlining(null);
+ backend.annotations.trustTypeAnnotations(null);
+ backend.annotations.assumeDynamic(null);
}
useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index c788276..e21429c 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -2085,7 +2085,7 @@
examples: const [
"main() async * {}",
"main() sync * {}",
- "main() async* { yield * 0; }"
+ "main() async* { yield * null; }"
]);
static const MessageKind INVALID_SYNC_MODIFIER = const MessageKind(
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index bdec706..ed094dd 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -396,3 +396,24 @@
String toString() => message;
String message;
}
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to disable inlining of the annotated method.
+class NoInlining {
+ const NoInlining();
+}
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to make the type inferrer trust the parameter and return types,
+/// effectively asserting the runtime values will (at least) be subtypes of the
+/// annotated types.
+class TrustTypeAnnotations {
+ const TrustTypeAnnotations();
+}
+
+/// Annotation class for testing of dart2js. Use this as metadata on method
+/// declarations to disable closed world assumptions on parameters, effectively
+/// assuming that the runtime arguments could be any value.
+class AssumeDynamic {
+ const AssumeDynamic();
+}
\ No newline at end of file
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index 542602f..52f2539 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -4,7 +4,9 @@
#include "bin/dartutils.h"
#include "bin/eventhandler.h"
+#include "bin/lockers.h"
#include "bin/socket.h"
+#include "bin/thread.h"
#include "include/dart_api.h"
@@ -12,8 +14,6 @@
namespace dart {
namespace bin {
-static const intptr_t kTimerId = -1;
-static const intptr_t kInvalidId = -2;
void TimeoutQueue::UpdateTimeout(Dart_Port port, int64_t timeout) {
// Find port if present.
@@ -57,19 +57,40 @@
static EventHandler* event_handler = NULL;
+static Monitor *shutdown_monitor = NULL;
void EventHandler::Start() {
ASSERT(event_handler == NULL);
+ shutdown_monitor = new Monitor();
event_handler = new EventHandler();
event_handler->delegate_.Start(event_handler);
}
+void EventHandler::NotifyShutdownDone() {
+ MonitorLocker ml(shutdown_monitor);
+ ml.Notify();
+}
+
+
void EventHandler::Stop() {
if (event_handler == NULL) return;
- event_handler->delegate_.Shutdown();
+
+ // Wait until it has stopped.
+ {
+ MonitorLocker ml(shutdown_monitor);
+
+ // Signal to event handler that we want it to stop.
+ event_handler->delegate_.Shutdown();
+ ml.Wait(Monitor::kNoTimeout);
+ }
+
+ // Cleanup
+ delete event_handler;
event_handler = NULL;
+ delete shutdown_monitor;
+ shutdown_monitor = NULL;
}
@@ -85,7 +106,7 @@
*/
void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
Dart_Handle sender = Dart_GetNativeArgument(args, 0);
- intptr_t id = kInvalidId;
+ intptr_t id;
if (Dart_IsNull(sender)) {
id = kTimerId;
} else {
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 80efaca..70636bf 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -25,6 +25,7 @@
kShutdownReadCommand = 9,
kShutdownWriteCommand = 10,
kReturnTokenCommand = 11,
+ kSetEventMaskCommand = 12,
kListeningSocket = 16,
kPipe = 17,
};
@@ -32,10 +33,19 @@
#define COMMAND_MASK ((1 << kCloseCommand) | \
(1 << kShutdownReadCommand) | \
(1 << kShutdownWriteCommand) | \
- (1 << kReturnTokenCommand))
+ (1 << kReturnTokenCommand) | \
+ (1 << kSetEventMaskCommand))
+#define EVENT_MASK ((1 << kInEvent) | \
+ (1 << kOutEvent) | \
+ (1 << kErrorEvent) | \
+ (1 << kCloseEvent) | \
+ (1 << kDestroyedEvent))
#define IS_COMMAND(data, command_bit) \
((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT
-#define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0) // NOLINT
+#define IS_EVENT(data, event_bit) \
+ ((data & EVENT_MASK) == (1 << event_bit)) // NOLINT
+#define IS_LISTENING_SOCKET(data) \
+ ((data & (1 << kListeningSocket)) != 0) // NOLINT
#define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1))
class TimeoutQueue {
@@ -94,6 +104,78 @@
Timeout* timeouts_;
};
+
+class InterruptMessage {
+ public:
+ intptr_t id;
+ Dart_Port dart_port;
+ int64_t data;
+};
+
+
+static const int kInterruptMessageSize = sizeof(InterruptMessage);
+static const int kInfinityTimeout = -1;
+static const int kTimerId = -1;
+static const int kShutdownId = -2;
+
+
+template<typename T>
+class CircularLinkedList {
+ public:
+ CircularLinkedList() : head_(NULL) {}
+
+ // Returns true if the list was empty.
+ bool Add(T t) {
+ Entry* e = new Entry(t);
+ if (head_ == NULL) {
+ // Empty list, make e head, and point to itself.
+ e->next_ = e;
+ e->prev_ = e;
+ head_ = e;
+ return true;
+ } else {
+ // Insert e as the last element in the list.
+ e->prev_ = head_->prev_;
+ e->next_ = head_;
+ e->prev_->next_ = e;
+ head_->prev_ = e;
+ return false;
+ }
+ }
+
+ void RemoveHead() {
+ Entry* e = head_;
+ if (e->next_ == e) {
+ head_ = NULL;
+ } else {
+ e->prev_->next_ = e->next_;
+ e->next_->prev_ = e->prev_;
+ head_ = e->next_;
+ }
+ delete e;
+ }
+
+ T head() const { return head_->t; }
+
+ bool HasHead() {
+ return head_ != NULL;
+ }
+
+ void Rotate() {
+ head_ = head_->next_;
+ }
+
+ private:
+ struct Entry {
+ explicit Entry(const T& t) : t(t) {}
+ const T t;
+ Entry* next_;
+ Entry* prev_;
+ };
+
+ Entry* head_;
+};
+
} // namespace bin
} // namespace dart
@@ -120,6 +202,11 @@
}
/**
+ * Signal to main thread that event handler is done.
+ */
+ void NotifyShutdownDone();
+
+ /**
* Start the event-handler.
*/
static void Start();
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 680bcae..204bf8a 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -34,11 +34,6 @@
namespace dart {
namespace bin {
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
intptr_t SocketData::GetPollEvents() {
// Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
@@ -118,12 +113,14 @@
EventHandlerImplementation::~EventHandlerImplementation() {
+ VOID_TEMP_FAILURE_RETRY(close(epoll_fd_));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
}
-SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) {
+SocketData* EventHandlerImplementation::GetSocketData(
+ intptr_t fd, bool listening_socket) {
ASSERT(fd >= 0);
HashMap::Entry* entry = socket_map_.Lookup(
GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true);
@@ -132,7 +129,7 @@
if (sd == NULL) {
// If there is no data in the hash map for this file descriptor a
// new SocketData for the file descriptor is inserted.
- sd = new SocketData(fd);
+ sd = new SocketData(fd, listening_socket);
entry->value = sd;
}
ASSERT(fd == sd->fd());
@@ -173,8 +170,10 @@
} else if (msg[i].id == kShutdownId) {
shutdown_ = true;
} else {
- SocketData* sd = GetSocketData(msg[i].id);
+ ASSERT((msg[i].data & COMMAND_MASK) != 0);
+ SocketData* sd = GetSocketData(
+ msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
// Close the socket for reading.
shutdown(sd->fd(), SHUT_RD);
@@ -198,11 +197,16 @@
AddToEpollInstance(epoll_fd_, sd);
}
}
- } else {
- ASSERT_NO_COMMAND(msg[i].data);
+ } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+ // `events` can only have kInEvent/kOutEvent flags set.
+ intptr_t events = msg[i].data & EVENT_MASK;
+ ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
// Setup events to wait for.
- sd->SetPortAndMask(msg[i].dart_port, msg[i].data);
+ sd->SetPortAndMask(msg[i].dart_port, events);
AddToEpollInstance(epoll_fd_, sd);
+ } else {
+ UNREACHABLE();
}
}
}
@@ -299,25 +303,27 @@
ThreadSignalBlocker signal_blocker(SIGPROF);
static const intptr_t kMaxEvents = 16;
struct epoll_event events[kMaxEvents];
- EventHandlerImplementation* handler =
- reinterpret_cast<EventHandlerImplementation*>(args);
- ASSERT(handler != NULL);
- while (!handler->shutdown_) {
- int64_t millis = handler->GetTimeout();
+ EventHandler* handler = reinterpret_cast<EventHandler*>(args);
+ EventHandlerImplementation* handler_impl = &handler->delegate_;
+ ASSERT(handler_impl != NULL);
+
+ while (!handler_impl->shutdown_) {
+ int64_t millis = handler_impl->GetTimeout();
ASSERT(millis == kInfinityTimeout || millis >= 0);
if (millis > kMaxInt32) millis = kMaxInt32;
intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(
- epoll_wait(handler->epoll_fd_, events, kMaxEvents, millis));
+ epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, millis));
ASSERT(EAGAIN == EWOULDBLOCK);
if (result == -1) {
if (errno != EWOULDBLOCK) {
perror("Poll failed");
}
} else {
- handler->HandleTimeout();
- handler->HandleEvents(events, result);
+ handler_impl->HandleTimeout();
+ handler_impl->HandleEvents(events, result);
}
}
+ handler->NotifyShutdownDone();
}
diff --git a/runtime/bin/eventhandler_android.h b/runtime/bin/eventhandler_android.h
index 2eee0af..2f9ab91 100644
--- a/runtime/bin/eventhandler_android.h
+++ b/runtime/bin/eventhandler_android.h
@@ -22,18 +22,11 @@
namespace dart {
namespace bin {
-class InterruptMessage {
- public:
- intptr_t id;
- Dart_Port dart_port;
- int64_t data;
-};
-
-
class SocketData {
public:
- explicit SocketData(intptr_t fd)
- : fd_(fd), port_(0), mask_(0), tokens_(16) {
+ explicit SocketData(intptr_t fd, bool listening_socket)
+ : fd_(fd), port_(0), mask_(0), tokens_(16),
+ listening_socket_(listening_socket) {
ASSERT(fd_ != -1);
}
@@ -55,7 +48,7 @@
intptr_t fd() { return fd_; }
Dart_Port port() { return port_; }
- bool IsListeningSocket() { return (mask_ & (1 << kListeningSocket)) != 0; }
+ bool IsListeningSocket() { return listening_socket_; }
// Returns true if the last token was taken.
bool TakeToken() {
@@ -76,6 +69,7 @@
Dart_Port port_;
intptr_t mask_;
int tokens_;
+ bool listening_socket_;
};
@@ -86,7 +80,7 @@
// Gets the socket data structure for a given file
// descriptor. Creates a new one if one is not found.
- SocketData* GetSocketData(intptr_t fd);
+ SocketData* GetSocketData(intptr_t fd, bool is_listening);
void SendData(intptr_t id, Dart_Port dart_port, intptr_t data);
void Start(EventHandler* handler);
void Shutdown();
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 97b305b..475b39d 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -28,10 +28,6 @@
namespace dart {
namespace bin {
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
intptr_t SocketData::GetPollEvents() {
// Do not ask for EPOLLERR and EPOLLHUP explicitly as they are
@@ -197,8 +193,10 @@
} else if (msg[i].id == kShutdownId) {
shutdown_ = true;
} else {
+ ASSERT((msg[i].data & COMMAND_MASK) != 0);
+
SocketData* sd = GetSocketData(
- msg[i].id, (msg[i].data & (1 << kListeningSocket)) != 0);
+ msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
ASSERT(!sd->IsListeningSocket());
// Close the socket for reading.
@@ -223,13 +221,18 @@
if (sd->ReturnToken(msg[i].dart_port, count)) {
AddToEpollInstance(epoll_fd_, sd);
}
- } else {
- ASSERT_NO_COMMAND(msg[i].data);
+ } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+ // `events` can only have kInEvent/kOutEvent flags set.
+ intptr_t events = msg[i].data & EVENT_MASK;
+ ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
// Setup events to wait for.
if (sd->AddPort(msg[i].dart_port)) {
- sd->SetMask(msg[i].data);
+ sd->SetMask(events);
AddToEpollInstance(epoll_fd_, sd);
}
+ } else {
+ UNREACHABLE();
}
}
}
@@ -315,6 +318,7 @@
EventHandler* handler = reinterpret_cast<EventHandler*>(args);
EventHandlerImplementation* handler_impl = &handler->delegate_;
ASSERT(handler_impl != NULL);
+
while (!handler_impl->shutdown_) {
intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(
epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, -1));
@@ -327,13 +331,13 @@
handler_impl->HandleEvents(events, result);
}
}
- delete handler;
+ handler->NotifyShutdownDone();
}
void EventHandlerImplementation::Start(EventHandler* handler) {
int result = Thread::Start(&EventHandlerImplementation::Poll,
- reinterpret_cast<uword>(handler));
+ reinterpret_cast<uword>(handler));
if (result != 0) {
FATAL1("Failed to start event handler thread %d", result);
}
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index 0db4f3f..0c5bd26 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -21,71 +21,6 @@
namespace dart {
namespace bin {
-class InterruptMessage {
- public:
- intptr_t id;
- Dart_Port dart_port;
- int64_t data;
-};
-
-template<typename T>
-class CircularLinkedList {
- public:
- CircularLinkedList() : head_(NULL) {}
-
- // Returns true if the list was empty.
- bool Add(T t) {
- Entry* e = new Entry(t);
- if (head_ == NULL) {
- // Empty list, make e head, and point to itself.
- e->next_ = e;
- e->prev_ = e;
- head_ = e;
- return true;
- } else {
- // Insert e as the last element in the list.
- e->prev_ = head_->prev_;
- e->next_ = head_;
- e->prev_->next_ = e;
- head_->prev_ = e;
- return false;
- }
- }
-
- void RemoveHead() {
- Entry* e = head_;
- if (e->next_ == e) {
- head_ = NULL;
- } else {
- e->prev_->next_ = e->next_;
- e->next_->prev_ = e->prev_;
- head_ = e->next_;
- }
- delete e;
- }
-
- T head() const { return head_->t; }
-
- bool HasHead() {
- return head_ != NULL;
- }
-
- void Rotate() {
- head_ = head_->next_;
- }
-
- private:
- struct Entry {
- explicit Entry(const T& t) : t(t) {}
- const T t;
- Entry* next_;
- Entry* prev_;
- };
-
- Entry* head_;
-};
-
-
class ListeningSocketData;
class SocketData {
public:
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 49ec247..911cbad 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -27,12 +27,6 @@
namespace dart {
namespace bin {
-static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
-static const int kTimerId = -1;
-static const int kShutdownId = -2;
-
-
bool SocketData::HasReadEvent() {
return (mask_ & (1 << kInEvent)) != 0;
}
@@ -142,7 +136,8 @@
}
-SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd) {
+SocketData* EventHandlerImplementation::GetSocketData(intptr_t fd,
+ bool is_listening) {
ASSERT(fd >= 0);
HashMap::Entry* entry = socket_map_.Lookup(
GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd), true);
@@ -151,7 +146,7 @@
if (sd == NULL) {
// If there is no data in the hash map for this file descriptor a
// new SocketData for the file descriptor is inserted.
- sd = new SocketData(fd);
+ sd = new SocketData(fd, is_listening);
entry->value = sd;
}
ASSERT(fd == sd->fd());
@@ -191,7 +186,10 @@
} else if (msg[i].id == kShutdownId) {
shutdown_ = true;
} else {
- SocketData* sd = GetSocketData(msg[i].id);
+ ASSERT((msg[i].data & COMMAND_MASK) != 0);
+
+ SocketData* sd = GetSocketData(
+ msg[i].id, IS_LISTENING_SOCKET(msg[i].data));
if (IS_COMMAND(msg[i].data, kShutdownReadCommand)) {
// Close the socket for reading.
shutdown(sd->fd(), SHUT_RD);
@@ -213,14 +211,17 @@
AddToKqueue(kqueue_fd_, sd);
}
}
- } else {
- ASSERT_NO_COMMAND(msg[i].data);
+ } else if (IS_COMMAND(msg[i].data, kSetEventMaskCommand)) {
+ // `events` can only have kInEvent/kOutEvent flags set.
+ intptr_t events = msg[i].data & EVENT_MASK;
+ ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
// Setup events to wait for.
- ASSERT((msg[i].data > 0) && (msg[i].data < kIntptrMax));
ASSERT(sd->port() == 0);
- sd->SetPortAndMask(msg[i].dart_port,
- static_cast<intptr_t>(msg[i].data));
+ sd->SetPortAndMask(msg[i].dart_port, events);
AddToKqueue(kqueue_fd_, sd);
+ } else {
+ UNREACHABLE();
}
}
}
@@ -358,6 +359,7 @@
EventHandler* handler = reinterpret_cast<EventHandler*>(args);
EventHandlerImplementation* handler_impl = &handler->delegate_;
ASSERT(handler_impl != NULL);
+
while (!handler_impl->shutdown_) {
int64_t millis = handler_impl->GetTimeout();
ASSERT(millis == kInfinityTimeout || millis >= 0);
@@ -387,14 +389,14 @@
handler_impl->HandleEvents(events, result);
}
}
- delete handler;
+ handler->NotifyShutdownDone();
}
void EventHandlerImplementation::Start(EventHandler* handler) {
int result =
Thread::Start(&EventHandlerImplementation::EventHandlerEntry,
- reinterpret_cast<uword>(handler));
+ reinterpret_cast<uword>(handler));
if (result != 0) {
FATAL1("Failed to start event handler thread %d", result);
}
diff --git a/runtime/bin/eventhandler_macos.h b/runtime/bin/eventhandler_macos.h
index 4e32dc0..ebfe251 100644
--- a/runtime/bin/eventhandler_macos.h
+++ b/runtime/bin/eventhandler_macos.h
@@ -21,29 +21,22 @@
namespace dart {
namespace bin {
-class InterruptMessage {
- public:
- intptr_t id;
- Dart_Port dart_port;
- int64_t data;
-};
-
-
class SocketData {
public:
- explicit SocketData(intptr_t fd)
+ explicit SocketData(intptr_t fd, bool is_listening)
: fd_(fd),
port_(0),
mask_(0),
tracked_by_kqueue_(false),
- tokens_(16) {
+ tokens_(16),
+ is_listening_(is_listening) {
ASSERT(fd_ != -1);
}
bool HasReadEvent();
bool HasWriteEvent();
- bool IsListeningSocket() { return (mask_ & (1 << kListeningSocket)) != 0; }
+ bool IsListeningSocket() { return is_listening_; }
void SetPortAndMask(Dart_Port port, intptr_t mask) {
ASSERT(fd_ != -1);
@@ -77,6 +70,7 @@
intptr_t mask_;
bool tracked_by_kqueue_;
int tokens_;
+ bool is_listening_;
};
@@ -87,7 +81,7 @@
// Gets the socket data structure for a given file
// descriptor. Creates a new one if one is not found.
- SocketData* GetSocketData(intptr_t fd);
+ SocketData* GetSocketData(intptr_t fd, bool is_listening);
void SendData(intptr_t id, Dart_Port dart_port, int64_t data);
void Start(EventHandler* handler);
void Shutdown();
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index fff9d87..61b6f44 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -29,10 +29,6 @@
static const int kBufferSize = 64 * 1024;
static const int kStdOverlappedBufferSize = 16 * 1024;
-static const int kInfinityTimeout = -1;
-static const int kTimeoutId = -1;
-static const int kShutdownId = -2;
-
OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
Operation operation) {
OverlappedBuffer* buffer =
@@ -1011,89 +1007,109 @@
void EventHandlerImplementation::HandleInterrupt(InterruptMessage* msg) {
ASSERT(this != NULL);
- if (msg->id == kTimeoutId) {
+ if (msg->id == kTimerId) {
// Change of timeout request. Just set the new timeout and port as the
// completion thread will use the new timeout value for its next wait.
timeout_queue_.UpdateTimeout(msg->dart_port, msg->data);
} else if (msg->id == kShutdownId) {
shutdown_ = true;
} else {
- // No tokens to return on Windows.
- if ((msg->data & (1 << kReturnTokenCommand)) != 0) return;
Handle* handle = reinterpret_cast<Handle*>(msg->id);
ASSERT(handle != NULL);
if (handle->is_listen_socket()) {
ListenSocket* listen_socket =
reinterpret_cast<ListenSocket*>(handle);
listen_socket->EnsureInitialized(this);
- listen_socket->SetPortAndMask(msg->dart_port, msg->data);
Handle::ScopedLock lock(listen_socket);
- // If incoming connections are requested make sure to post already
- // accepted connections.
- if ((msg->data & (1 << kInEvent)) != 0) {
- if (listen_socket->CanAccept()) {
- int event_mask = (1 << kInEvent);
- handle->set_mask(handle->mask() & ~event_mask);
- DartUtils::PostInt32(handle->port(), event_mask);
+ if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
+ // No tokens to return on Windows.
+ } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
+ // `events` can only have kInEvent/kOutEvent flags set.
+ intptr_t events = msg->data & EVENT_MASK;
+ ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
+ listen_socket->SetPortAndMask(msg->dart_port, msg->data);
+
+ // If incoming connections are requested make sure to post already
+ // accepted connections.
+ if ((events & (1 << kInEvent)) != 0) {
+ if (listen_socket->CanAccept()) {
+ int event_mask = (1 << kInEvent);
+ handle->set_mask(handle->mask() & ~event_mask);
+ DartUtils::PostInt32(handle->port(), event_mask);
+ }
}
+ } else if (IS_COMMAND(msg->data, kCloseCommand)) {
+ handle->SetPortAndMask(msg->dart_port, msg->data);
+ handle->Close();
+ } else {
+ UNREACHABLE();
}
} else {
handle->EnsureInitialized(this);
Handle::ScopedLock lock(handle);
- // Only set mask if we turned on kInEvent or kOutEvent.
- if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) {
+ if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
+ // No tokens to return on Windows.
+ } else if (IS_COMMAND(msg->data, kSetEventMaskCommand)) {
+ // `events` can only have kInEvent/kOutEvent flags set.
+ intptr_t events = msg->data & EVENT_MASK;
+ ASSERT(0 == (events & ~(1 << kInEvent | 1 << kOutEvent)));
+
handle->SetPortAndMask(msg->dart_port, msg->data);
- }
- // Issue a read.
- if ((msg->data & (1 << kInEvent)) != 0) {
- if (handle->is_datagram_socket()) {
- handle->IssueRecvFrom();
- } else if (handle->is_client_socket()) {
- if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
- handle->IssueRead();
- }
- } else {
- handle->IssueRead();
- }
- }
-
- // If out events (can write events) have been requested, and there
- // are no pending writes, meaning any writes are already complete,
- // post an out event immediately.
- if ((msg->data & (1 << kOutEvent)) != 0) {
- if (!handle->HasPendingWrite()) {
- if (handle->is_client_socket()) {
+ // Issue a read.
+ if ((msg->data & (1 << kInEvent)) != 0) {
+ if (handle->is_datagram_socket()) {
+ handle->IssueRecvFrom();
+ } else if (handle->is_client_socket()) {
if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
- DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+ handle->IssueRead();
}
} else {
- DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+ handle->IssueRead();
}
}
- }
- if (handle->is_client_socket()) {
+ // If out events (can write events) have been requested, and there
+ // are no pending writes, meaning any writes are already complete,
+ // post an out event immediately.
+ if ((msg->data & (1 << kOutEvent)) != 0) {
+ if (!handle->HasPendingWrite()) {
+ if (handle->is_client_socket()) {
+ if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
+ DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+ }
+ } else {
+ DartUtils::PostInt32(handle->port(), 1 << kOutEvent);
+ }
+ }
+ }
+ } else if (IS_COMMAND(msg->data, kShutdownReadCommand)) {
+ ASSERT(handle->is_client_socket());
+
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
if ((msg->data & (1 << kShutdownReadCommand)) != 0) {
client_socket->Shutdown(SD_RECEIVE);
}
+ } else if (IS_COMMAND(msg->data, kShutdownWriteCommand)) {
+ ASSERT(handle->is_client_socket());
+ ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(handle);
if ((msg->data & (1 << kShutdownWriteCommand)) != 0) {
client_socket->Shutdown(SD_SEND);
}
+ } else if (IS_COMMAND(msg->data, kCloseCommand)) {
+ handle->SetPortAndMask(msg->dart_port, msg->data);
+ handle->Close();
+ } else {
+ UNREACHABLE();
}
}
- if ((msg->data & (1 << kCloseCommand)) != 0) {
- handle->SetPortAndMask(msg->dart_port, msg->data);
- handle->Close();
- }
-
DeleteIfClosed(handle);
}
}
@@ -1295,6 +1311,7 @@
EventHandler* handler = reinterpret_cast<EventHandler*>(args);
EventHandlerImplementation* handler_impl = &handler->delegate_;
ASSERT(handler_impl != NULL);
+
while (!handler_impl->shutdown_) {
DWORD bytes;
ULONG_PTR key;
@@ -1344,13 +1361,13 @@
handler_impl->HandleIOCompletion(bytes, key, overlapped);
}
}
- delete handler;
+ handler->NotifyShutdownDone();
}
void EventHandlerImplementation::Start(EventHandler* handler) {
int result = Thread::Start(EventHandlerEntry,
- reinterpret_cast<uword>(handler));
+ reinterpret_cast<uword>(handler));
if (result != 0) {
FATAL1("Failed to start event handler thread %d", result);
}
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index c54ef07..3a9a1f4 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -29,13 +29,6 @@
class ListenSocket;
-struct InterruptMessage {
- intptr_t id;
- Dart_Port dart_port;
- int64_t data;
-};
-
-
// An OverlappedBuffer encapsulates the OVERLAPPED structure and the
// associated data buffer. For accept it also contains the pre-created
// socket for the client.
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 251108d..b2723ca 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -75,6 +75,30 @@
// being allocated.
static int vm_service_server_port = -1;
+
+// Exit code indicating an API error.
+static const int kApiErrorExitCode = 253;
+// Exit code indicating a compilation error.
+static const int kCompilationErrorExitCode = 254;
+// Exit code indicating an unhandled error that is not a compilation error.
+static const int kErrorExitCode = 255;
+
+static void ErrorExit(int exit_code, const char* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ Log::VPrintErr(format, arguments);
+ va_end(arguments);
+ fflush(stderr);
+
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+
+ Dart_Cleanup();
+
+ exit(exit_code);
+}
+
+
// The environment provided through the command line using -D options.
static dart::HashMap* environment = NULL;
@@ -540,7 +564,8 @@
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
*error = strdup(Dart_GetError(result)); \
- *is_compile_error = Dart_IsCompilationError(result); \
+ *exit_code = Dart_IsCompilationError(result) ? kCompilationErrorExitCode : \
+ (Dart_IsApiError(result) ? kApiErrorExitCode : kErrorExitCode); \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
return NULL; \
@@ -552,7 +577,7 @@
const char* main,
const char* package_root,
char** error,
- bool* is_compile_error) {
+ int* exit_code) {
ASSERT(script_uri != NULL);
IsolateData* isolate_data = new IsolateData(script_uri, package_root);
Dart_Isolate isolate = NULL;
@@ -640,7 +665,7 @@
const char* package_root,
void* data, char** error) {
IsolateData* parent_isolate_data = reinterpret_cast<IsolateData*>(data);
- bool is_compile_error = false;
+ int exit_code = 0;
if (script_uri == NULL) {
if (data == NULL) {
*error = strdup("Invalid 'callback_data' - Unable to spawn new isolate");
@@ -663,7 +688,7 @@
main,
package_root,
error,
- &is_compile_error);
+ &exit_code);
}
@@ -765,29 +790,6 @@
return buffer;
}
-
-// Exit code indicating a compilation error.
-static const int kCompilationErrorExitCode = 254;
-
-// Exit code indicating an unhandled error that is not a compilation error.
-static const int kErrorExitCode = 255;
-
-static void ErrorExit(int exit_code, const char* format, ...) {
- va_list arguments;
- va_start(arguments, format);
- Log::VPrintErr(format, arguments);
- va_end(arguments);
- fflush(stderr);
-
- Dart_ExitScope();
- Dart_ShutdownIsolate();
-
- Dart_Cleanup();
-
- exit(exit_code);
-}
-
-
static void DartExitOnError(Dart_Handle error) {
if (!Dart_IsError(error)) {
return;
@@ -855,15 +857,11 @@
static const char* ServiceRequestHandler(
const char* name,
- const char** arguments,
- intptr_t num_arguments,
- const char** option_keys,
- const char** option_values,
- intptr_t num_options,
+ const char** param_keys,
+ const char** param_values,
+ intptr_t num_params,
void* user_data) {
DartScope scope;
- ASSERT(num_arguments > 0);
- ASSERT(strncmp(arguments[0], "io", 2) == 0);
// TODO(ajohnsen): Store the library/function in isolate data or user_data.
Dart_Handle dart_io_str = Dart_NewStringFromCString("dart:io");
if (Dart_IsError(dart_io_str)) return ServiceRequestError(dart_io_str);
@@ -874,15 +872,14 @@
if (Dart_IsError(handler_function_name)) {
return ServiceRequestError(handler_function_name);
}
- Dart_Handle paths = Dart_NewList(num_arguments - 1);
- for (int i = 0; i < num_arguments - 1; i++) {
- Dart_ListSetAt(paths, i, Dart_NewStringFromCString(arguments[i + 1]));
- }
- Dart_Handle keys = Dart_NewList(num_options);
- Dart_Handle values = Dart_NewList(num_options);
- for (int i = 0; i < num_options; i++) {
- Dart_ListSetAt(keys, i, Dart_NewStringFromCString(option_keys[i]));
- Dart_ListSetAt(values, i, Dart_NewStringFromCString(option_values[i]));
+ // TODO(johnmccutchan): paths is no longer used. Update the io
+ // _serviceObjectHandler function to use json rpc.
+ Dart_Handle paths = Dart_NewList(0);
+ Dart_Handle keys = Dart_NewList(num_params);
+ Dart_Handle values = Dart_NewList(num_params);
+ for (int i = 0; i < num_params; i++) {
+ Dart_ListSetAt(keys, i, Dart_NewStringFromCString(param_keys[i]));
+ Dart_ListSetAt(values, i, Dart_NewStringFromCString(param_values[i]));
}
Dart_Handle args[] = {paths, keys, values};
Dart_Handle result = Dart_Invoke(io_lib, handler_function_name, 3, args);
@@ -982,18 +979,18 @@
// Call CreateIsolateAndSetup which creates an isolate and loads up
// the specified application script.
char* error = NULL;
- bool is_compile_error = false;
+ int exit_code = 0;
char* isolate_name = BuildIsolateName(script_name, "main");
Dart_Isolate isolate = CreateIsolateAndSetupHelper(script_name,
"main",
commandline_package_root,
&error,
- &is_compile_error);
+ &exit_code);
if (isolate == NULL) {
Log::PrintErr("%s\n", error);
free(error);
delete [] isolate_name;
- exit(is_compile_error ? kCompilationErrorExitCode : kErrorExitCode);
+ exit((exit_code != 0) ? exit_code : kErrorExitCode);
}
delete [] isolate_name;
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index c2cc587..3983f24 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -238,8 +238,9 @@
// The lower bits of RETURN_TOKEN_COMMAND messages contains the number
// of tokens returned.
static const int RETURN_TOKEN_COMMAND = 11;
+ static const int SET_EVENT_MASK_COMMAND = 12;
static const int FIRST_COMMAND = CLOSE_COMMAND;
- static const int LAST_COMMAND = RETURN_TOKEN_COMMAND;
+ static const int LAST_COMMAND = SET_EVENT_MASK_COMMAND;
// Type flag send to the eventhandler providing additional
// information on the type of the file descriptor.
@@ -523,7 +524,9 @@
_NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET | TYPE_TCP_SOCKET;
- _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET | TYPE_TCP_SOCKET;
+ _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET | TYPE_TCP_SOCKET {
+ isClosedWrite = true;
+ }
_NativeSocket.pipe() : typeFlags = TYPE_PIPE;
@@ -805,7 +808,7 @@
if (write) issueWriteEvent();
if (!flagsSent && !isClosing) {
flagsSent = true;
- int flags = 0;
+ int flags = 1 << SET_EVENT_MASK_COMMAND;
if (!isClosedRead) flags |= 1 << READ_EVENT;
if (!isClosedWrite) flags |= 1 << WRITE_EVENT;
sendToEventHandler(flags);
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 46cff7b..55f36e0 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -32,15 +32,7 @@
}
var serial = map['id'];
- // If the map contains 'params' then this is a JsonRPC message.
- // We are currently in the process of switching the vmservice over to
- // JsonRPC.
- if (map['params'] != null) {
- onMessage(serial, new Message.fromJsonRpc(map['method'],
- map['params']));
- } else {
- onMessage(serial, new Message.fromUri(Uri.parse(map['method'])));
- }
+ onMessage(serial, new Message.fromJsonRpc(map['method'], map['params']));
} else {
socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
}
@@ -219,4 +211,4 @@
}
void _notifyServerState(String ip, int port)
- native "VMServiceIO_NotifyServerState";
\ No newline at end of file
+ native "VMServiceIO_NotifyServerState";
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index f28b53a..f7fbfe3 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2770,29 +2770,21 @@
* a service request it can't handle and the service request command name
* matches one of the embedder registered handlers.
*
- * \param name The service request command name. Always the first entry
- * in the arguments array. Will match the name the callback was
- * registered with.
- * \param arguments The service request command arguments. Incoming service
- * request paths are split like file system paths and flattened into an array
- * (e.g. /foo/bar becomes the array ["foo", "bar"].
- * \param num_arguments The length of the arguments array.
- * \param option_keys Service requests can have options key-value pairs. The
+ * \param method The rpc method name.
+ * \param param_keys Service requests can have key-value pair parameters. The
* keys and values are flattened and stored in arrays.
- * \param option_values The values associated with the keys.
- * \param num_options The length of the option_keys and option_values array.
+ * \param param_values The values associated with the keys.
+ * \param num_params The length of the param_keys and param_values arrays.
* \param user_data The user_data pointer registered with this handler.
*
* \return Returns a C string containing a valid JSON object. The returned
* pointer will be freed by the VM by calling free.
*/
typedef const char* (*Dart_ServiceRequestCallback)(
- const char* name,
- const char** arguments,
- intptr_t num_arguments,
- const char** option_keys,
- const char** option_values,
- intptr_t num_options,
+ const char* method,
+ const char** param_keys,
+ const char** param_values,
+ intptr_t num_params,
void* user_data);
/**
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 71d59b3..a4217b9 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -21,3 +21,54 @@
static const List<String> _enum_names = null;
String toString() => _enum_names[index];
}
+
+typedef bool SyncGeneratorCallback(Iterator iterator);
+
+// _SyncIterable and _syncIterator are used by the compiler to
+// implement sync* generator functions. A sync* generator allocates
+// and returns a new _SyncIterable object.
+class _SyncIterable extends IterableBase {
+ // moveNextFn is the closurized body of the generator function.
+ final SyncGeneratorCallback moveNextFn;
+
+ const _SyncIterable(this.moveNextFn);
+
+ get iterator {
+ return new _SyncIterator(moveNextFn._clone());
+ }
+}
+
+class _SyncIterator implements Iterator {
+ bool isYieldEach; // Set by generated code for the yield* statement.
+ Iterator yieldEachIterator;
+ var current; // Set by generated code for the yield and yield* statement.
+ SyncGeneratorCallback moveNextFn;
+
+ _SyncIterator(this.moveNextFn);
+
+ bool moveNext() {
+ if (moveNextFn == null) {
+ return false;
+ }
+ while(true) {
+ if (yieldEachIterator != null) {
+ if (yieldEachIterator.moveNext()) {
+ current = yieldEachIterator.current;
+ return true;
+ }
+ yieldEachIterator = null;
+ }
+ isYieldEach = false;
+ if (!moveNextFn(this)) {
+ moveNextFn = null;
+ current = null;
+ return false;
+ }
+ if (isYieldEach && (current is Iterable)) {
+ yieldEachIterator = current.iterator;
+ continue;
+ }
+ return true;
+ }
+ }
+}
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 3f55293..801ad54 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -74,4 +74,28 @@
return Object::null();
}
+
+DEFINE_NATIVE_ENTRY(FunctionImpl_clone, 1) {
+ const Instance& receiver = Instance::CheckedHandle(
+ isolate, arguments->NativeArgAt(0));
+ ASSERT(receiver.IsClosure());
+ if (receiver.IsClosure()) {
+ const Function& func =
+ Function::Handle(isolate, Closure::function(receiver));
+ const Context& ctx =
+ Context::Handle(isolate, Closure::context(receiver));
+ Context& cloned_ctx =
+ Context::Handle(isolate, Context::New(ctx.num_variables()));
+ cloned_ctx.set_parent(Context::Handle(isolate, ctx.parent()));
+ Object& inst = Object::Handle(isolate);
+ for (int i = 0; i < ctx.num_variables(); i++) {
+ inst = ctx.At(i);
+ cloned_ctx.SetAt(i, inst);
+ }
+ return Closure::New(func, cloned_ctx);
+ }
+ return Object::null();
+}
+
+
} // namespace dart
diff --git a/runtime/lib/function.dart b/runtime/lib/function.dart
index 8147b2d..d91ce66 100644
--- a/runtime/lib/function.dart
+++ b/runtime/lib/function.dart
@@ -9,4 +9,6 @@
int get hashCode native "FunctionImpl_hashCode";
_FunctionImpl get call => this;
+
+ _FunctionImpl _clone() native "FunctionImpl_clone";
}
diff --git a/runtime/observatory/bin/shell.dart b/runtime/observatory/bin/shell.dart
index ef2459c..ae4e7ff 100644
--- a/runtime/observatory/bin/shell.dart
+++ b/runtime/observatory/bin/shell.dart
@@ -11,17 +11,19 @@
// Simple demo for service_io library. Connects to localhost on the default
// port, picks the first isolate, reads requests from stdin, and prints
// results to stdout. Example session:
-// <<< prefix /isolates/1071334835
+// <<< isolate isolates/1071334835
// >>> /classes/40
// <<< {"type":"Class","id":"classes\/40","name":"num","user_name":"num",...
// >>> /objects/0
// >>> {"type":"Array","class":{"type":"@Class","id":"classes\/62",...
-void repl(VM vm, String prefix, String lastResult) {
+void repl(VM vm, Isolate isolate, String lastResult) {
print(lastResult);
- // TODO(turnidge): use the non-deprecated api here.
- vm.getStringDeprecated(prefix + stdin.readLineSync()).then((String result) {
- repl(vm, prefix, result);
+ Map params = {
+ 'objectId': stdin.readLineSync(),
+ };
+ isolate.invokeRpcNoUpgrade('getObject', params).then((Map result) {
+ repl(vm, isolate, result.toString());
});
}
@@ -29,7 +31,6 @@
String addr = 'ws://localhost:8181/ws';
new WebSocketVM(new WebSocketVMTarget(addr)).load().then((VM vm) {
Isolate isolate = vm.isolates.first;
- String prefix = '${isolate.link}';
- repl(vm, prefix, 'prefix $prefix');
+ repl(vm, isolate, 'isolate ${isolate.id}');
});
}
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index f63249d..c4eec73 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -2,7 +2,6 @@
// Export elements.
export 'package:observatory/src/elements/action_link.dart';
-export 'package:observatory/src/elements/breakpoint_list.dart';
export 'package:observatory/src/elements/class_ref.dart';
export 'package:observatory/src/elements/class_tree.dart';
export 'package:observatory/src/elements/class_view.dart';
@@ -21,6 +20,7 @@
export 'package:observatory/src/elements/flag_list.dart';
export 'package:observatory/src/elements/function_ref.dart';
export 'package:observatory/src/elements/function_view.dart';
+export 'package:observatory/src/elements/general_error.dart';
export 'package:observatory/src/elements/heap_map.dart';
export 'package:observatory/src/elements/heap_profile.dart';
export 'package:observatory/src/elements/instance_ref.dart';
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index eeb782d..4cc405c 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -1,5 +1,4 @@
<link rel="import" href="src/elements/action_link.html">
-<link rel="import" href="src/elements/breakpoint_list.html">
<link rel="import" href="src/elements/class_ref.html">
<link rel="import" href="src/elements/class_tree.html">
<link rel="import" href="src/elements/class_view.html">
@@ -16,6 +15,7 @@
<link rel="import" href="src/elements/flag_list.html">
<link rel="import" href="src/elements/function_ref.html">
<link rel="import" href="src/elements/function_view.html">
+<link rel="import" href="src/elements/general_error.html">
<link rel="import" href="src/elements/heap_map.html">
<link rel="import" href="src/elements/io_view.html">
<link rel="import" href="src/elements/isolate_ref.html">
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index c082fdf..f417b88 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -58,10 +58,7 @@
final Map params;
final Completer<String> completer;
- _WebSocketRequest.old(this.method)
- : params = null, completer = new Completer<String>();
-
- _WebSocketRequest.rpc(this.method, this.params)
+ _WebSocketRequest(this.method, this.params)
: completer = new Completer<String>();
}
@@ -128,31 +125,6 @@
_notifyDisconnect();
}
- Future<String> getStringDeprecated(String id) {
- if (!_hasInitiatedConnect) {
- _hasInitiatedConnect = true;
- _webSocket.connect(
- target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
- }
- return _makeRequest(id);
- }
-
- /// Add a request for [id] to pending requests.
- Future<String> _makeRequest(String id) {
- assert(_hasInitiatedConnect);
- // Create request.
- String serial = (_requestSerial++).toString();
- var request = new _WebSocketRequest.old(id);
- if (_webSocket.isOpen) {
- // Already connected, send request immediately.
- _sendRequest(serial, request);
- } else {
- // Not connected yet, add to delayed requests.
- _delayedRequests[serial] = request;
- }
- return request.completer.future;
- }
-
Future<String> invokeRpcRaw(String method, Map params) {
if (!_hasInitiatedConnect) {
_hasInitiatedConnect = true;
@@ -160,7 +132,7 @@
target.networkAddress, _onOpen, _onMessage, _onError, _onClose);
}
String serial = (_requestSerial++).toString();
- var request = new _WebSocketRequest.rpc(method, params);
+ var request = new _WebSocketRequest(method, params);
if (_webSocket.isOpen) {
// Already connected, send request immediately.
_sendRequest(serial, request);
@@ -289,7 +261,9 @@
/// Send the request over WebSocket.
void _sendRequest(String serial, _WebSocketRequest request) {
assert (_webSocket.isOpen);
- if (request.method != 'getTagProfile') {
+ if (request.method != 'getTagProfile' &&
+ request.method != 'getIsolateMetric' &&
+ request.method != 'getVMMetric') {
Logger.root.info('GET ${request.method} from ${target.networkAddress}');
}
// Mark request as pending.
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index cee60ba..447e8db 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -103,6 +103,9 @@
}
void _registerPages() {
+ _pageRegistry.add(new VMPage(this));
+ _pageRegistry.add(new FlagsPage(this));
+ _pageRegistry.add(new InspectPage(this));
_pageRegistry.add(new ClassTreePage(this));
_pageRegistry.add(new DebuggerPage(this));
_pageRegistry.add(new CpuProfilerPage(this));
@@ -111,9 +114,9 @@
_pageRegistry.add(new VMConnectPage(this));
_pageRegistry.add(new ErrorViewPage(this));
_pageRegistry.add(new MetricsPage(this));
- // Note that ServiceObjectPage must be the last entry in the list as it is
+ // Note that ErrorPage must be the last entry in the list as it is
// the catch all.
- _pageRegistry.add(new ServiceObjectPage(this));
+ _pageRegistry.add(new ErrorPage(this));
}
void _onError(ServiceError error) {
@@ -153,11 +156,12 @@
if (_traceView != null) {
_traceView.tracer = Tracer.current;
}
+ Uri uri = Uri.parse(url);
for (var i = 0; i < _pageRegistry.length; i++) {
var page = _pageRegistry[i];
- if (page.canVisit(url)) {
+ if (page.canVisit(uri)) {
_installPage(page);
- page.visit(url, argsMap);
+ page.visit(uri, argsMap);
return;
}
}
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 2942905..c777579 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -26,57 +26,25 @@
element = null;
}
- /// Called when the page should update its state based on [url].
+ /// Called when the page should update its state based on [uri].
/// NOTE: Only called when the page is installed.
- void visit(String url, Map argsMap) {
+ void visit(Uri uri, Map argsMap) {
args = toObservable(argsMap);
- _visit(url);
+ _visit(uri);
}
// Overridden by subclasses.
- void _visit(String url);
+ void _visit(Uri uri);
- /// Called to test whether this page can visit [url].
- bool canVisit(String url);
+ /// Called to test whether this page can visit [uri].
+ bool canVisit(Uri uri);
}
-/// A general service object viewer.
-class ServiceObjectPage extends Page {
- ServiceObjectPage(app) : super(app);
-
- void onInstall() {
- if (element == null) {
- /// Lazily create page.
- element = new Element.tag('service-view');
- }
- }
-
- void _visit(String url) {
- assert(element != null);
- assert(canVisit(url));
- if (url == '') {
- // Nothing requested.
- return;
- }
- /// Request url from VM and display it.
- app.vm.getDeprecated(url).then((obj) {
- ServiceObjectViewElement serviceElement = element;
- serviceElement.object = obj;
- }).catchError((e) {
- Logger.root.severe('ServiceObjectPage visit error: $e');
- });
- }
-
- /// Catch all.
- bool canVisit(String url) => true;
-}
-
-class IsolateSuffixPage extends Page {
- final String pagePrefix;
+/// A [SimplePage] matches a single uri path and displays a single element.
+class SimplePage extends Page {
+ final String path;
final String elementTagName;
- String _isolateId;
- String get isolateId => _isolateId;
- IsolateSuffixPage(this.pagePrefix, this.elementTagName, app) : super(app);
+ SimplePage(this.path, this.elementTagName, app) : super(app);
void onInstall() {
if (element == null) {
@@ -84,30 +52,117 @@
}
}
- void _visit(String url) {
- assert(url != null);
- assert(canVisit(url));
- _isolateId = url.substring(pagePrefix.length);
+ void _visit(Uri uri) {
+ assert(uri != null);
+ assert(canVisit(uri));
}
- Future<Isolate> getIsolate() {
- return app.vm.getIsolate(isolateId).catchError((e) {
- Logger.root.severe('$pagePrefix visit error: $e');
+ Future<Isolate> getIsolate(Uri uri) {
+ return app.vm.getIsolate(uri.queryParameters['isolateId']).catchError((e) {
+ Logger.root.severe('$path visit error: $e');
return e;
});
}
- bool canVisit(String url) => url.startsWith(pagePrefix);
+ bool canVisit(Uri uri) => uri.path == path;
+}
+
+/// Error page for unrecognized paths.
+class ErrorPage extends Page {
+ ErrorPage(app) : super(app);
+
+ void onInstall() {
+ if (element == null) {
+ // Lazily create page.
+ element = new Element.tag('general-error');
+ }
+ }
+
+ void _visit(Uri uri) {
+ assert(element != null);
+ assert(canVisit(uri));
+
+ /*
+ if (uri.path == '') {
+ // Nothing requested.
+ return;
+ }
+ */
+
+ if (element != null) {
+ GeneralErrorElement serviceElement = element;
+ serviceElement.message = "Path '${uri.path}' not found";
+ }
+ }
+
+ /// Catch all.
+ bool canVisit(Uri uri) => true;
+}
+
+/// Top-level vm info page.
+class VMPage extends SimplePage {
+ VMPage(app) : super('vm', 'service-view', app);
+
+ void _visit(Uri uri) {
+ super._visit(uri);
+ app.vm.reload().then((vm) {
+ if (element != null) {
+ ServiceObjectViewElement serviceElement = element;
+ serviceElement.object = vm;
+ }
+ }).catchError((e) {
+ Logger.root.severe('VMPage visit error: $e');
+ });
+ }
+}
+
+class FlagsPage extends SimplePage {
+ FlagsPage(app) : super('flags', 'flag-list', app);
+
+ void _visit(Uri uri) {
+ super._visit(uri);
+ app.vm.getFlagList().then((flags) {
+ if (element != null) {
+ FlagListElement serviceElement = element;
+ serviceElement.flagList = flags;
+ }
+ }).catchError((e) {
+ Logger.root.severe('FlagsPage visit error: $e');
+ });
+ }
+}
+
+class InspectPage extends SimplePage {
+ InspectPage(app) : super('inspect', 'service-view', app);
+
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
+ var objectId = uri.queryParameters['objectId'];
+ if (objectId == null) {
+ isolate.reload().then(_visitObject);
+ } else {
+ isolate.getObject(objectId).then(_visitObject);
+ }
+ });
+ }
+
+ void _visitObject(obj) {
+ if (element != null) {
+ ServiceObjectViewElement serviceElement = element;
+ serviceElement.object = obj;
+ }
+ }
}
/// Class tree page.
-class ClassTreePage extends IsolateSuffixPage {
- ClassTreePage(app) : super('class-tree/', 'class-tree', app);
+class ClassTreePage extends SimplePage {
+ ClassTreePage(app) : super('class-tree', 'class-tree', app);
- void _visit(String url) {
- super._visit(url);
- getIsolate().then((isolate) {
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
if (element != null) {
/// Update the page.
ClassTreeElement page = element;
@@ -117,12 +172,12 @@
}
}
-class DebuggerPage extends IsolateSuffixPage {
- DebuggerPage(app) : super('debugger/', 'debugger-page', app);
+class DebuggerPage extends SimplePage {
+ DebuggerPage(app) : super('debugger', 'debugger-page', app);
- void _visit(String url) {
- super._visit(url);
- getIsolate().then((isolate) {
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
if (element != null) {
/// Update the page.
DebuggerPageElement page = element;
@@ -132,12 +187,12 @@
}
}
-class CpuProfilerPage extends IsolateSuffixPage {
- CpuProfilerPage(app) : super('profiler/', 'cpu-profile', app);
+class CpuProfilerPage extends SimplePage {
+ CpuProfilerPage(app) : super('profiler', 'cpu-profile', app);
- void _visit(String url) {
- super._visit(url);
- getIsolate().then((isolate) {
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
if (element != null) {
/// Update the page.
CpuProfileElement page = element;
@@ -147,13 +202,13 @@
}
}
-class AllocationProfilerPage extends IsolateSuffixPage {
+class AllocationProfilerPage extends SimplePage {
AllocationProfilerPage(app)
- : super('allocation-profiler/', 'heap-profile', app);
+ : super('allocation-profiler', 'heap-profile', app);
- void _visit(String url) {
- super._visit(url);
- getIsolate().then((isolate) {
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
if (element != null) {
/// Update the page.
HeapProfileElement page = element;
@@ -163,12 +218,12 @@
}
}
-class HeapMapPage extends IsolateSuffixPage {
- HeapMapPage(app) : super('heap-map/', 'heap-map', app);
+class HeapMapPage extends SimplePage {
+ HeapMapPage(app) : super('heap-map', 'heap-map', app);
- void _visit(String url) {
- super._visit(url);
- getIsolate().then((isolate) {
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
if (element != null) {
/// Update the page.
HeapMapElement page = element;
@@ -188,13 +243,14 @@
}
}
- void _visit(String url) {
+ void _visit(Uri uri) {
assert(element != null);
- assert(canVisit(url));
+ assert(canVisit(uri));
(element as ServiceObjectViewElement).object = app.lastErrorOrException;
}
- bool canVisit(String url) => url.startsWith('error/');
+ // TODO(turnidge): How to test this page?
+ bool canVisit(Uri uri) => uri.path.startsWith('error/');
}
class VMConnectPage extends Page {
@@ -207,18 +263,16 @@
assert(element != null);
}
- void _visit(String url) {
+ void _visit(Uri uri) {
assert(element != null);
- assert(canVisit(url));
+ assert(canVisit(uri));
}
- bool canVisit(String url) => url.startsWith('vm-connect/');
+ // TODO(turnidge): Update this to not have the trailing slash.
+ bool canVisit(Uri uri) => uri.path.startsWith('vm-connect/');
}
class MetricsPage extends Page {
- static RegExp _matcher = new RegExp(r'isolates/.*/metrics');
- static RegExp _isolateMatcher = new RegExp(r'isolates/.*/');
-
// Page state, retained as long as ObservatoryApplication.
String selectedMetricId;
@@ -266,20 +320,13 @@
throw new FallThroughError();
}
- String _isolateId(String url) {
- // Grab isolate prefix.
- String isolateId = _isolateMatcher.stringMatch(url);
- // Remove the trailing slash.
- return isolateId.substring(0, isolateId.length - 1);
- }
-
- void _visit(String url) {
+ void _visit(Uri uri) {
assert(element != null);
- assert(canVisit(url));
- app.vm.getIsolate(_isolateId(url)).then((i) {
+ assert(canVisit(uri));
+ app.vm.getIsolate(uri.queryParameters['isolateId']).then((i) {
(element as MetricsPageElement).isolate = i;
});
}
- bool canVisit(String url) => _matcher.hasMatch(url);
+ bool canVisit(Uri uri) => uri.path == 'metrics';
}
diff --git a/runtime/observatory/lib/src/elements/breakpoint_list.dart b/runtime/observatory/lib/src/elements/breakpoint_list.dart
deleted file mode 100644
index 157e6c5..0000000
--- a/runtime/observatory/lib/src/elements/breakpoint_list.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2013, 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 breakpoint_list_element;
-
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
-
-// TODO(turnidge): Is a breakpoint list associated with a VM or an isolate?
-@CustomTag('breakpoint-list')
-class BreakpointListElement extends ObservatoryElement {
- @published ServiceMap msg;
-
- BreakpointListElement.created() : super.created();
-
- void refresh(var done) {
- msg.reload().whenComplete(done);
- }
-}
diff --git a/runtime/observatory/lib/src/elements/breakpoint_list.html b/runtime/observatory/lib/src/elements/breakpoint_list.html
deleted file mode 100644
index ec2cd7d..0000000
--- a/runtime/observatory/lib/src/elements/breakpoint_list.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-
-<polymer-element name="breakpoint-list" extends="observatory-element">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <nav-bar>
- <top-nav-menu></top-nav-menu>
- <isolate-nav-menu isolate="{{ msg.isolate }}"></isolate-nav-menu>
- <nav-menu link="{{ gotoLink(msg.isolate.relativeLink('debug/breakpoints')) }}" anchor="breakpoints" last="{{ true }}"></nav-menu>
- <nav-refresh callback="{{ refresh }}"></nav-refresh>
- <nav-control></nav-control>
- </nav-bar>
- <template if="{{ msg['breakpoints'].isEmpty }}">
- <div>
- <div>No breakpoints</div>
- </div>
- </template>
- <template if="{{ msg['breakpoints'].isNotEmpty }}">
- <ul class="list-group">
- <template repeat="{{ bpt in msg['breakpoints'] }}">
- <li class="list-group-item">
- {{ bpt }}
- </li>
- </template>
- </ul>
- </template>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="breakpoint_list.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/code_view.html b/runtime/observatory/lib/src/elements/code_view.html
index bd1396b..56010b4 100644
--- a/runtime/observatory/lib/src/elements/code_view.html
+++ b/runtime/observatory/lib/src/elements/code_view.html
@@ -57,7 +57,7 @@
<nav-bar>
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ code.isolate }}"></isolate-nav-menu>
- <nav-menu link="{{ code.link }}" anchor="{{ code.name }}" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/inspect', code) }}" anchor="{{ code.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 90b1518..cc7d0c0 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -11,7 +11,7 @@
<nav-bar>
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
- <nav-menu link="{{ '/profiler' + isolate.link }}" anchor="cpu profile" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/profiler', isolate) }}" anchor="cpu profile" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 347cba3..6b15957 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -57,7 +57,7 @@
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ isolate }}">
</isolate-nav-menu>
- <nav-menu link="{{ '/debugger' + isolate.link) }}" anchor="debugger" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/debugger', isolate) }}" anchor="debugger" last="{{ true }}"></nav-menu>
<nav-control></nav-control>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index e73e292..2a9d728 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -19,7 +19,7 @@
<template if="{{ field.owner.type == 'Library' }}">
<library-nav-menu library="{{ field.owner }}"></library-nav-menu>
</template>
- <nav-menu link="{{ field.link }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/inspect', field) }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
index d1861df..94a2bdb 100644
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ b/runtime/observatory/lib/src/elements/flag_list.html
@@ -7,7 +7,7 @@
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu></top-nav-menu>
- <nav-menu link="{{ flagList.vm.relativeLink('flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 439b6a6..519cad8 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -21,7 +21,7 @@
<template if="{{ function.owningLibrary != null }}">
<library-nav-menu library="{{ function.owningLibrary }}"></library-nav-menu>
</template>
- <nav-menu link="{{ function.link }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
diff --git a/runtime/observatory/lib/src/elements/general_error.dart b/runtime/observatory/lib/src/elements/general_error.dart
new file mode 100644
index 0000000..d47ec04
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/general_error.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2013, 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 general_error_element;
+
+import 'observatory_element.dart';
+import 'package:polymer/polymer.dart';
+
+/// Displays an error message
+@CustomTag('general-error')
+class GeneralErrorElement extends ObservatoryElement {
+ @published String message;
+
+ GeneralErrorElement.created() : super.created();
+}
diff --git a/runtime/observatory/lib/src/elements/general_error.html b/runtime/observatory/lib/src/elements/general_error.html
new file mode 100644
index 0000000..ac32b03
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/general_error.html
@@ -0,0 +1,20 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="nav_bar.html">
+<link rel="import" href="observatory_element.html">
+
+<polymer-element name="general-error" extends="observatory-element">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <nav-bar>
+ <top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-control></nav-control>
+ </nav-bar>
+ <div class="content-centered">
+ <h1>Error</h1>
+ <br>
+ <div class="well">{{ message }}</div>
+ </div>
+ </template>
+</polymer-element>
+
+<script type="application/dart" src="general_error.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/heap_map.dart b/runtime/observatory/lib/src/elements/heap_map.dart
index 2e36c2d..05ed60a 100644
--- a/runtime/observatory/lib/src/elements/heap_map.dart
+++ b/runtime/observatory/lib/src/elements/heap_map.dart
@@ -96,7 +96,7 @@
}
void _updateClassList(classList, int freeClassId) {
- for (var member in classList['members']) {
+ for (var member in classList['classes']) {
if (member is! Class) {
// TODO(turnidge): The printing for some of these non-class
// members is broken. Fix this:
@@ -160,8 +160,13 @@
void _handleClick(MouseEvent event) {
var address = _objectAt(event.offset).address.toRadixString(16);
- app.locationManager.go(app.locationManager.makeLink(
- "${isolate.relativeLink('address/$address')}"));
+ isolate.getObjectByAddress(address).then((result) {
+ if (result is DartError) {
+ Logger.root.severe(result.message);
+ } else {
+ app.locationManager.go(gotoLink('/inspect', result));
+ }
+ });
}
void _updateFragmentationData() {
diff --git a/runtime/observatory/lib/src/elements/heap_map.html b/runtime/observatory/lib/src/elements/heap_map.html
index a4296ab..66bd845 100644
--- a/runtime/observatory/lib/src/elements/heap_map.html
+++ b/runtime/observatory/lib/src/elements/heap_map.html
@@ -22,7 +22,7 @@
<nav-bar pad="{{ false }}">
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ fragmentation.isolate }}"></isolate-nav-menu>
- <nav-menu link="{{ fragmentation.isolate.relativeLink('heapmap') }}" anchor="heap map" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/heap-map', fragmentation.isolate) }}" anchor="heap map" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
</nav-bar>
@@ -38,4 +38,4 @@
</template>
</polymer-element>
-<script type="application/dart" src="heap_map.dart"></script>
\ No newline at end of file
+<script type="application/dart" src="heap_map.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/heap_profile.html b/runtime/observatory/lib/src/elements/heap_profile.html
index fafdcfb..3d0bfec 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.html
+++ b/runtime/observatory/lib/src/elements/heap_profile.html
@@ -53,7 +53,7 @@
<nav-bar>
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ profile.isolate }}"></isolate-nav-menu>
- <nav-menu link="{{ profile.isolate.relativeLink('allocationprofile') }}" anchor="allocation profile" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/allocation-profiler', profile.isolate) }}" anchor="allocation profile" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ resetAccumulator }}" label="Reset Accumulator"></nav-refresh>
<nav-refresh callback="{{ refreshGC }}" label="GC"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
diff --git a/runtime/observatory/lib/src/elements/io_view.html b/runtime/observatory/lib/src/elements/io_view.html
index 4072404..a63f010 100644
--- a/runtime/observatory/lib/src/elements/io_view.html
+++ b/runtime/observatory/lib/src/elements/io_view.html
@@ -20,7 +20,7 @@
<ul class="list-group">
<li class="list-group-item">
- <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/http/servers'))}}">HTTP Servers</a>
+ <a on-click="{{ goto }}" _href="{{gotoLink('io/http/servers', isolate)}}">HTTP Servers</a>
</li>
</ul>
@@ -28,7 +28,7 @@
<ul class="list-group">
<li class="list-group-item">
- <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/sockets'))}}">Sockets</a>
+ <a on-click="{{ goto }}" _href="{{gotoLink('io/sockets', isolate)}}">Sockets</a>
</li>
</ul>
@@ -36,7 +36,7 @@
<ul class="list-group">
<li class="list-group-item">
- <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/websockets'))}}">WebSockets</a>
+ <a on-click="{{ goto }}" _href="{{gotoLink('io/websockets', isolate)}}">WebSockets</a>
</li>
</ul>
@@ -44,7 +44,7 @@
<ul class="list-group">
<li class="list-group-item">
- <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/file/randomaccessfiles'))}}">Random Access Files</a>
+ <a on-click="{{ goto }}" _href="{{gotoLink('io/file/randomaccessfiles', isolate)}}">Random Access Files</a>
</li>
</ul>
@@ -52,7 +52,7 @@
<ul class="list-group">
<li class="list-group-item">
- <a on-click="{{ goto }}" _href="{{gotoLink(io.isolate.relativeLink('io/processes'))}}">Processes</a>
+ <a on-click="{{ goto }}" _href="{{gotoLink('io/processes', isolate)}}">Processes</a>
</li>
</ul>
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index 5718cdb..5331b1e 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -152,39 +152,39 @@
<br>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink('/debugger' + isolate.link) }}">debugger</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/debugger', isolate) }}">debugger</a>
</div>
</div>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink('/class-tree' + isolate.link) }}">class hierarchy</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/class-tree', isolate) }}">class hierarchy</a>
</div>
</div>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink('/profiler' + isolate.link) }}">cpu profile</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/profiler', isolate) }}">cpu profile</a>
</div>
</div>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink('/allocation-profiler' + isolate.link) }}">allocation profile</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/allocation-profiler', isolate) }}">allocation profile</a>
</div>
</div>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink('/heap-map' + isolate.link) }}">heap map</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/heap-map', isolate) }}">heap map</a>
</div>
</div>
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink(isolate.relativeLink('metrics')) }}">metrics</a>
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/metrics', isolate) }}">metrics</a>
</div>
</div>
<!-- Temporarily disabled until UI for dart:io is acceptable.
<template if="{{ isolate.ioEnabled }}">
<div class="memberItem">
<div class="memberValue">
- See <a on-click="{{ goto }}" href="{{ gotoLink(isolate.relativeLink('io')) }}">dart:io</a>
+ See <a on-click="{{ goto }}" href="{{ gotoLink('/io', isolate) }}">dart:io</a>
</div>
</div>
</template>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 9ac4ed8..615a855 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -99,13 +99,6 @@
</div>
</div>
</div>
- <div class="flex-item-50-percent">
- <div class="memberItem">
- <div class="memberValue">
- See <a on-click="{{ goto }}" _href="{{ gotoLink(isolate.relativeLink('debug/breakpoints')) }}">breakpoints</a>
- </div>
- </div>
- </div>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.dart b/runtime/observatory/lib/src/elements/nav_bar.dart
index 9f5b0ed..75e7d66 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.dart
+++ b/runtime/observatory/lib/src/elements/nav_bar.dart
@@ -83,21 +83,6 @@
@published bool last = false;
@published Isolate isolate;
- void isolateChanged(oldValue) {
- notifyPropertyChange(#hashLinkWorkaround, 0, 1);
- }
-
- // TODO(turnidge): Figure out why polymer needs this function.
- @reflectable
- String get hashLinkWorkaround {
- if (isolate != null) {
- return isolate.link;
- } else {
- return '';
- }
- }
- @reflectable set hashLinkWorkaround(var x) { /* silence polymer */ }
-
IsolateNavMenuElement.created() : super.created();
}
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index 9ffecd1..bb6c045 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -201,14 +201,14 @@
<polymer-element name="isolate-nav-menu" extends="observatory-element">
<template>
- <nav-menu link="{{ hashLinkWorkaround }}" anchor="{{ isolate.name }}" last="{{ last }}">
- <nav-menu-item link="{{ '/debugger' + isolate.link }}"
+ <nav-menu link="{{ makeLink('/inspect', isolate) }}" anchor="{{ isolate.name }}" last="{{ last }}">
+ <nav-menu-item link="{{ makeLink('/debugger', isolate) }}"
anchor="debugger"></nav-menu-item>
- <nav-menu-item link="{{ '/profiler' + isolate.link }}"
+ <nav-menu-item link="{{ makeLink('/profiler', isolate) }}"
anchor="cpu profile"></nav-menu-item>
- <nav-menu-item link="{{ '/allocation-profiler' + isolate.link }}"
+ <nav-menu-item link="{{ makeLink('/allocation-profiler', isolate) }}"
anchor="allocation profile"></nav-menu-item>
- <nav-menu-item link="{{ '/heap-map' + isolate.link }}"
+ <nav-menu-item link="{{ makeLink('/heap-map', isolate) }}"
anchor="heap map"></nav-menu-item>
<content></content>
</nav-menu>
@@ -217,7 +217,7 @@
<polymer-element name="library-nav-menu" extends="observatory-element">
<template>
- <nav-menu link="{{ library.link }}"
+ <nav-menu link="{{ makeLink('/inspect', library) }}"
anchor="{{ library.name }}" last="{{ last }}">
<content></content>
</nav-menu>
@@ -226,7 +226,7 @@
<polymer-element name="class-nav-menu" extends="observatory-element">
<template>
- <nav-menu link="{{ cls.link }}"
+ <nav-menu link="{{ makeLink('/inspect', cls) }}"
anchor="{{ cls.name }}" last="{{ last }}">
<content></content>
</nav-menu>
@@ -320,7 +320,7 @@
<div class="item">
Isolate
<a class="link" on-click="{{ goto }}"
- _href="{{ event.isolate.link }}">{{ event.isolate.name }}</a>
+ _href="{{ gotoLink('/inspect', event.isolate) }}">{{ event.isolate.name }}</a>
is paused
<template if="{{ event.breakpoint != null }}">
at breakpoint
diff --git a/runtime/observatory/lib/src/elements/observatory_element.dart b/runtime/observatory/lib/src/elements/observatory_element.dart
index b31ac94..9e9a363 100644
--- a/runtime/observatory/lib/src/elements/observatory_element.dart
+++ b/runtime/observatory/lib/src/elements/observatory_element.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:html';
import 'package:observatory/app.dart';
+import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
/// Base class for all Observatory custom elements.
@@ -91,9 +92,21 @@
event.stopPropagation();
}
+ String makeLink(String url, [ServiceObject obj]) {
+ if (obj != null) {
+ if (obj is Isolate) {
+ url = '${url}?isolateId=${Uri.encodeComponent(obj.id)}';
+ } else {
+ url = ('${url}?isolateId=${Uri.encodeComponent(obj.isolate.id)}'
+ '&objectId=${Uri.encodeComponent(obj.id)}');
+ }
+ }
+ return url;
+ }
+
/// Create a link that can be consumed by [goto].
- String gotoLink(String url) {
- return app.locationManager.makeLink(url);
+ String gotoLink(String url, [ServiceObject obj]) {
+ return app.locationManager.makeLink(makeLink(url, obj));
}
String formatTimePrecise(double time) => Utils.formatTimePrecise(time);
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index b6f31ec..7e376f7 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -10,8 +10,8 @@
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ script.isolate }}">
</isolate-nav-menu>
- <nav-menu link="{{ script.owningLibrary.link }}" anchor="{{ script.owningLibrary.name }}"></nav-menu>
- <nav-menu link="{{ script.link }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/inspect', script.owningLibrary) }}" anchor="{{ script.owningLibrary.name }}"></nav-menu>
+ <nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-control></nav-control>
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 63f2449..f8ef42e 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -27,7 +27,7 @@
if (ref == null) {
return 'NULL REF';
}
- return gotoLink(ref.link);
+ return gotoLink('/inspect', ref);
}
String get serviceId {
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index 98ed51c..ad12afd 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -26,10 +26,6 @@
HeapProfileElement element = new Element.tag('heap-profile');
element.profile = object;
return element;
- case 'BreakpointList':
- BreakpointListElement element = new Element.tag('breakpoint-list');
- element.msg = object;
- return element;
case 'Class':
ClassViewElement element = new Element.tag('class-view');
element.cls = object;
diff --git a/runtime/observatory/lib/src/elements/service_view.html b/runtime/observatory/lib/src/elements/service_view.html
index 02a3ff8..b3254c0 100644
--- a/runtime/observatory/lib/src/elements/service_view.html
+++ b/runtime/observatory/lib/src/elements/service_view.html
@@ -1,5 +1,4 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="breakpoint_list.html">
<link rel="import" href="class_view.html">
<link rel="import" href="code_view.html">
<link rel="import" href="context_view.html">
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index b22a887..f4ec057 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -4,8 +4,7 @@
part of service;
-/// A [ServiceObject] is an object known to the VM service and is tied
-/// to an owning [Isolate].
+/// A [ServiceObject] represents a persistent object within the vm.
abstract class ServiceObject extends Observable {
static int LexicalSortName(ServiceObject o1, ServiceObject o2) {
return o1.name.compareTo(o2.name);
@@ -90,9 +89,6 @@
!isMirrorReference && !isWeakProperty && !isClosure);
}
- /// The complete service url of this object.
- @reflectable String get link => _owner.relativeLink(_id);
-
/// Has this object been fully loaded?
bool get loaded => _loaded;
bool _loaded = false;
@@ -282,19 +278,12 @@
// Updates internal state from [map]. [map] can be a reference.
void _update(ObservableMap map, bool mapIsRef);
-
- String relativeLink(String id) {
- assert(id != null);
- return "${link}/${id}";
- }
}
abstract class Coverage {
// Following getters and functions will be provided by [ServiceObject].
- ServiceObjectOwner get owner;
- String get type;
- VM get vm;
- String relativeLink(String id);
+ String get id;
+ Isolate get isolate;
/// Default handler for coverage data.
void processCoverageData(List coverageData) {
@@ -311,8 +300,7 @@
}
return isolate.invokeRpcNoUpgrade('getCoverage', params).then(
(ObservableMap map) {
- var coverageOwner = (type == 'Isolate') ? this : owner;
- var coverage = new ServiceObject._fromMap(coverageOwner, map);
+ var coverage = new ServiceObject._fromMap(isolate, map);
assert(coverage.type == 'CodeCoverage');
var coverageList = coverage['coverage'];
assert(coverageList != null);
@@ -329,9 +317,6 @@
/// The result may come from the cache. The result will not necessarily
/// be [loaded].
ServiceObject getFromMap(ObservableMap map);
-
- /// Creates a link to [id] relative to [this].
- String relativeLink(String id);
}
/// State for a VM being inspected.
@@ -341,9 +326,6 @@
@reflectable Iterable<Isolate> get isolates => _isolateCache.values;
- @reflectable String get link => '$id';
- @reflectable String relativeLink(String id) => '$id';
-
@observable String version = 'unknown';
@observable String targetCPU;
@observable int architectureBits;
@@ -450,42 +432,6 @@
});
}
- Future<ServiceObject> getDeprecated(String id) {
- assert(id.startsWith('/') == false);
- // Isolates are handled specially, since they can cache sub-objects.
- if (id.startsWith(_isolatesPrefix)) {
- String isolateId = _parseIsolateId(id);
- String objectId = _parseObjectId(id);
- return getIsolate(isolateId).then((isolate) {
- if (isolate == null) {
- // The isolate does not exist. Return the VM object instead.
- //
- // TODO(turnidge): Generate a service error?
- return this;
- }
- if (objectId == null) {
- return isolate.reload();
- } else {
- return isolate.getDeprecated(objectId);
- }
- });
- }
-
- var obj = _cache[id];
- if (obj != null) {
- return obj.reload();
- }
-
- // Cache miss. Get the object from the vm directly.
- return _getAsMapDeprecated(id).then((ObservableMap map) {
- var obj = new ServiceObject._fromMap(this, map);
- if (obj.canCache) {
- _cache.putIfAbsent(id, () => obj);
- }
- return obj;
- });
- }
-
dynamic _reviver(dynamic key, dynamic value) {
return value;
}
@@ -527,31 +473,6 @@
return new Future.value(map);
}
- /// Gets [id] as an [ObservableMap] from the service directly. If
- /// an error occurs, the future is completed as an error with a
- /// ServiceError or ServiceException. Therefore any chained then() calls
- /// will only receive a map encoding a valid ServiceObject.
- Future<ObservableMap> _getAsMapDeprecated(String id) {
- return getStringDeprecated(id).then((response) {
- var map = _parseJSON(response);
- if (Tracer.current != null) {
- Tracer.current.trace("Received response for ${id}", map:map);
- }
- return _processMap(map);
- }).catchError((error) {
- // ServiceError, forward to VM's ServiceError stream.
- errors.add(error);
- return new Future.error(error);
- }, test: (e) => e is ServiceError).catchError((exception) {
- // ServiceException, forward to VM's ServiceException stream.
- exceptions.add(exception);
- return new Future.error(exception);
- }, test: (e) => e is ServiceException);
- }
-
- /// Get [id] as a [String] from the service directly. See [getAsMap].
- Future<String> getStringDeprecated(String id);
-
// Implemented in subclass.
Future<String> invokeRpcRaw(String method, Map params);
@@ -592,6 +513,10 @@
return invokeRpcNoUpgrade('getVM', {});
}
+ Future<ServiceObject> getFlagList() {
+ return invokeRpc('getFlagList', {});
+ }
+
/// Force the VM to disconnect.
void disconnect();
/// Completes when the VM first connects.
@@ -754,8 +679,7 @@
var result = [];
for (var v in graph.getMostRetained(classId: classId, limit: limit)) {
var address = v.addressForWordSize(isolate.vm.architectureBits ~/ 8);
- result.add(isolate.getDeprecated(
- 'address/${address.toRadixString(16)}?ref=true').then((obj) {
+ result.add(isolate.getObjectByAddress(address.toRadixString(16)).then((obj) {
obj.retainedSize = v.retainedSize;
return new Future(() => obj);
}));
@@ -772,8 +696,6 @@
@reflectable Isolate get isolate => this;
@observable ObservableMap counters = new ObservableMap();
- String get link => '/${_id}';
-
@observable ServiceEvent pauseEvent = null;
bool get _isPaused => pauseEvent != null;
@@ -789,9 +711,6 @@
assert(owner is VM);
}
- /// Creates a link to [id] relative to [this].
- @reflectable String relativeLink(String id) => '/${this.id}/$id';
-
static const TAG_ROOT_ID = 'code/tag-0';
/// Returns the Code object for the root tag.
@@ -890,25 +809,8 @@
return obj;
}
- Future<ServiceObject> getDeprecated(String id) {
- // Do not allow null ids or empty ids.
- assert(id != null && id != '');
- var obj = _cache[id];
- if (obj != null) {
- return obj.reload();
- }
- // Cache miss. Get the object from the vm directly.
- return vm._getAsMapDeprecated(relativeLink(id)).then((ObservableMap map) {
- var obj = new ServiceObject._fromMap(this, map);
- if (obj.canCache) {
- _cache.putIfAbsent(id, () => obj);
- }
- return obj;
- });
- }
-
Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
- params['isolate'] = id;
+ params['isolateId'] = id;
return vm.invokeRpcNoUpgrade(method, params);
}
@@ -1327,6 +1229,14 @@
return invokeRpc('getInstances', params);
}
+ Future<ServiceObject> getObjectByAddress(String address, [bool ref=true]) {
+ Map params = {
+ 'address': address,
+ 'ref': ref,
+ };
+ return invokeRpc('getObjectByAddress', params);
+ }
+
final ObservableMap<String, ServiceMetric> dartMetrics =
new ObservableMap<String, ServiceMetric>();
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index bf4723a..1eb2ba2 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -67,8 +67,6 @@
'lib/src/app/view_model.dart',
'lib/src/elements/action_link.dart',
'lib/src/elements/action_link.html',
- 'lib/src/elements/breakpoint_list.dart',
- 'lib/src/elements/breakpoint_list.html',
'lib/src/elements/class_ref.dart',
'lib/src/elements/class_ref.html',
'lib/src/elements/class_tree.dart',
@@ -107,6 +105,8 @@
'lib/src/elements/function_ref.html',
'lib/src/elements/function_view.dart',
'lib/src/elements/function_view.html',
+ 'lib/src/elements/general_error.dart',
+ 'lib/src/elements/general_error.html',
'lib/src/elements/heap_map.dart',
'lib/src/elements/heap_map.html',
'lib/src/elements/heap_profile.dart',
diff --git a/runtime/tests/vm/dart/bad_snapshot b/runtime/tests/vm/dart/bad_snapshot
new file mode 100644
index 0000000..9b1a92d
--- /dev/null
+++ b/runtime/tests/vm/dart/bad_snapshot
Binary files differ
diff --git a/runtime/tests/vm/dart/snapshot_version_test.dart b/runtime/tests/vm/dart/snapshot_version_test.dart
new file mode 100644
index 0000000..2dcde10
--- /dev/null
+++ b/runtime/tests/vm/dart/snapshot_version_test.dart
@@ -0,0 +1,14 @@
+// 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.
+
+import "dart:io";
+import "package:expect/expect.dart";
+
+main() {
+ var result = Process.runSync(Platform.executable,
+ [Platform.script.resolve('./bad_snapshot').toFilePath()]);
+ print("=== stdout ===\n ${result.stdout}");
+ print("=== stderr ===\n ${result.stderr}");
+ Expect.equals(253, result.exitCode);
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index d2d66d6..dfe5f584 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -85,3 +85,6 @@
[ $compiler == none && $runtime == ContentShellOnAndroid ]
dart/byte_array_test: RuntimeError # Issue 17612
+
+[ $runtime != vm ]
+dart/snapshot_version_test: SkipByDesign # Spawns processes
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index f0de423..32719ac 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -24,6 +24,7 @@
V(Function_apply, 2) \
V(FunctionImpl_equals, 2) \
V(FunctionImpl_hashCode, 1) \
+ V(FunctionImpl_clone, 1) \
V(AbstractType_toString, 1) \
V(Identical_comparison, 2) \
V(Integer_bitAndFromInteger, 2) \
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 6d97ba5..38b5f2f 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -639,8 +639,8 @@
DEFINE_RUNTIME_ENTRY(ReThrow, 2) {
const Instance& exception =
Instance::CheckedHandle(isolate, arguments.ArgAt(0));
- const Instance& stacktrace =
- Instance::CheckedHandle(isolate, arguments.ArgAt(1));
+ const Stacktrace& stacktrace =
+ Stacktrace::CheckedHandle(isolate, arguments.ArgAt(1));
Exceptions::ReThrow(isolate, exception, stacktrace);
}
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 77af93c..04eabbb 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -761,7 +761,7 @@
if (obj.IsNull()) {
RETURN_TYPE_ERROR(isolate, exception, Instance);
}
- const Instance& stacktrace = Instance::Handle(isolate);
+ const Stacktrace& stacktrace = Stacktrace::Handle(isolate);
return Api::NewHandle(isolate, UnhandledException::New(obj, stacktrace));
}
@@ -4373,16 +4373,16 @@
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
const Instance* saved_exception;
- const Instance* saved_stacktrace;
+ const Stacktrace* saved_stacktrace;
{
NoGCScope no_gc;
RawInstance* raw_exception =
Api::UnwrapInstanceHandle(isolate, exception).raw();
- RawInstance* raw_stacktrace =
- Api::UnwrapInstanceHandle(isolate, stacktrace).raw();
+ RawStacktrace* raw_stacktrace =
+ Api::UnwrapStacktraceHandle(isolate, stacktrace).raw();
state->UnwindScopes(isolate->top_exit_frame_info());
saved_exception = &Instance::Handle(raw_exception);
- saved_stacktrace = &Instance::Handle(raw_stacktrace);
+ saved_stacktrace = &Stacktrace::Handle(raw_stacktrace);
}
Exceptions::ReThrow(isolate, *saved_exception, *saved_stacktrace);
return Api::NewError("Exception was not re thrown, internal error");
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 4cb32fc..d863b24 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -361,7 +361,7 @@
static void ThrowExceptionHelper(Isolate* isolate,
const Instance& incoming_exception,
- const Instance& existing_stacktrace,
+ const Stacktrace& existing_stacktrace,
const bool is_rethrow) {
bool use_preallocated_stacktrace = false;
Instance& exception = Instance::Handle(isolate, incoming_exception.raw());
@@ -426,7 +426,7 @@
stacktrace = Stacktrace::New(code_array, pc_offset_array);
} else {
ASSERT(is_rethrow);
- stacktrace ^= existing_stacktrace.raw();
+ stacktrace = existing_stacktrace.raw();
if (pc_offset_array.Length() != 0) {
// Skip the first frame during a rethrow. This is the catch clause
// with the rethrow statement, which is not part of the original
@@ -573,13 +573,13 @@
isolate->debugger()->SignalExceptionThrown(exception);
}
// Null object is a valid exception object.
- ThrowExceptionHelper(isolate, exception, Instance::Handle(isolate), false);
+ ThrowExceptionHelper(isolate, exception, Stacktrace::Handle(isolate), false);
}
void Exceptions::ReThrow(Isolate* isolate,
const Instance& exception,
- const Instance& stacktrace) {
+ const Stacktrace& stacktrace) {
// Null object is a valid exception object.
ThrowExceptionHelper(isolate, exception, stacktrace, true);
}
@@ -593,7 +593,7 @@
// rethrow the exception in the normal fashion.
const UnhandledException& uhe = UnhandledException::Cast(error);
const Instance& exc = Instance::Handle(isolate, uhe.exception());
- const Instance& stk = Instance::Handle(isolate, uhe.stacktrace());
+ const Stacktrace& stk = Stacktrace::Handle(isolate, uhe.stacktrace());
Exceptions::ReThrow(isolate, exc, stk);
} else {
// Return to the invocation stub and return this error object. The
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index cf0eb98..9743ca8 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -24,6 +24,7 @@
class RawString;
class Script;
class StackFrame;
+class Stacktrace;
class String;
class Exceptions : AllStatic {
@@ -33,7 +34,7 @@
static void Throw(Isolate* isolate, const Instance& exception);
static void ReThrow(Isolate* isolate,
const Instance& exception,
- const Instance& stacktrace);
+ const Stacktrace& stacktrace);
static void PropagateError(const Error& error);
// Helpers to create and throw errors.
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 009c60c..afc250d 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1075,13 +1075,13 @@
//
// We distinguish those kinds of nodes via is_regular_return().
//
- if (function.is_async_closure() &&
+ if (function.IsAsyncClosure() &&
(node->return_type() == ReturnNode::kRegular)) {
// Temporary store the computed return value.
Do(BuildStoreExprTemp(return_value));
- LocalVariable* rcv_var = node->scope()->LookupVariable(
- Symbols::AsyncCompleter(), false);
+ LocalVariable* rcv_var =
+ node->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
ASSERT(rcv_var != NULL && rcv_var->is_captured());
ZoneGrowableArray<PushArgumentInstr*>* arguments =
new(I) ZoneGrowableArray<PushArgumentInstr*>(2);
@@ -1109,10 +1109,9 @@
UnchainContexts(current_context_level);
}
-
AddReturnExit(node->token_pos(), return_value);
- if (function.is_async_closure() &&
+ if ((function.IsAsyncClosure() || function.IsSyncGenClosure()) &&
(node->return_type() == ReturnNode::kContinuationTarget)) {
JoinEntryInstr* const join = new(I) JoinEntryInstr(
owner()->AllocateBlockId(), owner()->try_index());
@@ -1484,6 +1483,62 @@
}
+void EffectGraphVisitor::BuildYieldJump(LocalVariable* old_context,
+ LocalVariable* iterator_param,
+ const intptr_t old_ctx_level,
+ JoinEntryInstr* target) {
+ // Building a jump consists of the following actions:
+ // * Load the generator body's iterator parameter (:iterator)
+ // from the current context into a temporary.
+ // * Restore the old context from :await_cxt_var.
+ // * Copy the iterator saved above into the restored context.
+ // * Append a Goto to the target's join.
+ ASSERT((iterator_param != NULL) && iterator_param->is_captured());
+ ASSERT((old_context != NULL) && old_context->is_captured());
+ // Before restoring the context we need to temporarily save the
+ // iterator parameter.
+ LocalVariable* temp_iterator_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*iterator_param)));
+
+ // Restore the saved continuation context, i.e. the context that was
+ // saved into :await_ctx_var before the closure suspended.
+ BuildRestoreContext(*old_context);
+
+ // Store the continuation result and continuation error values into
+ // the restored context.
+
+ // FlowGraphBuilder is at top context level, but the continuation
+ // target has possibly been recorded in a nested context (old_ctx_level).
+ // We need to unroll manually here.
+ intptr_t delta =
+ old_ctx_level - iterator_param->owner()->context_level();
+ ASSERT(delta >= 0);
+ Value* context = Bind(BuildCurrentContext());
+ while (delta-- > 0) {
+ context = Bind(new(I) LoadFieldInstr(
+ context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
+ Scanner::kNoSourcePos));
+ }
+ LocalVariable* temp_context_var = EnterTempLocalScope(context);
+
+ Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var));
+ Value* store_val = Bind(new(I) LoadLocalInstr(*temp_iterator_var));
+ StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
+ Context::variable_offset(iterator_param->index()),
+ context_val,
+ store_val,
+ kEmitStoreBarrier,
+ Scanner::kNoSourcePos);
+ Do(store);
+
+ Do(ExitTempLocalScope(temp_context_var));
+ Do(ExitTempLocalScope(temp_iterator_var));
+
+ // Goto saved join.
+ Goto(target);
+}
+
+
void EffectGraphVisitor::BuildAwaitJump(LocalVariable* old_context,
LocalVariable* continuation_result,
LocalVariable* continuation_error,
@@ -1491,31 +1546,37 @@
const intptr_t old_ctx_level,
JoinEntryInstr* target) {
// Building a jump consists of the following actions:
- // * Record the current continuation result in a temporary.
- // * Restore the old context.
- // * Overwrite the old context's continuation result with the temporary.
+ // * Load the current continuation result parameter (:async_result)
+ // and continuation error parameter (:async_error_param) from
+ // the current context into temporaries.
+ // * Restore the old context from :await_cxt_var.
+ // * Copy the result and error parameters saved above into the restored
+ // context.
// * Append a Goto to the target's join.
ASSERT((continuation_result != NULL) && continuation_result->is_captured());
ASSERT((continuation_error != NULL) && continuation_error->is_captured());
ASSERT((old_context != NULL) && old_context->is_captured());
// Before restoring the continuation context we need to temporary save the
// result and error parameter.
- LocalVariable* temp_result_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_result)));
- LocalVariable* temp_error_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_error)));
- LocalVariable* temp_stack_trace_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_stack_trace)));
- // Restore the saved continuation context.
+ LocalVariable* temp_result_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_result)));
+ LocalVariable* temp_error_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_error)));
+ LocalVariable* temp_stack_trace_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_stack_trace)));
+
+ // Restore the saved continuation context, i.e. the context that was
+ // saved into :await_ctx_var before the closure suspended.
BuildRestoreContext(*old_context);
- // Pass over the continuation result.
+ // Store the continuation result and continuation error values into
+ // the restored context.
// FlowGraphBuilder is at top context level, but the await target has possibly
// been recorded in a nested context (old_ctx_level). We need to unroll
// manually here.
- intptr_t delta = old_ctx_level -
- continuation_result->owner()->context_level();
+ intptr_t delta =
+ old_ctx_level - continuation_result->owner()->context_level();
ASSERT(delta >= 0);
Value* context = Bind(BuildCurrentContext());
while (delta-- > 0) {
@@ -3702,6 +3763,7 @@
// label: SourceLabel }
void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
LocalScope* scope = node->scope();
+ const Function& function = owner()->function();
const intptr_t num_context_variables =
(scope != NULL) ? scope->num_context_variables() : 0;
const bool is_top_level_sequence =
@@ -3734,7 +3796,6 @@
// the captured parameters from the frame into the context.
if (is_top_level_sequence) {
ASSERT(scope->context_level() == 1);
- const Function& function = owner()->function();
const int num_params = function.NumParameters();
int param_frame_index = (num_params == function.num_fixed_parameters()) ?
(kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp;
@@ -3772,7 +3833,6 @@
// This check may be deleted if the generated code is leaf.
// Native functions don't need a stack check at entry.
- const Function& function = owner()->function();
if (is_top_level_sequence && !function.is_native()) {
// Always allocate CheckOverflowInstr so that deopt-ids match regardless
// if we inline or not.
@@ -3789,7 +3849,6 @@
}
if (Isolate::Current()->TypeChecksEnabled() && is_top_level_sequence) {
- const Function& function = owner()->function();
const int num_params = function.NumParameters();
int pos = 0;
if (function.IsConstructor()) {
@@ -3818,10 +3877,12 @@
}
// Continuation part:
- // If this node sequence is the body of an async closure leave room for a
- // preamble. The preamble is generated after visiting the body.
+ // If this node sequence is the body of a function with continuations,
+ // leave room for a preamble.
+ // The preamble is generated after visiting the body.
GotoInstr* preamble_start = NULL;
- if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+ if (is_top_level_sequence &&
+ (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
owner()->AllocateBlockId(), owner()->try_index());
ASSERT(exit() != NULL);
@@ -3844,33 +3905,28 @@
}
// Continuation part:
- // After generating the CFG for the body we can create the preamble because we
- // know exactly how many continuation states we need.
- if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+ // After generating the CFG for the body we can create the preamble
+ // because we know exactly how many continuation states we need.
+ if (is_top_level_sequence &&
+ (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
ASSERT(preamble_start != NULL);
// We are at the top level. Fetch the corresponding scope.
LocalScope* top_scope = node->scope();
LocalVariable* jump_var = top_scope->LookupVariable(
Symbols::AwaitJumpVar(), false);
ASSERT(jump_var != NULL && jump_var->is_captured());
-
Instruction* saved_entry = entry_;
Instruction* saved_exit = exit_;
entry_ = NULL;
exit_ = NULL;
- LoadLocalNode* load_jump_count = new(I) LoadLocalNode(
- Scanner::kNoSourcePos, jump_var);
+ LoadLocalNode* load_jump_count =
+ new(I) LoadLocalNode(Scanner::kNoSourcePos, jump_var);
ComparisonNode* check_jump_count;
const intptr_t num_await_states = owner()->await_joins()->length();
+
LocalVariable* old_context = top_scope->LookupVariable(
Symbols::AwaitContextVar(), false);
- LocalVariable* continuation_result = top_scope->LookupVariable(
- Symbols::AsyncOperationParam(), false);
- LocalVariable* continuation_error = top_scope->LookupVariable(
- Symbols::AsyncOperationErrorParam(), false);
- LocalVariable* continuation_stack_trace = top_scope->LookupVariable(
- Symbols::AsyncOperationStackTraceParam(), false);
for (intptr_t i = 0; i < num_await_states; i++) {
check_jump_count = new(I) ComparisonNode(
Scanner::kNoSourcePos,
@@ -3883,14 +3939,32 @@
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
- for_true.BuildAwaitJump(old_context,
- continuation_result,
- continuation_error,
- continuation_stack_trace,
- (*owner()->await_levels())[i],
- (*owner()->await_joins())[i]);
- Join(for_test, for_true, for_false);
+ if (function.IsAsyncClosure()) {
+ LocalVariable* result_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationParam(), false);
+ LocalVariable* error_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationErrorParam(),
+ false);
+ LocalVariable* stack_trace_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationStackTraceParam(),
+ false);
+ for_true.BuildAwaitJump(old_context,
+ result_param,
+ error_param,
+ stack_trace_param,
+ (*owner()->await_levels())[i],
+ (*owner()->await_joins())[i]);
+ } else {
+ ASSERT(function.IsSyncGenClosure());
+ LocalVariable* iterator_param =
+ top_scope->LookupVariable(Symbols::IteratorParameter(), false);
+ for_true.BuildYieldJump(old_context,
+ iterator_param,
+ (*owner()->await_levels())[i],
+ (*owner()->await_joins())[i]);
+ }
+ Join(for_test, for_true, for_false);
if (i == 0) {
// Manually link up the preamble start.
preamble_start->previous()->set_next(for_test.entry());
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index fa337d1..4168459 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -467,6 +467,11 @@
void BuildLetTempExpressions(LetNode* node);
+ void BuildYieldJump(LocalVariable* old_context,
+ LocalVariable* iterator_param,
+ const intptr_t old_ctx_level,
+ JoinEntryInstr* target);
+
void BuildAwaitJump(LocalVariable* old_context,
LocalVariable* continuation_result,
LocalVariable* continuation_error,
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 1649ab2..ddd24f3 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -61,8 +61,8 @@
#if defined(DEBUG)
// Pattern for unused new space and swept old space.
static const uint64_t kZap64Bits = 0xf3f3f3f3f3f3f3f3;
- static const uint32_t kZap32Bits = static_cast<uint32_t>(kZap64Bits);
- static const uint8_t kZapByte = static_cast<uint8_t>(kZap64Bits);
+ static const uint32_t kZap32Bits = 0xf3f3f3f3;
+ static const uint8_t kZapByte = 0xf3;
#endif // DEBUG
~Heap();
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index b525d7f..d4ae6a1 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -21,12 +21,10 @@
: open_objects_(0),
buffer_(buf_size),
reply_port_(ILLEGAL_PORT),
- command_(""),
- arguments_(NULL),
- num_arguments_(0),
- option_keys_(NULL),
- option_values_(NULL),
- num_options_(0) {
+ method_(""),
+ param_keys_(NULL),
+ param_values_(NULL),
+ num_params_(0) {
}
@@ -36,89 +34,35 @@
void JSONStream::Setup(Zone* zone,
Dart_Port reply_port,
- const GrowableObjectArray& path,
- const Array& option_keys,
- const Array& option_values) {
+ const String& method,
+ const Array& param_keys,
+ const Array& param_values) {
set_reply_port(reply_port);
+ method_ = method.ToCString();
- // Setup JSONStream arguments and options. The arguments and options
- // are zone allocated and will be freed immediately after handling the
- // message.
- const char** arguments = zone->Alloc<const char*>(path.Length());
String& string_iterator = String::Handle();
- for (intptr_t i = 0; i < path.Length(); i++) {
- string_iterator ^= path.At(i);
- arguments[i] = zone->MakeCopyOfString(string_iterator.ToCString());
- if (i == 0) {
- command_ = arguments[i];
- }
- }
- SetArguments(arguments, path.Length());
- if (option_keys.Length() > 0) {
- const char** option_keys_native =
- zone->Alloc<const char*>(option_keys.Length());
- const char** option_values_native =
- zone->Alloc<const char*>(option_keys.Length());
- for (intptr_t i = 0; i < option_keys.Length(); i++) {
- string_iterator ^= option_keys.At(i);
- option_keys_native[i] =
+ if (param_keys.Length() > 0) {
+ ASSERT(param_keys.Length() == param_values.Length());
+ const char** param_keys_native =
+ zone->Alloc<const char*>(param_keys.Length());
+ const char** param_values_native =
+ zone->Alloc<const char*>(param_keys.Length());
+ for (intptr_t i = 0; i < param_keys.Length(); i++) {
+ string_iterator ^= param_keys.At(i);
+ param_keys_native[i] =
zone->MakeCopyOfString(string_iterator.ToCString());
- string_iterator ^= option_values.At(i);
- option_values_native[i] =
+ string_iterator ^= param_values.At(i);
+ param_values_native[i] =
zone->MakeCopyOfString(string_iterator.ToCString());
}
- SetOptions(option_keys_native, option_values_native, option_keys.Length());
+ SetParams(param_keys_native, param_values_native, param_keys.Length());
}
if (FLAG_trace_service) {
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
const char* isolate_name = isolate->name();
- OS::Print("Isolate %s processing service request %s",
- isolate_name, command_);
- for (intptr_t i = 1; i < num_arguments(); i++) {
- OS::Print("/%s", GetArgument(i));
- }
- OS::Print("\n");
- setup_time_micros_ = OS::GetCurrentTimeMicros();
- }
-}
-
-
-void JSONStream::SetupNew(Zone* zone,
- Dart_Port reply_port,
- const String& method,
- const Array& option_keys,
- const Array& option_values) {
- set_reply_port(reply_port);
- command_ = method.ToCString();
-
- String& string_iterator = String::Handle();
- if (option_keys.Length() > 0) {
- ASSERT(option_keys.Length() == option_values.Length());
- const char** option_keys_native =
- zone->Alloc<const char*>(option_keys.Length());
- const char** option_values_native =
- zone->Alloc<const char*>(option_keys.Length());
- for (intptr_t i = 0; i < option_keys.Length(); i++) {
- string_iterator ^= option_keys.At(i);
- option_keys_native[i] =
- zone->MakeCopyOfString(string_iterator.ToCString());
- string_iterator ^= option_values.At(i);
- option_values_native[i] =
- zone->MakeCopyOfString(string_iterator.ToCString());
- }
- SetOptions(option_keys_native, option_values_native, option_keys.Length());
- }
- if (FLAG_trace_service) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- const char* isolate_name = isolate->name();
- OS::Print("Isolate %s processing service request %s",
- isolate_name, command_);
- for (intptr_t i = 1; i < num_arguments(); i++) {
- OS::Print("/%s", GetArgument(i));
- }
- OS::Print("\n");
+ OS::Print("Isolate %s processing service request %s\n",
+ isolate_name, method_);
setup_time_micros_ = OS::GetCurrentTimeMicros();
}
}
@@ -151,36 +95,32 @@
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
const char* isolate_name = isolate->name();
- OS::Print("Isolate %s processed service request %s",
- isolate_name, command_);
- for (intptr_t i = 1; i < num_arguments(); i++) {
- OS::Print("/%s", GetArgument(i));
- }
- OS::Print(" in %" Pd64" us.\n", process_delta_micros);
+ OS::Print("Isolate %s processed service request %s in %" Pd64" us.\n",
+ isolate_name, method_, process_delta_micros);
}
}
-const char* JSONStream::LookupOption(const char* key) const {
- for (int i = 0; i < num_options(); i++) {
- if (!strcmp(key, option_keys_[i])) {
- return option_values_[i];
+const char* JSONStream::LookupParam(const char* key) const {
+ for (int i = 0; i < num_params(); i++) {
+ if (!strcmp(key, param_keys_[i])) {
+ return param_values_[i];
}
}
return NULL;
}
-bool JSONStream::HasOption(const char* key) const {
+bool JSONStream::HasParam(const char* key) const {
ASSERT(key);
- return LookupOption(key) != NULL;
+ return LookupParam(key) != NULL;
}
-bool JSONStream::OptionIs(const char* key, const char* value) const {
+bool JSONStream::ParamIs(const char* key, const char* value) const {
ASSERT(key);
ASSERT(value);
- const char* key_value = LookupOption(key);
+ const char* key_value = LookupParam(key);
return (key_value != NULL) && (strcmp(key_value, value) == 0);
}
@@ -411,22 +351,12 @@
}
-void JSONStream::SetArguments(const char** arguments, intptr_t num_arguments) {
- if (num_arguments > 0) {
- // Set command.
- command_ = arguments[0];
- }
- arguments_ = arguments;
- num_arguments_ = num_arguments;
-}
-
-
-void JSONStream::SetOptions(const char** option_keys,
- const char** option_values,
- intptr_t num_options) {
- option_keys_ = option_keys;
- option_values_ = option_values;
- num_options_ = num_options;
+void JSONStream::SetParams(const char** param_keys,
+ const char** param_values,
+ intptr_t num_params) {
+ param_keys_ = param_keys;
+ param_values_ = param_values;
+ num_params_ = num_params;
}
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 56ecbcc..b15c3d5 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -31,15 +31,9 @@
void Setup(Zone* zone,
Dart_Port reply_port,
- const GrowableObjectArray& path,
- const Array& option_keys,
- const Array& option_values);
-
- void SetupNew(Zone* zone,
- Dart_Port reply_port,
- const String& method,
- const Array& param_keys,
- const Array& param_values);
+ const String& method,
+ const Array& param_keys,
+ const Array& param_values);
void PostReply();
@@ -47,40 +41,31 @@
const char* ToCString() { return buffer_.buf(); }
void set_reply_port(Dart_Port port);
- void SetArguments(const char** arguments, intptr_t num_arguments);
- void SetOptions(const char** option_keys, const char** option_values,
- intptr_t num_options);
+
+ void SetParams(const char** param_keys, const char** param_values,
+ intptr_t num_params);
Dart_Port reply_port() const { return reply_port_; }
- intptr_t num_arguments() const { return num_arguments_; }
- const char* GetArgument(intptr_t i) const {
- return arguments_[i];
+ intptr_t num_params() const { return num_params_; }
+ const char* GetParamKey(intptr_t i) const {
+ return param_keys_[i];
+ }
+ const char* GetParamValue(intptr_t i) const {
+ return param_values_[i];
}
- // TODO(turnidge): Rename "options" to "params". That is the more
- // appropriate name for json rpc.
- intptr_t num_options() const { return num_options_; }
- const char* GetOptionKey(intptr_t i) const {
- return option_keys_[i];
- }
- const char* GetOptionValue(intptr_t i) const {
- return option_values_[i];
- }
+ const char* LookupParam(const char* key) const;
- const char* LookupOption(const char* key) const;
+ bool HasParam(const char* key) const;
- bool HasOption(const char* key) const;
-
- // Returns true if there is an option with key and value, false
+ // Returns true if there is an param with key and value, false
// otherwise.
- bool OptionIs(const char* key, const char* value) const;
+ bool ParamIs(const char* key, const char* value) const;
- // TODO(turnidge): Rename "command" to "method". Better name for json rpc.
- const char* command() const { return command_; }
- const char** arguments() const { return arguments_; }
- const char** option_keys() const { return option_keys_; }
- const char** option_values() const { return option_values_; }
+ const char* method() const { return method_; }
+ const char** param_keys() const { return param_keys_; }
+ const char** param_values() const { return param_values_; }
private:
void Clear();
@@ -134,12 +119,10 @@
intptr_t open_objects_;
TextBuffer buffer_;
Dart_Port reply_port_;
- const char* command_;
- const char** arguments_;
- intptr_t num_arguments_;
- const char** option_keys_;
- const char** option_values_;
- intptr_t num_options_;
+ const char* method_;
+ const char** param_keys_;
+ const char** param_values_;
+ intptr_t num_params_;
int64_t setup_time_micros_;
friend class JSONObject;
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index cf65040..b7c25da 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -390,25 +390,19 @@
}
-TEST_CASE(JSON_JSONStream_Options) {
- const char* arguments[] = {"a", "b", "c"};
- const char* option_keys[] = {"dog", "cat"};
- const char* option_values[] = {"apple", "banana"};
+TEST_CASE(JSON_JSONStream_Params) {
+ const char* param_keys[] = {"dog", "cat"};
+ const char* param_values[] = {"apple", "banana"};
JSONStream js;
- EXPECT(js.num_arguments() == 0);
- js.SetArguments(&arguments[0], 3);
- EXPECT(js.num_arguments() == 3);
- EXPECT_STREQ("a", js.command());
-
- EXPECT(js.num_options() == 0);
- js.SetOptions(&option_keys[0], &option_values[0], 2);
- EXPECT(js.num_options() == 2);
- EXPECT(!js.HasOption("lizard"));
- EXPECT(js.HasOption("dog"));
- EXPECT(js.HasOption("cat"));
- EXPECT(js.OptionIs("cat", "banana"));
- EXPECT(!js.OptionIs("dog", "banana"));
+ EXPECT(js.num_params() == 0);
+ js.SetParams(¶m_keys[0], ¶m_values[0], 2);
+ EXPECT(js.num_params() == 2);
+ EXPECT(!js.HasParam("lizard"));
+ EXPECT(js.HasParam("dog"));
+ EXPECT(js.HasParam("cat"));
+ EXPECT(js.ParamIs("cat", "banana"));
+ EXPECT(!js.ParamIs("dog", "banana"));
}
} // namespace dart
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8bb0a39..e774599 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5584,7 +5584,7 @@
bool Function::CanBeInlined() const {
return is_inlinable() &&
- !is_async_closure() &&
+ !is_generated_body() &&
HasCode() &&
!Isolate::Current()->debugger()->HasBreakpoint(*this);
}
@@ -6111,7 +6111,7 @@
result.set_is_debuggable(true); // Will be computed later.
result.set_is_intrinsic(false);
result.set_is_redirecting(false);
- result.set_is_async_closure(false);
+ result.set_is_generated_body(false);
result.set_always_inline(false);
result.set_is_polymorphic_target(false);
result.set_owner(owner);
@@ -12788,7 +12788,23 @@
const char* ContextScope::ToCString() const {
- return "ContextScope";
+ const char* format =
+ "%s\nvar %s token-pos %" Pd " ctx lvl %" Pd " index %" Pd "";
+ const char* prev_cstr = "ContextScope:";
+ String& name = String::Handle();
+ for (int i = 0; i < num_variables(); i++) {
+ name = NameAt(i);
+ const char* cname = name.ToCString();
+ intptr_t pos = TokenIndexAt(i);
+ intptr_t idx = ContextIndexAt(i);
+ intptr_t lvl = ContextLevelAt(i);
+ intptr_t len =
+ OS::SNPrint(NULL, 0, format, prev_cstr, cname, pos, lvl, idx) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, format, prev_cstr, cname, pos, lvl, idx);
+ prev_cstr = chars;
+ }
+ return prev_cstr;
}
@@ -13194,7 +13210,7 @@
RawUnhandledException* UnhandledException::New(const Instance& exception,
- const Instance& stacktrace,
+ const Stacktrace& stacktrace,
Heap::Space space) {
ASSERT(Object::unhandled_exception_class() != Class::null());
UnhandledException& result = UnhandledException::Handle();
@@ -13222,7 +13238,7 @@
result ^= raw;
}
result.set_exception(Object::null_instance());
- result.set_stacktrace(Object::null_instance());
+ result.set_stacktrace(Stacktrace::Handle());
return result.raw();
}
@@ -13232,7 +13248,7 @@
}
-void UnhandledException::set_stacktrace(const Instance& stacktrace) const {
+void UnhandledException::set_stacktrace(const Stacktrace& stacktrace) const {
StorePointer(&raw_ptr()->stacktrace_, stacktrace.raw());
}
@@ -20099,6 +20115,7 @@
intptr_t frame_index) {
const char* kFormatWithCol = "#%-6d %s (%s:%d:%d)\n";
const char* kFormatNoCol = "#%-6d %s (%s:%d)\n";
+ const char* kFormatNoLine = "#%-6d %s (%s)\n";
const intptr_t token_pos = code.GetTokenIndexOfPC(pc);
const Script& script = Script::Handle(isolate, function.script());
const String& function_name =
@@ -20106,7 +20123,7 @@
const String& url = String::Handle(isolate, script.url());
intptr_t line = -1;
intptr_t column = -1;
- if (token_pos >= 0) {
+ if (token_pos > 0) {
if (script.HasSource()) {
script.GetTokenLocation(token_pos, &line, &column);
} else {
@@ -20124,7 +20141,7 @@
frame_index,
function_name.ToCString(),
url.ToCString(), line, column);
- } else {
+ } else if (line >= 0) {
len = OS::SNPrint(NULL, 0, kFormatNoCol,
frame_index, function_name.ToCString(),
url.ToCString(), line);
@@ -20132,6 +20149,14 @@
OS::SNPrint(chars, (len + 1), kFormatNoCol,
frame_index, function_name.ToCString(),
url.ToCString(), line);
+ } else {
+ len = OS::SNPrint(NULL, 0, kFormatNoLine,
+ frame_index, function_name.ToCString(),
+ url.ToCString());
+ chars = isolate->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(chars, (len + 1), kFormatNoLine,
+ frame_index, function_name.ToCString(),
+ url.ToCString());
}
frame_strings->Add(chars);
return len;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c57f824..47d6afd 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2152,6 +2152,28 @@
return modifier() == RawFunction::kAsync;
}
+ bool IsAsyncClosure() const {
+ return is_generated_body() &&
+ Function::Handle(parent_function()).IsAsyncFunction();
+ }
+
+ bool IsGenerator() const {
+ return (modifier() & RawFunction::kGeneratorBit) != 0;
+ }
+
+ bool IsSyncGenerator() const {
+ return modifier() == RawFunction::kSyncGen;
+ }
+
+ bool IsSyncGenClosure() const {
+ return is_generated_body() &&
+ Function::Handle(parent_function()).IsSyncGenerator();
+ }
+
+ bool IsAsyncOrGenerator() const {
+ return modifier() != RawFunction::kNoModifier;
+ }
+
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawFunction));
}
@@ -2239,7 +2261,7 @@
V(External, is_external) \
V(AllowsHoistingCheckClass, allows_hoisting_check_class) \
V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization) \
- V(AsyncClosure, is_async_closure) \
+ V(GeneratedBody, is_generated_body) \
V(AlwaysInline, always_inline) \
V(PolymorphicTarget, is_polymorphic_target) \
@@ -2262,6 +2284,8 @@
kRecognizedTagPos = kKindTagPos + kKindTagSize,
kRecognizedTagSize = 8,
kModifierPos = kRecognizedTagPos + kRecognizedTagSize,
+ kModifierSize = 2,
+ kLastModifierBitPos = kModifierPos + (kModifierSize - 1),
// Single bit sized fields start here.
#define DECLARE_BIT(name, _) k##name##Bit,
FOR_EACH_FUNCTION_KIND_BIT(DECLARE_BIT)
@@ -2277,11 +2301,14 @@
class KindBits :
public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {}; // NOLINT
+
class RecognizedBits : public BitField<MethodRecognizer::Kind,
kRecognizedTagPos,
kRecognizedTagSize> {};
class ModifierBits :
- public BitField<RawFunction::AsyncModifier, kModifierPos, 1> {}; // NOLINT
+ public BitField<RawFunction::AsyncModifier,
+ kModifierPos,
+ kModifierSize> {}; // NOLINT
#define DEFINE_BIT(name, _) \
class name##Bit : public BitField<bool, k##name##Bit, 1> {};
@@ -4549,7 +4576,7 @@
return OFFSET_OF(RawUnhandledException, exception_);
}
- RawInstance* stacktrace() const { return raw_ptr()->stacktrace_; }
+ RawStacktrace* stacktrace() const { return raw_ptr()->stacktrace_; }
static intptr_t stacktrace_offset() {
return OFFSET_OF(RawUnhandledException, stacktrace_);
}
@@ -4559,7 +4586,7 @@
}
static RawUnhandledException* New(const Instance& exception,
- const Instance& stacktrace,
+ const Stacktrace& stacktrace,
Heap::Space space = Heap::kNew);
virtual const char* ToErrorCString() const;
@@ -4568,7 +4595,7 @@
static RawUnhandledException* New(Heap::Space space = Heap::kNew);
void set_exception(const Instance& exception) const;
- void set_stacktrace(const Instance& stacktrace) const;
+ void set_stacktrace(const Stacktrace& stacktrace) const;
FINAL_HEAP_OBJECT_IMPLEMENTATION(UnhandledException, Error);
friend class Class;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 59ba57a..45759d9 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -150,7 +150,8 @@
// Allocate pre-allocated unhandled exception object initialized with the
// pre-allocated OutOfMemoryError.
const UnhandledException& unhandled_exception = UnhandledException::Handle(
- UnhandledException::New(Instance::Cast(result), Object::null_instance()));
+ UnhandledException::New(Instance::Cast(result),
+ Stacktrace::Handle(isolate)));
set_preallocated_unhandled_exception(unhandled_exception);
const Array& code_array = Array::Handle(
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 17d5367..c9b3345 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -888,8 +888,14 @@
}
if (!HasReturnNode(node_sequence)) {
- // Add implicit return node.
- node_sequence->Add(new ReturnNode(func.end_token_pos()));
+ // Add implicit return node. The implicit return value of synchronous
+ // generator closures is false, to indicate that there are no more
+ // elements in the iterable. In other cases the implicit return value
+ // is null.
+ AstNode* return_value = func.IsSyncGenClosure()
+ ? new LiteralNode(func.end_token_pos(), Bool::False())
+ : new LiteralNode(func.end_token_pos(), Instance::ZoneHandle());
+ node_sequence->Add(new ReturnNode(func.end_token_pos(), return_value));
}
if (parsed_function->has_expression_temp_var()) {
node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
@@ -3060,38 +3066,19 @@
&Symbols::TypeArgumentsParameter(),
&Type::ZoneHandle(Z, Type::DynamicType()));
}
+ // Expect the parameter list unless this is a getter function, or the
+ // body closure of an async or generator getter function.
ASSERT((CurrentToken() == Token::kLPAREN) ||
func.IsGetterFunction() ||
- func.is_async_closure());
+ (func.is_generated_body() &&
+ Function::Handle(func.parent_function()).IsGetterFunction()));
const bool allow_explicit_default_values = true;
if (func.IsGetterFunction()) {
// Populate function scope with the formal parameters. Since in this case
// we are compiling a getter this will at most populate the receiver.
AddFormalParamsToScope(¶ms, current_block_->scope);
- } else if (func.is_async_closure()) {
- // Async closures have two optional parameters:
- // * A continuation result.
- // * A continuation error.
- //
- // If the error!=null we rethrow the error at the next await.
- const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
- ParamDesc result_param;
- result_param.name = &Symbols::AsyncOperationParam();
- result_param.default_value = &Object::null_instance();
- result_param.type = &dynamic_type;
- ParamDesc error_param;
- error_param.name = &Symbols::AsyncOperationErrorParam();
- error_param.default_value = &Object::null_instance();
- error_param.type = &dynamic_type;
- ParamDesc stack_trace_param;
- stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
- stack_trace_param.default_value = &Object::null_instance();
- stack_trace_param.type = &dynamic_type;
- params.parameters->Add(result_param);
- params.parameters->Add(error_param);
- params.parameters->Add(stack_trace_param);
- params.num_optional_parameters += 3;
- params.has_optional_positional_parameters = true;
+ } else if (func.IsAsyncClosure()) {
+ AddAsyncClosureParameters(¶ms);
SetupDefaultsForOptionalParams(¶ms, default_parameter_values);
AddFormalParamsToScope(¶ms, current_block_->scope);
ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
@@ -3099,10 +3086,23 @@
if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
// Parse and discard any formal parameters. They are accessed as
// context variables.
- ParamList parse_away;
+ ParamList discarded_params;
ParseFormalParameterList(allow_explicit_default_values,
false,
- &parse_away);
+ &discarded_params);
+ }
+ } else if (func.IsSyncGenClosure()) {
+ AddSyncGenClosureParameters(¶ms);
+ SetupDefaultsForOptionalParams(¶ms, default_parameter_values);
+ AddFormalParamsToScope(¶ms, current_block_->scope);
+ ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
+ if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
+ // Parse and discard any formal parameters. They are accessed as
+ // context variables.
+ ParamList discarded_params;
+ ParseFormalParameterList(allow_explicit_default_values,
+ false,
+ &discarded_params);
}
} else {
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
@@ -3144,24 +3144,38 @@
}
}
+ const intptr_t modifier_pos = TokenPos();
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
- func.set_modifier(func_modifier);
+ if (!func.is_generated_body()) {
+ // Don't add a modifier to the closure representing the body of
+ // the asynchronous function or generator.
+ func.set_modifier(func_modifier);
+ }
OpenBlock(); // Open a nested scope for the outermost function block.
- Function& async_closure = Function::ZoneHandle(Z);
- if (func.IsAsyncFunction() && !func.is_async_closure()) {
+ Function& generated_body_closure = Function::ZoneHandle(Z);
+ if (func.IsAsyncFunction()) {
+ ASSERT(!func.is_generated_body());
// The code of an async function is synthesized. Disable debugging.
func.set_is_debuggable(false);
- async_closure = OpenAsyncFunction(func.token_pos());
- } else if (func.is_async_closure()) {
+ generated_body_closure = OpenAsyncFunction(func.token_pos());
+ } else if (func.IsAsyncClosure()) {
// The closure containing the body of an async function is debuggable.
ASSERT(func.is_debuggable());
OpenAsyncClosure();
+ } else if (func.IsSyncGenerator()) {
+ // The code of a sync generator is synthesized. Disable debugging.
+ func.set_is_debuggable(false);
+ generated_body_closure = OpenSyncGeneratorFunction(func.token_pos());
+ } else if (func.IsSyncGenClosure()) {
+ // The closure containing the body of a sync generator is debuggable.
+ ASSERT(func.is_debuggable());
+ // Nothing special to do.
}
BoolScope allow_await(&this->await_is_keyword_,
- func.IsAsyncFunction() || func.is_async_closure());
+ func.IsAsyncOrGenerator() || func.is_generated_body());
intptr_t end_token_pos = 0;
if (CurrentToken() == Token::kLBRACE) {
ConsumeToken();
@@ -3175,6 +3189,10 @@
end_token_pos = TokenPos();
ExpectToken(Token::kRBRACE);
} else if (CurrentToken() == Token::kARROW) {
+ if (func.IsGenerator()) {
+ ReportError(modifier_pos,
+ "=> style function may not be sync* or async* generator");
+ }
ConsumeToken();
if (String::Handle(Z, func.name()).Equals(
Symbols::EqualOperator())) {
@@ -3221,11 +3239,16 @@
func.end_token_pos() == end_token_pos);
func.set_end_token_pos(end_token_pos);
SequenceNode* body = CloseBlock();
- if (func.IsAsyncFunction() && !func.is_async_closure()) {
- body = CloseAsyncFunction(async_closure, body);
- async_closure.set_end_token_pos(end_token_pos);
- } else if (func.is_async_closure()) {
+ if (func.IsAsyncFunction()) {
+ body = CloseAsyncFunction(generated_body_closure, body);
+ generated_body_closure.set_end_token_pos(end_token_pos);
+ } else if (func.IsAsyncClosure()) {
body = CloseAsyncClosure(body);
+ } else if (func.IsSyncGenerator()) {
+ body = CloseSyncGenFunction(generated_body_closure, body);
+ generated_body_closure.set_end_token_pos(end_token_pos);
+ } else if (func.IsSyncGenClosure()) {
+ body->scope()->RecursivelyCaptureAllVariables();
}
current_block_->statements->Add(body);
innermost_function_ = saved_innermost_function.raw();
@@ -3544,11 +3567,12 @@
method->name->ToCString());
}
+ const intptr_t modifier_pos = TokenPos();
RawFunction::AsyncModifier async_modifier = ParseFunctionModifier();
if ((method->IsFactoryOrConstructor() || method->IsSetter()) &&
- async_modifier != RawFunction::kNoModifier) {
- ReportError(method->name_pos,
- "%s '%s' may not be async",
+ (async_modifier != RawFunction::kNoModifier)) {
+ ReportError(modifier_pos,
+ "%s '%s' may not be async, async* or sync*",
(method->IsSetter()) ? "setter" : "constructor",
method->name->ToCString());
}
@@ -3583,6 +3607,11 @@
method_end_pos = TokenPos();
ExpectToken(Token::kRBRACE);
} else {
+ if ((async_modifier & RawFunction::kGeneratorBit) != 0) {
+ ReportError(modifier_pos,
+ "=> style function may not be sync* or async* generator");
+ }
+
ConsumeToken();
BoolScope allow_await(&this->await_is_keyword_,
async_modifier != RawFunction::kNoModifier);
@@ -3646,6 +3675,12 @@
}
}
+ if (method->has_abstract && (async_modifier != RawFunction::kNoModifier)) {
+ ReportError(modifier_pos,
+ "abstract function '%s' may not be async, async* or sync*",
+ method->name->ToCString());
+ }
+
RawFunction::Kind function_kind;
if (method->IsFactoryOrConstructor()) {
function_kind = RawFunction::kConstructor;
@@ -5195,7 +5230,22 @@
RawFunction::AsyncModifier Parser::ParseFunctionModifier() {
if (CurrentLiteral()->raw() == Symbols::Async().raw()) {
ConsumeToken();
- return RawFunction::kAsync;
+ if (CurrentToken() == Token::kMUL) {
+ ReportError("async* generator functions are not yet supported");
+ ConsumeToken();
+ return RawFunction::kAsyncGen;
+ } else {
+ return RawFunction::kAsync;
+ }
+ } else if ((CurrentLiteral()->raw() == Symbols::Sync().raw()) &&
+ (LookaheadToken(1) == Token::kMUL)) {
+ const bool enableSyncStar = true;
+ if (!enableSyncStar) {
+ ReportError("sync* generator functions are not yet supported");
+ }
+ ConsumeToken();
+ ConsumeToken();
+ return RawFunction::kSyncGen;
}
return RawFunction::kNoModifier;
}
@@ -5254,6 +5304,7 @@
const bool allow_explicit_default_values = true;
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
+ const intptr_t modifier_pos = TokenPos();
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
intptr_t function_end_pos = function_pos;
@@ -5266,6 +5317,10 @@
function_end_pos = TokenPos();
ExpectToken(Token::kRBRACE);
} else if (CurrentToken() == Token::kARROW) {
+ if ((func_modifier & RawFunction::kGeneratorBit) != 0) {
+ ReportError(modifier_pos,
+ "=> style function may not be sync* or async* generator");
+ }
ConsumeToken();
BoolScope allow_await(&this->await_is_keyword_,
func_modifier != RawFunction::kNoModifier);
@@ -5395,7 +5450,12 @@
field_name->ToCString());
}
+ const intptr_t modifier_pos = TokenPos();
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
+ if (!is_getter && (func_modifier != RawFunction::kNoModifier)) {
+ ReportError(modifier_pos,
+ "setter function cannot be async, async* or sync*");
+ }
intptr_t accessor_end_pos = accessor_pos;
bool is_native = false;
@@ -5915,7 +5975,7 @@
}
ASSERT(try_blocks_list_ != NULL);
- if (innermost_function().is_async_closure() ||
+ if (innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) {
if ((try_blocks_list_->outer_try_block() != NULL) &&
(try_blocks_list_->outer_try_block()->try_block()
@@ -5945,7 +6005,7 @@
completer_args->Add(
new (Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
current_block_->statements->Add(new (Z) InstanceCallNode(
- Scanner::kNoSourcePos,
+ TokenPos(),
new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_completer),
Symbols::CompleterCompleteError(),
completer_args));
@@ -6020,15 +6080,175 @@
OpenBlock();
PushTryBlock(current_block_);
- if (innermost_function().is_async_closure() ||
+ if (innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) {
SetupSavedTryContext(context_var);
}
}
+void Parser::AddSyncGenClosureParameters(ParamList* params) {
+ // Create the parameter list for the body closure of a sync generator:
+ // 1) Implicit closure parameter;
+ // 2) Iterator
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+ // Add implicit closure parameter if not already present.
+ if (params->parameters->length() == 0) {
+ params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type);
+ }
+ ParamDesc iterator_param;
+ iterator_param.name = &Symbols::IteratorParameter();
+ iterator_param.type = &dynamic_type;
+ params->parameters->Add(iterator_param);
+ params->num_fixed_parameters++;
+}
+
+
+RawFunction* Parser::OpenSyncGeneratorFunction(intptr_t func_pos) {
+ Function& body = Function::Handle(Z);
+ String& body_closure_name = String::Handle(Z);
+ bool is_new_closure = false;
+
+ AddContinuationVariables();
+
+ // Check whether a function for the body of this generator
+ // function has already been created by a previous
+ // compilation.
+ const Function& found_func = Function::Handle(
+ Z, current_class().LookupClosureFunction(func_pos));
+ if (!found_func.IsNull() &&
+ (found_func.token_pos() == func_pos) &&
+ (found_func.script() == innermost_function().script()) &&
+ (found_func.parent_function() == innermost_function().raw())) {
+ ASSERT(found_func.IsSyncGenClosure());
+ body = found_func.raw();
+ body_closure_name = body.name();
+ } else {
+ // Create the closure containing the body of this generator function.
+ String& generator_name = String::Handle(Z, innermost_function().name());
+ body_closure_name =
+ String::NewFormatted("<%s_sync_body>", generator_name.ToCString());
+ body_closure_name = Symbols::New(body_closure_name);
+ body = Function::NewClosureFunction(body_closure_name,
+ innermost_function(),
+ func_pos);
+ body.set_is_generated_body(true);
+ body.set_result_type(AbstractType::Handle(Type::DynamicType()));
+ is_new_closure = true;
+ }
+
+ ParamList closure_params;
+ AddSyncGenClosureParameters(&closure_params);
+
+ if (is_new_closure) {
+ // Add the parameters to the newly created closure.
+ AddFormalParamsToFunction(&closure_params, body);
+
+ // Create and set the signature class of the closure.
+ const String& sig = String::Handle(Z, body.Signature());
+ Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
+ if (sig_cls.IsNull()) {
+ sig_cls = Class::NewSignatureClass(sig, body, script_, body.token_pos());
+ library_.AddClass(sig_cls);
+ }
+ body.set_signature_class(sig_cls);
+ const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
+ if (!sig_type.IsFinalized()) {
+ ClassFinalizer::FinalizeType(
+ sig_cls, sig_type, ClassFinalizer::kCanonicalize);
+ }
+ ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved());
+ ASSERT(body.NumParameters() == closure_params.parameters->length());
+ }
+
+ OpenFunctionBlock(body);
+ AddFormalParamsToScope(&closure_params, current_block_->scope);
+ OpenBlock();
+
+ /*
+ async_temp_scope_ = current_block_->scope; // Is this needed?
+ */
+ return body.raw();
+}
+
+SequenceNode* Parser::CloseSyncGenFunction(const Function& closure,
+ SequenceNode* closure_body) {
+ // The block for the closure body has already been closed. Close the
+ // corresponding function block.
+ CloseBlock();
+
+ closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
+ closure_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false);
+
+ // :await_jump_var = -1;
+ LocalVariable* jump_var =
+ current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
+ LiteralNode* init_value =
+ new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+ current_block_->statements->Add(
+ new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+
+ // return new SyncIterable(body_closure);
+ const Class& iterable_class =
+ Class::Handle(Z, Library::LookupCoreClass(Symbols::_SyncIterable()));
+ ASSERT(!iterable_class.IsNull());
+ const Function& iterable_constructor = Function::ZoneHandle(Z,
+ iterable_class.LookupConstructorAllowPrivate(
+ Symbols::_SyncIterableConstructor()));
+ ASSERT(!iterable_constructor.IsNull());
+
+ const String& closure_name = String::Handle(Z, closure.name());
+ ASSERT(closure_name.IsSymbol());
+
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ ClosureNode* closure_obj = new(Z) ClosureNode(
+ Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+ arguments->Add(closure_obj);
+ ConstructorCallNode* new_iterable =
+ new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+ TypeArguments::ZoneHandle(Z),
+ iterable_constructor,
+ arguments);
+ ReturnNode* return_node =
+ new (Z) ReturnNode(Scanner::kNoSourcePos, new_iterable);
+ current_block_->statements->Add(return_node);
+ return CloseBlock();
+}
+
+
+void Parser::AddAsyncClosureParameters(ParamList* params) {
+ // Async closures have two optional parameters:
+ // * A continuation result.
+ // * A continuation error.
+ // * A continuation stack trace.
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+ // Add implicit closure parameter if not yet present.
+ if (params->parameters->length() == 0) {
+ params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type);
+ }
+ ParamDesc result_param;
+ result_param.name = &Symbols::AsyncOperationParam();
+ result_param.default_value = &Object::null_instance();
+ result_param.type = &dynamic_type;
+ params->parameters->Add(result_param);
+ ParamDesc error_param;
+ error_param.name = &Symbols::AsyncOperationErrorParam();
+ error_param.default_value = &Object::null_instance();
+ error_param.type = &dynamic_type;
+ params->parameters->Add(error_param);
+ ParamDesc stack_trace_param;
+ stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
+ stack_trace_param.default_value = &Object::null_instance();
+ stack_trace_param.type = &dynamic_type;
+ params->parameters->Add(stack_trace_param);
+ params->has_optional_positional_parameters = true;
+ params->num_optional_parameters += 3;
+}
+
+
RawFunction* Parser::OpenAsyncFunction(intptr_t async_func_pos) {
TRACE_PARSER("OpenAsyncFunction");
+ AddContinuationVariables();
AddAsyncClosureVariables();
Function& closure = Function::Handle(Z);
bool is_new_closure = false;
@@ -6042,7 +6262,7 @@
(found_func.token_pos() == async_func_pos) &&
(found_func.script() == innermost_function().script()) &&
(found_func.parent_function() == innermost_function().raw())) {
- ASSERT(found_func.is_async_closure());
+ ASSERT(found_func.IsAsyncClosure());
closure = found_func.raw();
} else {
// Create the closure containing the body of this async function.
@@ -6054,33 +6274,13 @@
String::Handle(Z, Symbols::New(closure_name)),
innermost_function(),
async_func_pos);
- closure.set_is_async_closure(true);
+ closure.set_is_generated_body(true);
closure.set_result_type(AbstractType::Handle(Type::DynamicType()));
is_new_closure = true;
}
// Create the parameter list for the async body closure.
ParamList closure_params;
- const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
- closure_params.AddFinalParameter(
- async_func_pos, &Symbols::ClosureParameter(), &dynamic_type);
- ParamDesc result_param;
- result_param.name = &Symbols::AsyncOperationParam();
- result_param.default_value = &Object::null_instance();
- result_param.type = &dynamic_type;
- closure_params.parameters->Add(result_param);
- ParamDesc error_param;
- error_param.name = &Symbols::AsyncOperationErrorParam();
- error_param.default_value = &Object::null_instance();
- error_param.type = &dynamic_type;
- closure_params.parameters->Add(error_param);
- ParamDesc stack_trace_param;
- stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam();
- stack_trace_param.default_value = &Object::null_instance();
- stack_trace_param.type = &dynamic_type;
- closure_params.parameters->Add(stack_trace_param);
- closure_params.has_optional_positional_parameters = true;
- closure_params.num_optional_parameters += 3;
-
+ AddAsyncClosureParameters(&closure_params);
if (is_new_closure) {
// Add the parameters to the newly created closure.
AddFormalParamsToFunction(&closure_params, closure);
@@ -6110,12 +6310,10 @@
}
-void Parser::AddAsyncClosureVariables() {
- // Add to AST:
+void Parser::AddContinuationVariables() {
+ // Add to current block's scope:
// var :await_jump_var;
// var :await_ctx_var;
- // var :async_op;
- // var :async_completer;
const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
LocalVariable* await_jump_var = new (Z) LocalVariable(
Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type);
@@ -6127,12 +6325,20 @@
current_block_->scope->AddVariable(await_ctx_var);
current_block_->scope->CaptureVariable(Symbols::AwaitContextVar());
await_ctx_var->set_is_captured();
- LocalVariable* async_op_var = new (Z) LocalVariable(
+}
+
+
+void Parser::AddAsyncClosureVariables() {
+ // Add to current block's scope:
+ // var :async_op;
+ // var :async_completer;
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
+ LocalVariable* async_op_var = new(Z) LocalVariable(
Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
current_block_->scope->AddVariable(async_op_var);
current_block_->scope->CaptureVariable(Symbols::AsyncOperation());
async_op_var->set_is_captured();
- LocalVariable* async_completer = new (Z) LocalVariable(
+ LocalVariable* async_completer = new(Z) LocalVariable(
Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type);
current_block_->scope->AddVariable(async_completer);
current_block_->scope->CaptureVariable(Symbols::AsyncCompleter());
@@ -6214,12 +6420,12 @@
current_block_->statements->Add(store_completer);
// :await_jump_var = -1;
- LocalVariable* jump_var = current_block_->scope->LookupVariable(
- Symbols::AwaitJumpVar(), false);
+ LocalVariable* jump_var =
+ current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
LiteralNode* init_value =
- new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+ new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
current_block_->statements->Add(
- new (Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+ new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
// Add to AST:
// :async_op = <closure>; (containing the original body)
@@ -6234,7 +6440,7 @@
current_block_->statements->Add(store_async_op);
// Add to AST:
- // new Future(:async_op);
+ // new Future.microtask(:async_op);
ArgumentListNode* arguments = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
arguments->Add(new (Z) LoadLocalNode(
Scanner::kNoSourcePos, async_op_var));
@@ -6476,8 +6682,7 @@
"missing initialization of 'final' or 'const' variable");
} else {
// Initialize variable with null.
- AstNode* null_expr = new(Z) LiteralNode(
- ident_pos, Instance::ZoneHandle(Z));
+ AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z));
initialization = new(Z) StoreLocalNode(
ident_pos, variable, null_expr);
}
@@ -6907,7 +7112,11 @@
// Returns true if the current token is kIDENT or a pseudo-keyword.
bool Parser::IsIdentifier() {
- return Token::IsIdentifier(CurrentToken()) && !IsAwaitKeyword();
+ return Token::IsIdentifier(CurrentToken()) &&
+ !(await_is_keyword_ &&
+ ((CurrentLiteral()->raw() == Symbols::Await().raw()) ||
+ (CurrentLiteral()->raw() == Symbols::Async().raw()) ||
+ (CurrentLiteral()->raw() == Symbols::YieldKw().raw())));
}
@@ -7056,7 +7265,8 @@
(CurrentToken() == Token::kARROW) ||
(is_top_level_ && IsLiteral("native")) ||
is_external ||
- (CurrentLiteral()->raw() == Symbols::Async().raw())) {
+ (CurrentLiteral()->raw() == Symbols::Async().raw()) ||
+ (CurrentLiteral()->raw() == Symbols::Sync().raw())) {
SetPosition(saved_pos);
return true;
}
@@ -7546,6 +7756,12 @@
ConsumeToken(); // for.
ExpectToken(Token::kLPAREN);
+ if (!innermost_function().IsAsyncFunction() &&
+ !innermost_function().IsAsyncClosure()) {
+ ReportError(await_for_pos,
+ "await for loop is only allowed in async function");
+ }
+
// Parse loop variable.
bool loop_var_is_final = (CurrentToken() == Token::kFINAL);
if (CurrentToken() == Token::kCONST) {
@@ -7728,7 +7944,7 @@
// Generate initialization of iterator variable.
ArgumentListNode* no_args = new(Z) ArgumentListNode(collection_pos);
AstNode* get_iterator = new(Z) InstanceGetterNode(
- collection_pos, collection_expr, Symbols::GetIterator());
+ collection_pos, collection_expr, Symbols::Iterator());
AstNode* iterator_init =
new(Z) StoreLocalNode(collection_pos, iterator_var, get_iterator);
current_block_->statements->Add(iterator_init);
@@ -7979,7 +8195,7 @@
// In case of async closures we need to restore the saved try index of an
// outer try block (if it exists). The current try block has already been
// removed from the stack of try blocks.
- if ((innermost_function().is_async_closure() ||
+ if ((innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) &&
(try_blocks_list_ != NULL)) {
// We need two unchain two scopes: finally clause, and the try block level.
@@ -8139,7 +8355,7 @@
// In case of async closures we need to restore the saved try index of an
// outer try block (if it exists).
ASSERT(try_blocks_list_ != NULL);
- if (innermost_function().is_async_closure() ||
+ if (innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) {
if ((try_blocks_list_->outer_try_block() != NULL) &&
(try_blocks_list_->outer_try_block()->try_block()
@@ -8247,7 +8463,7 @@
// In case of async closures we need to restore the saved try index of an
// outer try block (if it exists).
ASSERT(try_blocks_list_ != NULL);
- if (innermost_function().is_async_closure() ||
+ if (innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) {
if ((try_blocks_list_->outer_try_block() != NULL) &&
(try_blocks_list_->outer_try_block()->try_block()
@@ -8285,15 +8501,17 @@
async_saved_try_ctx_name, false);
ASSERT(async_saved_try_ctx != NULL);
ASSERT(saved_try_context != NULL);
- current_block_->statements->Add(new (Z) StoreLocalNode(
- Scanner::kNoSourcePos, async_saved_try_ctx, new (Z) LoadLocalNode(
- Scanner::kNoSourcePos, saved_try_context)));
+ current_block_->statements->Add(new(Z) StoreLocalNode(
+ Scanner::kNoSourcePos,
+ async_saved_try_ctx,
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
parsed_function()->set_saved_try_ctx(saved_try_context);
parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
}
-// Set up the currently relevant :saved_try_context_var on the stack:
+// Restore the currently relevant :saved_try_context_var on the stack
+// from the captured :async_saved_try_cts_var.
// * Try blocks: Set the context variable for this try block.
// * Catch/finally blocks: Set the context variable for any outer try block (if
// existent).
@@ -8381,7 +8599,7 @@
PushTryBlock(current_block_);
ExpectToken(Token::kLBRACE);
- if (innermost_function().is_async_closure() ||
+ if (innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction()) {
SetupSavedTryContext(context_var);
}
@@ -8560,18 +8778,72 @@
const intptr_t return_pos = TokenPos();
ConsumeToken();
if (CurrentToken() != Token::kSEMICOLON) {
+ const intptr_t expr_pos = TokenPos();
if (current_function().IsConstructor() &&
(current_block_->scope->function_level() == 0)) {
- ReportError(return_pos,
- "return of a value not allowed in constructors");
+ ReportError(expr_pos,
+ "return of a value is not allowed in constructors");
+ } else if (current_function().IsGenerator()) {
+ ReportError(expr_pos, "generator functions may not return a value");
}
AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
statement = new(Z) ReturnNode(statement_pos, expr);
} else {
- statement = new(Z) ReturnNode(statement_pos);
+ if (current_function().IsSyncGenClosure() &&
+ (current_block_->scope->function_level() == 0)) {
+ // In a synchronous generator, return without an expression
+ // returns false, signaling that the iterator terminates and
+ // did not yield a value.
+ statement = new(Z) ReturnNode(statement_pos,
+ new(Z) LiteralNode(return_pos, Bool::False()));
+ } else {
+ statement = new(Z) ReturnNode(statement_pos);
+ }
}
AddNodeForFinallyInlining(statement);
ExpectSemicolon();
+ } else if (IsYieldKeyword()) {
+ bool is_yield_each = false;
+ ConsumeToken();
+ ASSERT(innermost_function().IsGenerator() ||
+ innermost_function().IsSyncGenClosure());
+ if (CurrentToken() == Token::kMUL) {
+ is_yield_each = true;
+ ConsumeToken();
+ }
+ AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
+ LocalVariable* iterator_param =
+ LookupLocalScope(Symbols::IteratorParameter());
+ ASSERT(iterator_param != NULL);
+ // Generate :iterator.current = expr;
+ AstNode* iterator =
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_param);
+ AstNode* store_current =
+ new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+ iterator,
+ String::ZoneHandle(Symbols::Current().raw()),
+ expr);
+ LetNode* yield = new(Z) LetNode(statement_pos);
+ yield->AddNode(store_current);
+ if (is_yield_each) {
+ // Generate :iterator.isYieldEach = true;
+ AstNode* set_is_yield_each =
+ new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+ iterator,
+ String::ZoneHandle(Symbols::IsYieldEach().raw()),
+ new(Z) LiteralNode(TokenPos(), Bool::True()));
+ yield->AddNode(set_is_yield_each);
+ }
+ AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode();
+ await_marker->set_scope(current_block_->scope);
+ yield->AddNode(await_marker);
+ // Return true to indicate that a value has been generated.
+ ReturnNode* return_true = new(Z) ReturnNode(statement_pos,
+ new(Z) LiteralNode(TokenPos(), Bool::True()));
+ return_true->set_return_type(ReturnNode::kContinuationTarget);
+ yield->AddNode(return_true);
+ statement = yield;
+ ExpectSemicolon();
} else if (token == Token::kIF) {
statement = ParseIfStatement(label_name);
} else if (token == Token::kASSERT) {
@@ -8757,6 +9029,12 @@
}
+bool Parser::IsYieldKeyword() {
+ return await_is_keyword_ &&
+ (CurrentLiteral()->raw() == Symbols::YieldKw().raw());
+}
+
+
static bool IsIncrementOperator(Token::Kind token) {
return token == Token::kINCR || token == Token::kDECR;
}
@@ -9414,9 +9692,13 @@
const intptr_t op_pos = TokenPos();
if (IsAwaitKeyword()) {
TRACE_PARSER("ParseAwaitExpr");
+ if (!innermost_function().IsAsyncFunction() &&
+ !innermost_function().IsAsyncClosure()) {
+ ReportError("await operator is only allowed in async function");
+ }
ConsumeToken();
parsed_function()->record_await();
- expr = new (Z) AwaitNode(TokenPos(), ParseUnaryExpr());
+ expr = new (Z) AwaitNode(op_pos, ParseUnaryExpr());
} else if (IsPrefixOperator(CurrentToken())) {
Token::Kind unary_op = CurrentToken();
if (unary_op == Token::kSUB) {
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 7af16e6..326906d 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -345,6 +345,7 @@
String* ExpectIdentifier(const char* msg);
bool IsLiteral(const char* literal);
bool IsAwaitKeyword();
+ bool IsYieldKeyword();
void SkipIf(Token::Kind);
void SkipBlock();
@@ -558,12 +559,18 @@
void OpenFunctionBlock(const Function& func);
void OpenAsyncClosure();
RawFunction* OpenAsyncFunction(intptr_t formal_param_pos);
+ RawFunction* OpenSyncGeneratorFunction(intptr_t func_pos);
+ SequenceNode* CloseSyncGenFunction(const Function& closure,
+ SequenceNode* closure_node);
+ void AddSyncGenClosureParameters(ParamList* params);
void OpenAsyncTryBlock();
SequenceNode* CloseBlock();
SequenceNode* CloseAsyncFunction(const Function& closure,
SequenceNode* closure_node);
SequenceNode* CloseAsyncClosure(SequenceNode* body);
SequenceNode* CloseAsyncTryBlock(SequenceNode* try_block);
+ void AddAsyncClosureParameters(ParamList* params);
+ void AddContinuationVariables();
void AddAsyncClosureVariables();
@@ -786,8 +793,9 @@
// global variables.
bool is_top_level_;
- // await_is_keyword_ is true if we are parsing an async function. In this
- // context async is not treated as identifier but as a keyword.
+ // await_is_keyword_ is true if we are parsing an async or generator
+ // function. In this context the identifiers await, async and yield
+ // are treated as keywords.
bool await_is_keyword_;
// The member currently being parsed during "top level" parsing.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 749ee45..5f13b40 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -521,6 +521,8 @@
void InitializeSmi(RawSmi* const* addr, RawSmi* value) {
// Can't use Contains, as array length is initialized through this method.
ASSERT(reinterpret_cast<uword>(addr) >= RawObject::ToAddr(this));
+ // This is an initializing store, so any previous content is OK.
+ VerifiedMemory::Accept(reinterpret_cast<uword>(addr), kWordSize);
VerifiedMemory::Write(const_cast<RawSmi**>(addr), value);
}
@@ -699,8 +701,12 @@
};
enum AsyncModifier {
- kNoModifier,
- kAsync,
+ kNoModifier = 0x0,
+ kAsyncBit = 0x1,
+ kGeneratorBit = 0x2,
+ kAsync = kAsyncBit,
+ kSyncGen = kGeneratorBit,
+ kAsyncGen = kAsyncBit | kGeneratorBit,
};
private:
@@ -1380,7 +1386,7 @@
return reinterpret_cast<RawObject**>(&ptr()->exception_);
}
RawInstance* exception_;
- RawInstance* stacktrace_;
+ RawStacktrace* stacktrace_;
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->stacktrace_);
}
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 25330c4..0361262 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -819,12 +819,11 @@
typedef bool (*IsolateMessageHandler)(Isolate* isolate, JSONStream* stream);
struct IsolateMessageHandlerEntry {
- const char* command;
+ const char* method;
IsolateMessageHandler handler;
};
-static IsolateMessageHandler FindIsolateMessageHandler(const char* command);
-static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command);
+static IsolateMessageHandler FindIsolateMessageHandler(const char* method);
// A handler for a root (vm-global) request.
@@ -836,32 +835,26 @@
typedef bool (*RootMessageHandler)(JSONStream* stream);
struct RootMessageHandlerEntry {
- const char* command;
+ const char* method;
RootMessageHandler handler;
};
-static RootMessageHandler FindRootMessageHandler(const char* command);
-static RootMessageHandler FindRootMessageHandlerNew(const char* command);
+static RootMessageHandler FindRootMessageHandler(const char* method);
-static void PrintArgumentsAndOptions(const JSONObject& obj, JSONStream* js) {
+static void PrintRequest(const JSONObject& obj, JSONStream* js) {
JSONObject jsobj(&obj, "request");
+ jsobj.AddProperty("method", js->method());
{
- JSONArray jsarr(&jsobj, "arguments");
- for (intptr_t i = 0; i < js->num_arguments(); i++) {
- jsarr.AddValue(js->GetArgument(i));
+ JSONArray jsarr(&jsobj, "param_keys");
+ for (intptr_t i = 0; i < js->num_params(); i++) {
+ jsarr.AddValue(js->GetParamKey(i));
}
}
{
- JSONArray jsarr(&jsobj, "option_keys");
- for (intptr_t i = 0; i < js->num_options(); i++) {
- jsarr.AddValue(js->GetOptionKey(i));
- }
- }
- {
- JSONArray jsarr(&jsobj, "option_values");
- for (intptr_t i = 0; i < js->num_options(); i++) {
- jsarr.AddValue(js->GetOptionValue(i));
+ JSONArray jsarr(&jsobj, "param_values");
+ for (intptr_t i = 0; i < js->num_params(); i++) {
+ jsarr.AddValue(js->GetParamValue(i));
}
}
}
@@ -885,7 +878,21 @@
JSONObject jsobj(js);
jsobj.AddProperty("type", "Error");
jsobj.AddProperty("message", buffer);
- PrintArgumentsAndOptions(jsobj, js);
+ PrintRequest(jsobj, js);
+}
+
+
+static void PrintMissingParamError(JSONStream* js,
+ const char* param) {
+ PrintError(js, "%s expects the '%s' parameter",
+ js->method(), param);
+}
+
+
+static void PrintInvalidParamError(JSONStream* js,
+ const char* param) {
+ PrintError(js, "%s: invalid '%s' parameter: %s",
+ js->method(), param, js->LookupParam(param));
}
@@ -910,13 +917,14 @@
jsobj.AddProperty("id", "");
jsobj.AddProperty("kind", kind);
jsobj.AddProperty("message", buffer);
- PrintArgumentsAndOptions(jsobj, js);
+ PrintRequest(jsobj, js);
}
-void Service::HandleIsolateMessageNew(Isolate* isolate, const Array& msg) {
+void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
ASSERT(isolate != NULL);
ASSERT(!msg.IsNull());
+ ASSERT(msg.Length() == 5);
{
StackZone zone(isolate);
@@ -941,11 +949,11 @@
}
IsolateMessageHandler handler =
- FindIsolateMessageHandlerNew(method.ToCString());
+ FindIsolateMessageHandler(method.ToCString());
{
JSONStream js;
- js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- method, param_keys, param_values);
+ js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+ method, param_keys, param_values);
if (handler == NULL) {
// Check for an embedder handler.
EmbedderServiceHandler* e_handler =
@@ -953,8 +961,8 @@
if (e_handler != NULL) {
EmbedderHandleMessage(e_handler, &js);
} else {
- if (FindRootMessageHandlerNew(method.ToCString()) != NULL) {
- PrintError(&js, "%s expects no 'isolate' parameter\n",
+ if (FindRootMessageHandler(method.ToCString()) != NULL) {
+ PrintError(&js, "%s does not expect the 'isolateId' parameter",
method.ToCString());
} else {
PrintError(&js, "Unrecognized method: %s", method.ToCString());
@@ -973,79 +981,6 @@
}
-void Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
- ASSERT(isolate != NULL);
- ASSERT(!msg.IsNull());
-
- {
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
-
- // Message is a list with five entries.
- ASSERT(msg.Length() == 5);
-
- Object& tmp = Object::Handle(isolate);
- tmp = msg.At(2);
- if (tmp.IsString()) {
- return Service::HandleIsolateMessageNew(isolate, msg);
- }
-
- Instance& reply_port = Instance::Handle(isolate);
- GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
- Array& option_keys = Array::Handle(isolate);
- Array& option_values = Array::Handle(isolate);
- reply_port ^= msg.At(1);
- path ^= msg.At(2);
- option_keys ^= msg.At(3);
- option_values ^= msg.At(4);
-
- ASSERT(!path.IsNull());
- ASSERT(!option_keys.IsNull());
- ASSERT(!option_values.IsNull());
- // Same number of option keys as values.
- ASSERT(option_keys.Length() == option_values.Length());
-
- if (!reply_port.IsSendPort()) {
- FATAL("SendPort expected.");
- }
-
- String& path_segment = String::Handle();
- if (path.Length() > 0) {
- path_segment ^= path.At(0);
- } else {
- path_segment ^= Symbols::Empty().raw();
- }
- ASSERT(!path_segment.IsNull());
- const char* path_segment_c = path_segment.ToCString();
-
- IsolateMessageHandler handler =
- FindIsolateMessageHandler(path_segment_c);
- {
- JSONStream js;
- js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- path, option_keys, option_values);
- if (handler == NULL) {
- // Check for an embedder handler.
- EmbedderServiceHandler* e_handler =
- FindIsolateEmbedderHandler(path_segment_c);
- if (e_handler != NULL) {
- EmbedderHandleMessage(e_handler, &js);
- } else {
- PrintError(&js, "Unrecognized path");
- }
- js.PostReply();
- } else {
- if (handler(isolate, &js)) {
- // Handler returns true if the reply is ready to be posted.
- // TODO(johnmccutchan): Support asynchronous replies.
- js.PostReply();
- }
- }
- }
- }
-}
-
-
static bool HandleIsolate(Isolate* isolate, JSONStream* js) {
isolate->PrintJSON(js, false);
return true;
@@ -1072,8 +1007,8 @@
static bool HandleCommonEcho(JSONObject* jsobj, JSONStream* js) {
jsobj->AddProperty("type", "_EchoResponse");
- if (js->HasOption("text")) {
- jsobj->AddProperty("text", js->LookupOption("text"));
+ if (js->HasParam("text")) {
+ jsobj->AddProperty("text", js->LookupParam("text"));
}
return true;
}
@@ -1098,7 +1033,7 @@
static bool HandleIsolateTriggerEchoEvent(Isolate* isolate, JSONStream* js) {
- Service::SendEchoEvent(isolate, js->LookupOption("text"));
+ Service::SendEchoEvent(isolate, js->LookupParam("text"));
JSONObject jsobj(js);
return HandleCommonEcho(&jsobj, js);
}
@@ -1110,26 +1045,6 @@
}
-// Print an error message if there is no ID argument.
-#define REQUIRE_COLLECTION_ID(collection) \
- if (js->num_arguments() == 1) { \
- PrintError(js, "Must specify collection object id: /%s/id", collection); \
- return true; \
- }
-
-
-#define CHECK_COLLECTION_ID_BOUNDS(collection, length, arg, id, js) \
- if (!GetIntegerId(arg, &id)) { \
- PrintError(js, "Must specify collection object id: %s/id", collection); \
- return true; \
- } \
- if ((id < 0) || (id >= length)) { \
- PrintError(js, "%s id (%" Pd ") must be in [0, %" Pd ").", collection, id, \
- length); \
- return true; \
- }
-
-
static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
if ((s == NULL) || (*s == '\0')) {
// Empty string.
@@ -1680,19 +1595,19 @@
static bool HandleIsolateGetInboundReferences(Isolate* isolate,
JSONStream* js) {
- const char* target_id = js->LookupOption("targetId");
+ const char* target_id = js->LookupParam("targetId");
if (target_id == NULL) {
- PrintError(js, "Missing 'targetId' option");
+ PrintMissingParamError(js, "targetId");
return true;
}
- const char* limit_cstr = js->LookupOption("limit");
+ const char* limit_cstr = js->LookupParam("limit");
if (target_id == NULL) {
- PrintError(js, "Missing 'limit' option");
+ PrintMissingParamError(js, "limit");
return true;
}
intptr_t limit;
- if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ if (!GetIntegerId(limit_cstr, &limit)) {
+ PrintInvalidParamError(js, "limit");
return true;
}
@@ -1706,18 +1621,15 @@
if (lookup_result == ObjectIdRing::kCollected) {
PrintErrorWithKind(
js, "InboundReferencesCollected",
- "attempt to find a retaining path for a collected object\n",
- js->num_arguments());
+ "attempt to find a retaining path for a collected object\n");
return true;
} else if (lookup_result == ObjectIdRing::kExpired) {
PrintErrorWithKind(
js, "InboundReferencesExpired",
- "attempt to find a retaining path for an expired object\n",
- js->num_arguments());
+ "attempt to find a retaining path for an expired object\n");
return true;
}
- PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
- target_id);
+ PrintInvalidParamError(js, "targetId");
return true;
}
return PrintInboundReferences(isolate, &obj, limit, js);
@@ -1781,19 +1693,19 @@
static bool HandleIsolateGetRetainingPath(Isolate* isolate,
JSONStream* js) {
- const char* target_id = js->LookupOption("targetId");
+ const char* target_id = js->LookupParam("targetId");
if (target_id == NULL) {
- PrintError(js, "Missing 'targetId' option");
+ PrintMissingParamError(js, "targetId");
return true;
}
- const char* limit_cstr = js->LookupOption("limit");
+ const char* limit_cstr = js->LookupParam("limit");
if (target_id == NULL) {
- PrintError(js, "Missing 'limit' option");
+ PrintMissingParamError(js, "limit");
return true;
}
intptr_t limit;
- if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ if (!GetIntegerId(limit_cstr, &limit)) {
+ PrintInvalidParamError(js, "limit");
return true;
}
@@ -1807,18 +1719,15 @@
if (lookup_result == ObjectIdRing::kCollected) {
PrintErrorWithKind(
js, "RetainingPathCollected",
- "attempt to find a retaining path for a collected object\n",
- js->num_arguments());
+ "attempt to find a retaining path for a collected object\n");
return true;
} else if (lookup_result == ObjectIdRing::kExpired) {
PrintErrorWithKind(
js, "RetainingPathExpired",
- "attempt to find a retaining path for an expired object\n",
- js->num_arguments());
+ "attempt to find a retaining path for an expired object\n");
return true;
}
- PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
- target_id);
+ PrintInvalidParamError(js, "targetId");
return true;
}
return PrintRetainingPath(isolate, &obj, limit, js);
@@ -1826,9 +1735,9 @@
static bool HandleIsolateGetRetainedSize(Isolate* isolate, JSONStream* js) {
- const char* target_id = js->LookupOption("targetId");
+ const char* target_id = js->LookupParam("targetId");
if (target_id == NULL) {
- PrintError(js, "Missing 'targetId' option");
+ PrintMissingParamError(js, "targetId");
return true;
}
ObjectIdRing::LookupResult lookup_result;
@@ -1838,18 +1747,15 @@
if (lookup_result == ObjectIdRing::kCollected) {
PrintErrorWithKind(
js, "RetainedCollected",
- "attempt to calculate size retained by a collected object\n",
- js->num_arguments());
+ "attempt to calculate size retained by a collected object\n");
return true;
} else if (lookup_result == ObjectIdRing::kExpired) {
PrintErrorWithKind(
js, "RetainedExpired",
- "attempt to calculate size retained by an expired object\n",
- js->num_arguments());
+ "attempt to calculate size retained by an expired object\n");
return true;
}
- PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
- target_id);
+ PrintInvalidParamError(js, "targetId");
return true;
}
if (obj.IsClass()) {
@@ -1868,43 +1774,22 @@
result.PrintJSON(js, true);
return true;
}
- PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
- "library, class, or instance", target_id);
- return true;
-}
-
-
-static bool HandleClassesClosures(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- intptr_t id;
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- if (!GetIntegerId(js->GetArgument(3), &id)) {
- PrintError(js, "Must specify collection object id: closures/id");
- return true;
- }
- Function& func = Function::Handle();
- func ^= cls.ClosureFunctionFromIndex(id);
- if (func.IsNull()) {
- PrintError(js, "Closure function %" Pd " not found", id);
- return true;
- }
- func.PrintJSON(js, false);
+ PrintError(js, "%s: Invalid 'targetId' parameter value: "
+ "id '%s' does not correspond to a "
+ "library, class, or instance", js->method(), target_id);
return true;
}
static bool HandleIsolateEval(Isolate* isolate, JSONStream* js) {
- const char* target_id = js->LookupOption("targetId");
+ const char* target_id = js->LookupParam("targetId");
if (target_id == NULL) {
- PrintError(js, "Missing 'targetId' option");
+ PrintMissingParamError(js, "targetId");
return true;
}
- const char* expr = js->LookupOption("expression");
+ const char* expr = js->LookupParam("expression");
if (expr == NULL) {
- PrintError(js, "Missing 'expression' option");
+ PrintMissingParamError(js, "expression");
return true;
}
const String& expr_str = String::Handle(isolate, String::New(expr));
@@ -1917,8 +1802,7 @@
} else if (lookup_result == ObjectIdRing::kExpired) {
PrintSentinel(js, "objects/expired", "<expired>");
} else {
- PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
- target_id);
+ PrintInvalidParamError(js, "targetId");
}
return true;
}
@@ -1950,173 +1834,9 @@
result.PrintJSON(js, true);
return true;
}
- PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
- "library, class, or instance", target_id);
- return true;
-}
-
-
-static bool HandleClassesDispatchers(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- intptr_t id;
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- if (!GetIntegerId(js->GetArgument(3), &id)) {
- PrintError(js, "Must specify collection object id: dispatchers/id");
- return true;
- }
- Function& func = Function::Handle();
- func ^= cls.InvocationDispatcherFunctionFromIndex(id);
- if (func.IsNull()) {
- PrintError(js, "Dispatcher %" Pd " not found", id);
- return true;
- }
- func.PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleFunctionSetSource(
- Isolate* isolate, const Class& cls, const Function& func, JSONStream* js) {
- if (js->LookupOption("source") == NULL) {
- PrintError(js, "set_source expects a 'source' option\n");
- return true;
- }
- const String& source =
- String::Handle(String::New(js->LookupOption("source")));
- const Object& result = Object::Handle(
- Parser::ParseFunctionFromSource(cls, source));
- if (result.IsError()) {
- Error::Cast(result).PrintJSON(js, false);
- return true;
- }
- if (!result.IsFunction()) {
- PrintError(js, "source did not compile to a function.\n");
- return true;
- }
-
- // Replace function.
- cls.RemoveFunction(func);
- cls.AddFunction(Function::Cast(result));
-
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "Success");
- jsobj.AddProperty("id", "");
- return true;
-}
-
-
-static bool HandleClassesFunctions(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- if (js->num_arguments() != 4 && js->num_arguments() != 5) {
- PrintError(js, "Command should have 4 or 5 arguments");
- return true;
- }
- const char* encoded_id = js->GetArgument(3);
- String& id = String::Handle(isolate, String::New(encoded_id));
- id = String::DecodeIRI(id);
- if (id.IsNull()) {
- PrintError(js, "Function id %s is malformed", encoded_id);
- return true;
- }
- Function& func = Function::Handle(cls.LookupFunction(id));
- if (func.IsNull()) {
- PrintError(js, "Function %s not found", encoded_id);
- return true;
- }
- if (js->num_arguments() == 4) {
- func.PrintJSON(js, false);
- return true;
- } else {
- const char* subcommand = js->GetArgument(4);
- if (strcmp(subcommand, "set_source") == 0) {
- return HandleFunctionSetSource(isolate, cls, func, js);
- } else {
- PrintError(js, "Invalid sub command %s", subcommand);
- return true;
- }
- }
- UNREACHABLE();
- return true;
-}
-
-
-static bool HandleClassesImplicitClosures(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- intptr_t id;
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- if (!GetIntegerId(js->GetArgument(3), &id)) {
- PrintError(js, "Must specify collection object id: implicit_closures/id");
- return true;
- }
- Function& func = Function::Handle();
- func ^= cls.ImplicitClosureFunctionFromIndex(id);
- if (func.IsNull()) {
- PrintError(js, "Implicit closure function %" Pd " not found", id);
- return true;
- }
- func.PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleClassesFields(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- intptr_t id;
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- if (!GetIntegerId(js->GetArgument(3), &id)) {
- PrintError(js, "Must specify collection object id: fields/id");
- return true;
- }
- Field& field = Field::Handle(cls.FieldFromIndex(id));
- if (field.IsNull()) {
- PrintError(js, "Field %" Pd " not found", id);
- return true;
- }
- field.PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleClassesTypes(Isolate* isolate, const Class& cls,
- JSONStream* js) {
- if (js->num_arguments() == 3) {
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "TypeList");
- JSONArray members(&jsobj, "members");
- const intptr_t num_types = cls.NumCanonicalTypes();
- Type& type = Type::Handle();
- for (intptr_t i = 0; i < num_types; i++) {
- type = cls.CanonicalTypeFromIndex(i);
- members.AddValue(type);
- }
- return true;
- }
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- ASSERT(js->num_arguments() == 4);
- intptr_t id;
- if (!GetIntegerId(js->GetArgument(3), &id)) {
- PrintError(js, "Must specify collection object id: types/id");
- return true;
- }
- Type& type = Type::Handle();
- type ^= cls.CanonicalTypeFromIndex(id);
- if (type.IsNull()) {
- PrintError(js, "Canonical type %" Pd " not found", id);
- return true;
- }
- type.PrintJSON(js, false);
+ PrintError(js, "%s: Invalid 'targetId' parameter value: "
+ "id '%s' does not correspond to a "
+ "library, class, or instance", js->method(), target_id);
return true;
}
@@ -2154,26 +1874,26 @@
static bool HandleIsolateGetInstances(Isolate* isolate, JSONStream* js) {
- const char* target_id = js->LookupOption("classId");
+ const char* target_id = js->LookupParam("classId");
if (target_id == NULL) {
- PrintError(js, "Missing 'classId' option");
+ PrintMissingParamError(js, "classId");
return true;
}
- const char* limit_cstr = js->LookupOption("limit");
+ const char* limit_cstr = js->LookupParam("limit");
if (target_id == NULL) {
- PrintError(js, "Missing 'limit' option");
+ PrintMissingParamError(js, "limit");
return true;
}
intptr_t limit;
- if (!GetIntegerId(js->LookupOption("limit"), &limit)) {
- PrintError(js, "Invalid 'limit' option: %s", limit_cstr);
+ if (!GetIntegerId(limit_cstr, &limit)) {
+ PrintInvalidParamError(js, "limit");
return true;
}
const Object& obj =
Object::Handle(LookupHeapObject(isolate, target_id, NULL));
if (obj.raw() == Object::sentinel().raw() ||
!obj.IsClass()) {
- PrintError(js, "Invalid 'classId' value: no class with id '%s'", target_id);
+ PrintInvalidParamError(js, "classId");
return true;
}
const Class& cls = Class::Cast(obj);
@@ -2199,60 +1919,15 @@
}
-static bool HandleClasses(Isolate* isolate, JSONStream* js) {
- if (js->num_arguments() == 1) {
- PrintError(js, "Invalid number of arguments.");
- return true;
- }
- ASSERT(js->num_arguments() >= 2);
- intptr_t id;
- if (!GetIntegerId(js->GetArgument(1), &id)) {
- PrintError(js, "Must specify collection object id: /classes/id");
- return true;
- }
- ClassTable* table = isolate->class_table();
- if (!table->IsValidIndex(id)) {
- PrintError(js, "%" Pd " is not a valid class id.", id);
- return true;
- }
- Class& cls = Class::Handle(table->At(id));
- if (js->num_arguments() == 2) {
- cls.PrintJSON(js, false);
- return true;
- } else if (js->num_arguments() >= 3) {
- const char* second = js->GetArgument(2);
- if (strcmp(second, "closures") == 0) {
- return HandleClassesClosures(isolate, cls, js);
- } else if (strcmp(second, "fields") == 0) {
- return HandleClassesFields(isolate, cls, js);
- } else if (strcmp(second, "functions") == 0) {
- return HandleClassesFunctions(isolate, cls, js);
- } else if (strcmp(second, "implicit_closures") == 0) {
- return HandleClassesImplicitClosures(isolate, cls, js);
- } else if (strcmp(second, "dispatchers") == 0) {
- return HandleClassesDispatchers(isolate, cls, js);
- } else if (strcmp(second, "types") == 0) {
- return HandleClassesTypes(isolate, cls, js);
- } else {
- PrintError(js, "Invalid sub collection %s", second);
- return true;
- }
- }
- UNREACHABLE();
- return true;
-}
-
-
static bool HandleIsolateGetCoverage(Isolate* isolate, JSONStream* js) {
- if (!js->HasOption("targetId")) {
+ if (!js->HasParam("targetId")) {
CodeCoverage::PrintJSON(isolate, js, NULL);
return true;
}
- const char* target_id = js->LookupOption("targetId");
+ const char* target_id = js->LookupParam("targetId");
Object& obj = Object::Handle(LookupHeapObject(isolate, target_id, NULL));
if (obj.raw() == Object::sentinel().raw()) {
- PrintError(js, "Invalid 'targetId' value: no object with id '%s'",
- target_id);
+ PrintInvalidParamError(js, "targetId");
return true;
}
if (obj.IsScript()) {
@@ -2275,27 +1950,28 @@
CodeCoverage::PrintJSON(isolate, js, &ff);
return true;
}
- PrintError(js, "Invalid 'targetId' value: id '%s' does not correspond to a "
- "script, library, class, or function", target_id);
+ PrintError(js, "%s: Invalid 'targetId' parameter value: "
+ "id '%s' does not correspond to a "
+ "script, library, class, or function", js->method(), target_id);
return true;
}
static bool HandleIsolateAddBreakpoint(Isolate* isolate, JSONStream* js) {
- if (!js->HasOption("line")) {
- PrintError(js, "Missing 'line' option");
+ if (!js->HasParam("line")) {
+ PrintMissingParamError(js, "line");
return true;
}
- const char* line_option = js->LookupOption("line");
+ const char* line_param = js->LookupParam("line");
intptr_t line = -1;
- if (!GetIntegerId(line_option, &line)) {
- PrintError(js, "Invalid 'line' value: %s is not an integer", line_option);
+ if (!GetIntegerId(line_param, &line)) {
+ PrintInvalidParamError(js, "line");
return true;
}
- const char* script_id = js->LookupOption("script");
+ const char* script_id = js->LookupParam("script");
Object& obj = Object::Handle(LookupHeapObject(isolate, script_id, NULL));
if (obj.raw() == Object::sentinel().raw() || !obj.IsScript()) {
- PrintError(js, "Invalid 'script' value: no script with id '%s'", script_id);
+ PrintInvalidParamError(js, "script");
return true;
}
const Script& script = Script::Cast(obj);
@@ -2303,7 +1979,7 @@
SourceBreakpoint* bpt =
isolate->debugger()->SetBreakpointAtLine(script_url, line);
if (bpt == NULL) {
- PrintError(js, "Unable to set breakpoint at line %s", line_option);
+ PrintError(js, "Unable to set breakpoint at line %s", line_param);
return true;
}
bpt->PrintJSON(js);
@@ -2312,16 +1988,15 @@
static bool HandleIsolateRemoveBreakpoint(Isolate* isolate, JSONStream* js) {
- if (!js->HasOption("breakpointId")) {
- PrintError(js, "Missing 'breakpointId' option");
+ if (!js->HasParam("breakpointId")) {
+ PrintMissingParamError(js, "breakpointId");
return true;
}
- const char* bpt_id = js->LookupOption("breakpointId");
+ const char* bpt_id = js->LookupParam("breakpointId");
SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
if (bpt == NULL) {
fprintf(stderr, "ERROR1");
- PrintError(js, "Invalid 'breakpointId' value: no breakpoint with id '%s'",
- bpt_id);
+ PrintInvalidParamError(js, "breakpointId");
return true;
}
isolate->debugger()->RemoveBreakpoint(bpt->id());
@@ -2335,75 +2010,6 @@
}
-static bool HandleLibrariesScripts(Isolate* isolate,
- const Library& lib,
- JSONStream* js) {
- if (js->num_arguments() > 5) {
- PrintError(js, "Command too long");
- return true;
- } else if (js->num_arguments() < 4) {
- PrintError(js, "Must specify collection object id: scripts/id");
- return true;
- }
- const String& id = String::Handle(String::New(js->GetArgument(3)));
- ASSERT(!id.IsNull());
- // The id is the url of the script % encoded, decode it.
- const String& requested_url = String::Handle(String::DecodeIRI(id));
- Script& script = Script::Handle();
- String& script_url = String::Handle();
- const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
- ASSERT(!loaded_scripts.IsNull());
- intptr_t i;
- for (i = 0; i < loaded_scripts.Length(); i++) {
- script ^= loaded_scripts.At(i);
- ASSERT(!script.IsNull());
- script_url ^= script.url();
- if (script_url.Equals(requested_url)) {
- break;
- }
- }
- if (i == loaded_scripts.Length()) {
- PrintError(js, "Script %s not found", requested_url.ToCString());
- return true;
- }
- if (js->num_arguments() > 4) {
- PrintError(js, "Command too long");
- return true;
- }
- script.PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleLibraries(Isolate* isolate, JSONStream* js) {
- // TODO(johnmccutchan): Support fields and functions on libraries.
- REQUIRE_COLLECTION_ID("libraries");
- const GrowableObjectArray& libs =
- GrowableObjectArray::Handle(isolate->object_store()->libraries());
- ASSERT(!libs.IsNull());
- intptr_t id = 0;
- CHECK_COLLECTION_ID_BOUNDS("libraries", libs.Length(), js->GetArgument(1),
- id, js);
- Library& lib = Library::Handle();
- lib ^= libs.At(id);
- ASSERT(!lib.IsNull());
- if (js->num_arguments() == 2) {
- lib.PrintJSON(js, false);
- return true;
- } else if (js->num_arguments() >= 3) {
- const char* second = js->GetArgument(2);
- if (strcmp(second, "scripts") == 0) {
- return HandleLibrariesScripts(isolate, lib, js);
- } else {
- PrintError(js, "Invalid sub collection %s", second);
- return true;
- }
- }
- UNREACHABLE();
- return true;
-}
-
-
static RawClass* GetMetricsClass(Isolate* isolate) {
const Library& prof_lib =
Library::Handle(isolate, Library::ProfilerLibrary());
@@ -2500,18 +2106,17 @@
static bool HandleIsolateGetMetricList(Isolate* isolate, JSONStream* js) {
bool native_metrics = false;
- if (js->HasOption("type")) {
- if (js->OptionIs("type", "Native")) {
+ if (js->HasParam("type")) {
+ if (js->ParamIs("type", "Native")) {
native_metrics = true;
- } else if (js->OptionIs("type", "Dart")) {
+ } else if (js->ParamIs("type", "Dart")) {
native_metrics = false;
} else {
- PrintError(js, "Invalid 'type' option value: %s\n",
- js->LookupOption("type"));
+ PrintInvalidParamError(js, "type");
return true;
}
} else {
- PrintError(js, "Expected 'type' option.");
+ PrintMissingParamError(js, "type");
return true;
}
if (native_metrics) {
@@ -2522,9 +2127,9 @@
static bool HandleIsolateGetMetric(Isolate* isolate, JSONStream* js) {
- const char* metric_id = js->LookupOption("metricId");
+ const char* metric_id = js->LookupParam("metricId");
if (metric_id == NULL) {
- PrintError(js, "Expected 'metricId' option.");
+ PrintMissingParamError(js, "metricId");
return true;
}
// Verify id begins with "metrics/".
@@ -2553,114 +2158,16 @@
static bool HandleVMGetMetric(JSONStream* js) {
- const char* metric_id = js->LookupOption("metricId");
+ const char* metric_id = js->LookupParam("metricId");
if (metric_id == NULL) {
- PrintError(js, "Expected 'metricId' option.");
+ PrintMissingParamError(js, "metricId");
}
return false;
}
-static bool HandleObjects(Isolate* isolate, JSONStream* js) {
- REQUIRE_COLLECTION_ID("objects");
- if (js->num_arguments() != 2) {
- PrintError(js, "expected at least 2 arguments but found %" Pd "\n",
- js->num_arguments());
- return true;
- }
- const char* arg = js->GetArgument(1);
-
- // Handle special non-objects first.
- if (strcmp(arg, "optimized-out") == 0) {
- if (js->num_arguments() > 2) {
- PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
- js->num_arguments());
- } else {
- Symbols::OptimizedOut().PrintJSON(js, false);
- }
- return true;
-
- } else if (strcmp(arg, "collected") == 0) {
- if (js->num_arguments() > 2) {
- PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
- js->num_arguments());
- } else {
- PrintSentinel(js, "objects/collected", "<collected>");
- }
- return true;
-
- } else if (strcmp(arg, "expired") == 0) {
- if (js->num_arguments() > 2) {
- PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
- js->num_arguments());
- } else {
- PrintSentinel(js, "objects/expired", "<expired>");
- }
- return true;
- }
-
- // Lookup the object.
- Object& obj = Object::Handle(isolate);
- ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
- obj = LookupObjectId(isolate, arg, &kind);
- if (kind == ObjectIdRing::kInvalid) {
- PrintError(js, "unrecognized object id '%s'", arg);
- return true;
- }
-
- // Print.
- if (kind == ObjectIdRing::kCollected) {
- // The object has been collected by the gc.
- PrintSentinel(js, "objects/collected", "<collected>");
- return true;
- } else if (kind == ObjectIdRing::kExpired) {
- // The object id has expired.
- PrintSentinel(js, "objects/expired", "<expired>");
- return true;
- }
- obj.PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleScriptsEnumerate(Isolate* isolate, JSONStream* js) {
- JSONObject jsobj(js);
- jsobj.AddProperty("type", "ScriptList");
- jsobj.AddProperty("id", "scripts");
- JSONArray members(&jsobj, "members");
- const GrowableObjectArray& libs =
- GrowableObjectArray::Handle(isolate->object_store()->libraries());
- intptr_t num_libs = libs.Length();
- Library &lib = Library::Handle();
- Script& script = Script::Handle();
- for (intptr_t i = 0; i < num_libs; i++) {
- lib ^= libs.At(i);
- ASSERT(!lib.IsNull());
- ASSERT(Smi::IsValid(lib.index()));
- const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
- ASSERT(!loaded_scripts.IsNull());
- intptr_t num_scripts = loaded_scripts.Length();
- for (intptr_t i = 0; i < num_scripts; i++) {
- script ^= loaded_scripts.At(i);
- members.AddValue(script);
- }
- }
- return true;
-}
-
-
-static bool HandleScripts(Isolate* isolate, JSONStream* js) {
- if (js->num_arguments() == 1) {
- // Enumerate all scripts.
- return HandleScriptsEnumerate(isolate, js);
- }
- PrintError(js, "Command too long");
- return true;
-}
-
-
static bool HandleIsolateResume(Isolate* isolate, JSONStream* js) {
- const char* step_option = js->LookupOption("step");
+ const char* step_param = js->LookupParam("step");
if (isolate->message_handler()->paused_on_start()) {
isolate->message_handler()->set_pause_on_start(false);
JSONObject jsobj(js);
@@ -2676,15 +2183,15 @@
return true;
}
if (isolate->debugger()->PauseEvent() != NULL) {
- if (step_option != NULL) {
- if (strcmp(step_option, "into") == 0) {
+ if (step_param != NULL) {
+ if (strcmp(step_param, "into") == 0) {
isolate->debugger()->SetSingleStep();
- } else if (strcmp(step_option, "over") == 0) {
+ } else if (strcmp(step_param, "over") == 0) {
isolate->debugger()->SetStepOver();
- } else if (strcmp(step_option, "out") == 0) {
+ } else if (strcmp(step_param, "out") == 0) {
isolate->debugger()->SetStepOut();
} else {
- PrintError(js, "Invalid 'step' option: %s", step_option);
+ PrintInvalidParamError(js, "step");
return true;
}
}
@@ -2719,69 +2226,6 @@
}
-static bool HandleNullCode(uintptr_t pc, JSONStream* js) {
- // TODO(turnidge): Consider adding/using Object::null_code() for
- // consistent "type".
- Object::null_object().PrintJSON(js, false);
- return true;
-}
-
-
-static bool HandleCode(Isolate* isolate, JSONStream* js) {
- REQUIRE_COLLECTION_ID("code");
- uword pc;
- if (js->num_arguments() > 2) {
- PrintError(js, "Command too long");
- return true;
- }
- ASSERT(js->num_arguments() == 2);
- static const char* kCollectedPrefix = "collected-";
- static intptr_t kCollectedPrefixLen = strlen(kCollectedPrefix);
- static const char* kNativePrefix = "native-";
- static intptr_t kNativePrefixLen = strlen(kNativePrefix);
- static const char* kReusedPrefix = "reused-";
- static intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
- const char* command = js->GetArgument(1);
- if (strncmp(kCollectedPrefix, command, kCollectedPrefixLen) == 0) {
- if (!GetUnsignedIntegerId(&command[kCollectedPrefixLen], &pc, 16)) {
- PrintError(js, "Must specify code address: code/%sc0deadd0.",
- kCollectedPrefix);
- return true;
- }
- return HandleNullCode(pc, js);
- }
- if (strncmp(kNativePrefix, command, kNativePrefixLen) == 0) {
- if (!GetUnsignedIntegerId(&command[kNativePrefixLen], &pc, 16)) {
- PrintError(js, "Must specify code address: code/%sc0deadd0.",
- kNativePrefix);
- return true;
- }
- // TODO(johnmccutchan): Support native Code.
- return HandleNullCode(pc, js);
- }
- if (strncmp(kReusedPrefix, command, kReusedPrefixLen) == 0) {
- if (!GetUnsignedIntegerId(&command[kReusedPrefixLen], &pc, 16)) {
- PrintError(js, "Must specify code address: code/%sc0deadd0.",
- kReusedPrefix);
- return true;
- }
- return HandleNullCode(pc, js);
- }
- int64_t timestamp = 0;
- if (!GetCodeId(command, ×tamp, &pc) || (timestamp < 0)) {
- PrintError(js, "Malformed code id: %s", command);
- return true;
- }
- Code& code = Code::Handle(Code::FindCode(pc, timestamp));
- if (!code.IsNull()) {
- code.PrintJSON(js, false);
- return true;
- }
- PrintError(js, "Could not find code with id: %s", command);
- return true;
-}
-
-
static bool HandleIsolateGetTagProfile(Isolate* isolate, JSONStream* js) {
JSONObject miniProfile(js);
miniProfile.AddProperty("type", "TagProfile");
@@ -2792,23 +2236,22 @@
static bool HandleIsolateGetCpuProfile(Isolate* isolate, JSONStream* js) {
// A full profile includes disassembly of all Dart code objects.
- // TODO(johnmccutchan): Add sub command to trigger full code dump.
+ // TODO(johnmccutchan): Add option to trigger full code dump.
bool full_profile = false;
- const char* tags_option = js->LookupOption("tags");
Profiler::TagOrder tag_order = Profiler::kUserVM;
- if (js->HasOption("tags")) {
- if (js->OptionIs("tags", "None")) {
+ if (js->HasParam("tags")) {
+ if (js->ParamIs("tags", "None")) {
tag_order = Profiler::kNoTags;
- } else if (js->OptionIs("tags", "UserVM")) {
+ } else if (js->ParamIs("tags", "UserVM")) {
tag_order = Profiler::kUserVM;
- } else if (js->OptionIs("tags", "UserOnly")) {
+ } else if (js->ParamIs("tags", "UserOnly")) {
tag_order = Profiler::kUser;
- } else if (js->OptionIs("tags", "VMUser")) {
+ } else if (js->ParamIs("tags", "VMUser")) {
tag_order = Profiler::kVMUser;
- } else if (js->OptionIs("tags", "VMOnly")) {
+ } else if (js->ParamIs("tags", "VMOnly")) {
tag_order = Profiler::kVM;
} else {
- PrintError(js, "Invalid tags option value: %s\n", tags_option);
+ PrintInvalidParamError(js, "tags");
return true;
}
}
@@ -2821,20 +2264,19 @@
JSONStream* js) {
bool should_reset_accumulator = false;
bool should_collect = false;
- if (js->HasOption("reset")) {
- if (js->OptionIs("reset", "true")) {
+ if (js->HasParam("reset")) {
+ if (js->ParamIs("reset", "true")) {
should_reset_accumulator = true;
} else {
- PrintError(js, "Unrecognized reset option '%s'",
- js->LookupOption("reset"));
+ PrintInvalidParamError(js, "reset");
return true;
}
}
- if (js->HasOption("gc")) {
- if (js->OptionIs("gc", "full")) {
+ if (js->HasParam("gc")) {
+ if (js->ParamIs("gc", "full")) {
should_collect = true;
} else {
- PrintError(js, "Unrecognized gc option '%s'", js->LookupOption("gc"));
+ PrintInvalidParamError(js, "gc");
return true;
}
}
@@ -2907,15 +2349,20 @@
};
-static bool HandleAddress(Isolate* isolate, JSONStream* js) {
- uword addr = 0;
- if (js->num_arguments() != 2 ||
- !GetUnsignedIntegerId(js->GetArgument(1), &addr, 16)) {
- static const uword kExampleAddr = static_cast<uword>(kIntptrMax / 7);
- PrintError(js, "Must specify address: address/" Px ".", kExampleAddr);
+static bool HandleIsolateGetObjectByAddress(Isolate* isolate, JSONStream* js) {
+ const char* addr_str = js->LookupParam("address");
+ if (addr_str == NULL) {
+ PrintMissingParamError(js, "address");
return true;
}
- bool ref = js->HasOption("ref") && js->OptionIs("ref", "true");
+
+ // Handle heap objects.
+ uword addr = 0;
+ if (!GetUnsignedIntegerId(addr_str, &addr, 16)) {
+ PrintInvalidParamError(js, "address");
+ return true;
+ }
+ bool ref = js->HasParam("ref") && js->ParamIs("ref", "true");
Object& object = Object::Handle(isolate);
{
NoGCScope no_gc;
@@ -2949,39 +2396,10 @@
}
-static IsolateMessageHandlerEntry isolate_handlers[] = {
- { "", HandleIsolate }, // getObject
- { "address", HandleAddress }, // to do
- { "classes", HandleClasses }, // getObject
- { "code", HandleCode }, // getObject
- { "libraries", HandleLibraries }, // getObject
- { "objects", HandleObjects }, // getObject
- { "scripts", HandleScripts }, // getObject
-};
-
-
-static IsolateMessageHandler FindIsolateMessageHandler(const char* command) {
- intptr_t num_message_handlers = sizeof(isolate_handlers) /
- sizeof(isolate_handlers[0]);
- for (intptr_t i = 0; i < num_message_handlers; i++) {
- const IsolateMessageHandlerEntry& entry = isolate_handlers[i];
- if (strcmp(command, entry.command) == 0) {
- return entry.handler;
- }
- }
- if (FLAG_trace_service) {
- OS::Print("vm-service: No isolate message handler for <%s>.\n", command);
- }
- return NULL;
-}
-
-
static bool HandleIsolateGetObject(Isolate* isolate, JSONStream* js) {
- const char* id = js->LookupOption("objectId");
+ const char* id = js->LookupParam("objectId");
if (id == NULL) {
- // TODO(turnidge): Print the isolate here instead.
- PrintError(js, "GetObject expects an 'objectId' parameter\n",
- js->num_arguments());
+ PrintMissingParamError(js, "objectId");
return true;
}
@@ -2995,8 +2413,10 @@
return true;
} else if (lookup_result == ObjectIdRing::kCollected) {
PrintSentinel(js, "objects/collected", "<collected>");
+ return true;
} else if (lookup_result == ObjectIdRing::kExpired) {
PrintSentinel(js, "objects/expired", "<expired>");
+ return true;
}
// Handle non-heap objects.
@@ -3022,7 +2442,7 @@
static bool HandleIsolateGetTypeArgumentsList(Isolate* isolate,
JSONStream* js) {
bool only_with_instantiations = false;
- if (js->OptionIs("onlyWithInstantiations", "true")) {
+ if (js->ParamIs("onlyWithInstantiations", "true")) {
only_with_instantiations = true;
}
ObjectStore* object_store = isolate->object_store();
@@ -3051,6 +2471,7 @@
static IsolateMessageHandlerEntry isolate_handlers_new[] = {
{ "getIsolate", HandleIsolate },
{ "getObject", HandleIsolateGetObject },
+ { "getObjectByAddress", HandleIsolateGetObjectByAddress },
{ "getBreakpoints", HandleIsolateGetBreakpoints },
{ "pause", HandleIsolatePause },
{ "resume", HandleIsolateResume },
@@ -3079,33 +2500,33 @@
};
-static IsolateMessageHandler FindIsolateMessageHandlerNew(const char* command) {
+static IsolateMessageHandler FindIsolateMessageHandler(const char* method) {
intptr_t num_message_handlers = sizeof(isolate_handlers_new) /
sizeof(isolate_handlers_new[0]);
for (intptr_t i = 0; i < num_message_handlers; i++) {
const IsolateMessageHandlerEntry& entry = isolate_handlers_new[i];
- if (strcmp(command, entry.command) == 0) {
+ if (strcmp(method, entry.method) == 0) {
return entry.handler;
}
}
if (FLAG_trace_service) {
- OS::Print("Service has no isolate message handler for <%s>\n", command);
+ OS::Print("Service has no isolate message handler for <%s>\n", method);
}
return NULL;
}
-void Service::HandleRootMessageNew(const Array& msg) {
+void Service::HandleRootMessage(const Instance& msg_instance) {
Isolate* isolate = Isolate::Current();
- ASSERT(!msg.IsNull());
+ ASSERT(!msg_instance.IsNull());
+ ASSERT(msg_instance.IsArray());
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
- const Array& message = Array::Cast(msg);
- // Message is a list with five entries.
- ASSERT(message.Length() == 5);
+ const Array& msg = Array::Cast(msg_instance);
+ ASSERT(msg.Length() == 5);
Instance& reply_port = Instance::Handle(isolate);
String& method = String::Handle(isolate);
@@ -3126,11 +2547,11 @@
}
RootMessageHandler handler =
- FindRootMessageHandlerNew(method.ToCString());
+ FindRootMessageHandler(method.ToCString());
{
JSONStream js;
- js.SetupNew(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- method, param_keys, param_values);
+ js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
+ method, param_keys, param_values);
if (handler == NULL) {
// Check for an embedder handler.
EmbedderServiceHandler* e_handler =
@@ -3138,9 +2559,8 @@
if (e_handler != NULL) {
EmbedderHandleMessage(e_handler, &js);
} else {
- if (FindIsolateMessageHandlerNew(method.ToCString()) != NULL) {
- PrintError(&js, "%s expects an 'isolate' parameter\n",
- method.ToCString());
+ if (FindIsolateMessageHandler(method.ToCString()) != NULL) {
+ PrintMissingParamError(&js, "isolateId");
} else {
PrintError(&js, "Unrecognized method: %s", method.ToCString());
}
@@ -3158,84 +2578,6 @@
}
-void Service::HandleRootMessage(const Instance& msg) {
- Isolate* isolate = Isolate::Current();
- ASSERT(!msg.IsNull());
- ASSERT(msg.IsArray());
-
- {
- StackZone zone(isolate);
- HANDLESCOPE(isolate);
-
- const Array& message = Array::Cast(msg);
- // Message is a list with five entries.
- ASSERT(message.Length() == 5);
-
- Object& tmp = Object::Handle(isolate);
- tmp = message.At(2);
- if (tmp.IsString()) {
- return Service::HandleRootMessageNew(message);
- }
-
- Instance& reply_port = Instance::Handle(isolate);
- GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
- Array& option_keys = Array::Handle(isolate);
- Array& option_values = Array::Handle(isolate);
-
- reply_port ^= message.At(1);
- path ^= message.At(2);
- option_keys ^= message.At(3);
- option_values ^= message.At(4);
-
- ASSERT(!path.IsNull());
- ASSERT(!option_keys.IsNull());
- ASSERT(!option_values.IsNull());
- // Path always has at least one entry in it.
- ASSERT(path.Length() > 0);
- // Same number of option keys as values.
- ASSERT(option_keys.Length() == option_values.Length());
-
- if (!reply_port.IsSendPort()) {
- FATAL("SendPort expected.");
- }
-
- String& path_segment = String::Handle();
- if (path.Length() > 0) {
- path_segment ^= path.At(0);
- } else {
- path_segment ^= Symbols::Empty().raw();
- }
- ASSERT(!path_segment.IsNull());
- const char* path_segment_c = path_segment.ToCString();
-
- RootMessageHandler handler =
- FindRootMessageHandler(path_segment_c);
- {
- JSONStream js;
- js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
- path, option_keys, option_values);
- if (handler == NULL) {
- // Check for an embedder handler.
- EmbedderServiceHandler* e_handler =
- FindRootEmbedderHandler(path_segment_c);
- if (e_handler != NULL) {
- EmbedderHandleMessage(e_handler, &js);
- } else {
- PrintError(&js, "Unrecognized path");
- }
- js.PostReply();
- } else {
- if (handler(&js)) {
- // Handler returns true if the reply is ready to be posted.
- // TODO(johnmccutchan): Support asynchronous replies.
- js.PostReply();
- }
- }
- }
- }
-}
-
-
static bool HandleRootEcho(JSONStream* js) {
JSONObject jsobj(js);
return HandleCommonEcho(&jsobj, js);
@@ -3293,83 +2635,59 @@
}
-static bool HandleFlags(JSONStream* js) {
- if (js->num_arguments() == 1) {
- Flags::PrintJSON(js);
- return true;
- } else if (js->num_arguments() == 2) {
- const char* arg = js->GetArgument(1);
- if (strcmp(arg, "set") == 0) {
- if (js->num_arguments() > 2) {
- PrintError(js, "expected at most 2 arguments but found %" Pd "\n",
- js->num_arguments());
- } else {
- if (js->HasOption("name") && js->HasOption("value")) {
- JSONObject jsobj(js);
- const char* flag_name = js->LookupOption("name");
- const char* flag_value = js->LookupOption("value");
- const char* error = NULL;
- if (Flags::SetFlag(flag_name, flag_value, &error)) {
- jsobj.AddProperty("type", "Success");
- jsobj.AddProperty("id", "");
- } else {
- jsobj.AddProperty("type", "Failure");
- jsobj.AddProperty("id", "");
- jsobj.AddProperty("message", error);
- }
- } else {
- PrintError(js, "expected to find 'name' and 'value' options");
- }
- }
- }
- return true;
- } else {
- PrintError(js, "Command too long");
- return true;
- }
+static bool HandleVMFlagList(JSONStream* js) {
+ Flags::PrintJSON(js);
+ return true;
}
-static RootMessageHandlerEntry root_handlers[] = {
- { "vm", HandleVM },
- { "flags", HandleFlags },
-};
-
-static RootMessageHandler FindRootMessageHandler(const char* command) {
- intptr_t num_message_handlers = sizeof(root_handlers) /
- sizeof(root_handlers[0]);
- for (intptr_t i = 0; i < num_message_handlers; i++) {
- const RootMessageHandlerEntry& entry = root_handlers[i];
- if (strcmp(command, entry.command) == 0) {
- return entry.handler;
- }
+static bool HandleVMSetFlag(JSONStream* js) {
+ const char* flag_name = js->LookupParam("name");
+ if (flag_name == NULL) {
+ PrintMissingParamError(js, "name");
+ return true;
}
- if (FLAG_trace_service) {
- OS::Print("vm-service: No root message handler for <%s>.\n", command);
+ const char* flag_value = js->LookupParam("value");
+ if (flag_value == NULL) {
+ PrintMissingParamError(js, "value");
+ return true;
}
- return NULL;
+ JSONObject jsobj(js);
+ const char* error = NULL;
+ if (Flags::SetFlag(flag_name, flag_value, &error)) {
+ jsobj.AddProperty("type", "Success");
+ jsobj.AddProperty("id", "");
+ return true;
+ } else {
+ jsobj.AddProperty("type", "Failure");
+ jsobj.AddProperty("id", "");
+ jsobj.AddProperty("message", error);
+ return true;
+ }
}
static RootMessageHandlerEntry root_handlers_new[] = {
{ "getVM", HandleVM },
+ { "getFlagList", HandleVMFlagList },
+ { "setFlag", HandleVMSetFlag },
{ "getVMMetricList", HandleVMGetMetricList },
{ "getVMMetric", HandleVMGetMetric },
{ "_echo", HandleRootEcho },
};
-static RootMessageHandler FindRootMessageHandlerNew(const char* command) {
+static RootMessageHandler FindRootMessageHandler(const char* method) {
intptr_t num_message_handlers = sizeof(root_handlers_new) /
sizeof(root_handlers_new[0]);
for (intptr_t i = 0; i < num_message_handlers; i++) {
const RootMessageHandlerEntry& entry = root_handlers_new[i];
- if (strcmp(command, entry.command) == 0) {
+ if (strcmp(method, entry.method) == 0) {
return entry.handler;
}
}
if (FLAG_trace_service) {
- OS::Print("vm-service: No root message handler for <%s>.\n", command);
+ OS::Print("vm-service: No root message handler for <%s>.\n", method);
}
return NULL;
}
@@ -3456,12 +2774,10 @@
Dart_ServiceRequestCallback callback = handler->callback();
ASSERT(callback != NULL);
const char* r = NULL;
- const char* name = js->command();
- const char** arguments = js->arguments();
- const char** keys = js->option_keys();
- const char** values = js->option_values();
- r = callback(name, arguments, js->num_arguments(), keys, values,
- js->num_options(), handler->user_data());
+ const char* name = js->method();
+ const char** keys = js->param_keys();
+ const char** values = js->param_values();
+ r = callback(name, keys, values, js->num_params(), handler->user_data());
ASSERT(r != NULL);
// TODO(johnmccutchan): Allow for NULL returns?
TextBuffer* buffer = js->buffer();
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 2816173..2af9b2d 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -29,11 +29,9 @@
static bool IsServiceIsolateName(const char* name);
// Handles a message which is not directed to an isolate.
- static void HandleRootMessageNew(const Array& message);
static void HandleRootMessage(const Instance& message);
// Handles a message which is directed to a particular isolate.
- static void HandleIsolateMessageNew(Isolate* isolate, const Array& message);
static void HandleIsolateMessage(Isolate* isolate, const Array& message);
static Isolate* GetServiceIsolate(void* callback_data);
diff --git a/runtime/vm/service/message.dart b/runtime/vm/service/message.dart
index 4b2f80a..011d57d 100644
--- a/runtime/vm/service/message.dart
+++ b/runtime/vm/service/message.dart
@@ -10,8 +10,6 @@
/// Future of response.
Future<String> get response => _completer.future;
- final bool isOld;
-
// In new messages.
final String method;
@@ -32,29 +30,10 @@
});
}
- Message.fromUri(Uri uri) : isOld = true {
- var split = uri.path.split('/');
- if (split.length == 0) {
- setErrorResponse('Invalid uri: $uri.');
- return;
- }
- _setPath(split);
- params.addAll(uri.queryParameters);
- }
-
- Message.fromJsonRpc(this.method, Map rpcParams)
- : isOld = false {
+ Message.fromJsonRpc(this.method, Map rpcParams) {
params.addAll(rpcParams);
}
- Message.fromMap(Map map) : isOld = true {
- _setPath(map['path']);
- // TODO - turnidge - change this to params in sender.
- if (map['options'] != null) {
- params.addAll(map['options']);
- }
- }
-
dynamic toJson() {
return {
'path': path,
@@ -94,7 +73,7 @@
var request = new List(5)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
- ..[2] = (isOld ? path : method)
+ ..[2] = method
..[3] = keys
..[4] = values;
sendIsolateServiceMessage(sendPort, request);
@@ -116,7 +95,7 @@
var request = new List(5)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
- ..[2] = (isOld ? path : method)
+ ..[2] = method
..[3] = keys
..[4] = values;
sendRootServiceMessage(request);
diff --git a/runtime/vm/service/running_isolates.dart b/runtime/vm/service/running_isolates.dart
index 124eb90..7766491 100644
--- a/runtime/vm/service/running_isolates.dart
+++ b/runtime/vm/service/running_isolates.dart
@@ -26,11 +26,7 @@
}
Future<String> route(Message message) {
- if (message.isOld) {
- return routeOld(message);
- }
-
- String isolateParam = message.params['isolate'];
+ String isolateParam = message.params['isolateId'];
int isolateId;
if (!isolateParam.startsWith('isolates/')) {
message.setErrorResponse('Malformed isolate id $isolateParam');
@@ -54,39 +50,4 @@
}
return isolate.route(message);
}
-
- Future<String> routeOld(Message message) {
- if (message.path.length == 0) {
- message.setErrorResponse('No path.');
- return message.response;
- }
- if (message.path[0] != 'isolates') {
- message.setErrorResponse('Path must begin with /isolates/');
- return message.response;
- }
- if (message.path.length < 2) {
- message.setErrorResponse('An isolate id must be provided');
- return message.response;
- }
- var isolateId;
- if ((message.path[1] == 'root') && (_rootPortId != null)) {
- isolateId = _rootPortId;
- } else {
- try {
- isolateId = int.parse(message.path[1]);
- } catch (e) {
- message.setErrorResponse('Could not parse isolate id: $e');
- return message.response;
- }
- }
- assert(isolateId != null);
- var isolate = isolates[isolateId];
- if (isolate == null) {
- message.setErrorResponse('Cannot find isolate id: $isolateId');
- return message.response;
- }
- // Consume '/isolates/isolateId'
- message.path.removeRange(0, 2);
- return isolate.route(message);
- }
}
diff --git a/runtime/vm/service/service.idl b/runtime/vm/service/service.idl
index e915378..0edb79b 100644
--- a/runtime/vm/service/service.idl
+++ b/runtime/vm/service/service.idl
@@ -3,6 +3,17 @@
//
interface Service {
+ getVM() VM
+
+ getFlagList() FlagList
+
+ setFlag(name string, value string) Response
+
+ getObject(isolateId string, objectId string) Object
+
+ // The response is a subtype of Object or ObjectRef.
+ getObjectByAddress(address string, ref bool) Response
+
// Returns the list of breakpoints for an isolate.
getBreakpoints(isolateId string) BreakpointList
@@ -127,6 +138,16 @@
}
+struct VM extends Response {
+ placeholder int
+}
+
+
+struct FlagList extends Response {
+ placeholder int
+}
+
+
struct _EchoResponse extends Response {
text string
}
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart
index 3c5ed24..d4eca93 100644
--- a/runtime/vm/service/vmservice.dart
+++ b/runtime/vm/service/vmservice.dart
@@ -138,18 +138,13 @@
if (message.completed) {
return message.response;
}
+ // TODO(turnidge): Update to json rpc. BEFORE SUBMIT.
if ((message.path.length == 1) && (message.path[0] == 'clients')) {
_clientCollection(message);
return message.response;
}
- if (message.isOld) {
- if (message.path[0] == 'isolates') {
- return runningIsolates.route(message);
- }
- } else {
- if (message.params['isolate'] != null) {
- return runningIsolates.route(message);
- }
+ if (message.params['isolateId'] != null) {
+ return runningIsolates.route(message);
}
return message.sendToVM();
}
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index ee6659a..17691b4 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -184,7 +184,7 @@
Array& service_msg = Array::Handle();
// Get the isolate summary.
- service_msg = Eval(lib, "[0, port, [], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getIsolate', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
@@ -248,7 +248,8 @@
Array& service_msg = Array::Handle();
// null
- service_msg = Eval(lib, "[0, port, ['objects', 'null'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/null']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
handler.filterMsg("_vmName");
@@ -257,59 +258,9 @@
"\"valueAsString\":\"null\",\"class\":",
handler.msg());
- // not initialized
- service_msg = Eval(lib, "[0, port, ['objects', 'not-initialized'], [], []]");
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- handler.filterMsg("_vmName");
- EXPECT_STREQ(
- "{\"type\":\"Sentinel\",\"id\":\"objects\\/not-initialized\","
- "\"valueAsString\":\"<not initialized>\"}",
- handler.msg());
-
- // being initialized
- service_msg = Eval(lib,
- "[0, port, ['objects', 'being-initialized'], [], []]");
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- handler.filterMsg("_vmName");
- EXPECT_STREQ(
- "{\"type\":\"Sentinel\",\"id\":\"objects\\/being-initialized\","
- "\"valueAsString\":\"<being initialized>\"}",
- handler.msg());
-
- // optimized out
- service_msg = Eval(lib, "[0, port, ['objects', 'optimized-out'], [], []]");
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- handler.filterMsg("_vmName");
- EXPECT_STREQ(
- "{\"type\":\"Sentinel\",\"id\":\"objects\\/optimized-out\","
- "\"valueAsString\":\"<optimized out>\"}",
- handler.msg());
-
- // collected
- service_msg = Eval(lib, "[0, port, ['objects', 'collected'], [], []]");
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- handler.filterMsg("_vmName");
- EXPECT_STREQ(
- "{\"type\":\"Sentinel\",\"id\":\"objects\\/collected\","
- "\"valueAsString\":\"<collected>\"}",
- handler.msg());
-
- // expired
- service_msg = Eval(lib, "[0, port, ['objects', 'expired'], [], []]");
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- handler.filterMsg("_vmName");
- EXPECT_STREQ(
- "{\"type\":\"Sentinel\",\"id\":\"objects\\/expired\","
- "\"valueAsString\":\"<expired>\"}",
- handler.msg());
-
// bool
- service_msg = Eval(lib, "[0, port, ['objects', 'bool-true'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/bool-true']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
handler.filterMsg("_vmName");
@@ -323,7 +274,8 @@
handler.msg());
// int
- service_msg = Eval(lib, "[0, port, ['objects', 'int-123'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/int-123']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
handler.filterMsg("_vmName");
@@ -337,7 +289,8 @@
handler.msg());
// object id ring / valid
- service_msg = Eval(lib, "[0, port, ['objects', '$validId'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/$validId']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
handler.filterMsg("_vmName");
@@ -356,7 +309,8 @@
handler.msg());
// object id ring / invalid => expired
- service_msg = Eval(lib, "[0, port, ['objects', '99999999'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/99999999']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
handler.filterMsg("_vmName");
@@ -541,9 +495,10 @@
Array& service_msg = Array::Handle();
// Request library.
- service_msg = EvalF(lib,
- "[0, port, ['libraries', '%" Pd "'], [], []]",
- vmlib.index());
+ service_msg =
+ EvalF(lib,
+ "[0, port, 'getObject', ['objectId'], ['libraries/%" Pd "']]",
+ vmlib.index());
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Library\"", handler.msg());
@@ -594,17 +549,15 @@
Array& service_msg = Array::Handle();
// Request an invalid class id.
- service_msg = Eval(lib, "[0, port, ['classes', '999999'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/999999']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
- "{\"type\":\"Error\","
- "\"message\":\"999999 is not a valid class id.\","
- "\"request\":{\"arguments\":[\"classes\",\"999999\"],"
- "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Request the class A over the service.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
@@ -616,8 +569,8 @@
// Request function 'b' from class A.
service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b'],"
- "[], []]", cid);
+ "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/functions/b']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
@@ -626,8 +579,8 @@
"\"name\":\"b\",", cid);
// Request field 0 from class A.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'fields', '0'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/fields/0']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Field\"", handler.msg());
@@ -636,74 +589,51 @@
"\"name\":\"a\",", cid);
// Invalid sub command.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'huh', '0'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/huh']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\",\"message\":\"Invalid sub collection huh\""
- ",\"request\":"
- "{\"arguments\":[\"classes\",\"%" Pd "\",\"huh\",\"0\"],\"option_keys\":[],"
- "\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Invalid field request.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'fields', '9'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/fields/9']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\",\"message\":\"Field 9 not found\","
- "\"request\":{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Invalid function request.
service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'functions', '9'],"
- "[], []]", cid);
+ "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/functions/9']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\",\"message\":\"Function 9 not found\","
- "\"request\":{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
-
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Invalid field subcommand.
service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'fields', '9', 'x']"
- ",[], []]", cid);
+ "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/fields/9']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\",\"message\":\"Command too long\","
- "\"request\":"
- "{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\",\"x\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Invalid function command.
service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'functions', '0',"
- "'x', 'y'], [], []]", cid);
+ "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/functions/0/x/y']]",
+ cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\","
- "\"message\":\"Command should have 4 or 5 arguments\","
- "\"request\":"
- "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"0\",\"x\",\"y\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Invalid function subcommand with valid function id.
service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b',"
- "'x'], [], []]", cid);
+ "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/functions/b/x']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\",\"message\":\"Invalid sub command x\","
- "\"request\":"
- "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"b\",\"x\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Retained size of all instances of class B.
const Class& class_b = Class::Handle(GetClass(vmlib, "B"));
@@ -748,127 +678,6 @@
}
-TEST_CASE(Service_SetSource) {
- const char* kScript =
- "var port;\n" // Set to our mock port by C++.
- "\n"
- "class A {\n"
- " a() { return 1; }\n"
- " b() { return 0; }\n"
- " c(String f) { return f.length; }\n"
- "}\n"
- "main() {\n"
- " var z = new A();\n"
- " return z.a();\n"
- "}\n"
- "runB() {\n"
- " var z = new A();\n"
- " return z.b();\n"
- "}\n"
- "runC() {\n"
- " var z = new A();\n"
- " return z.c();\n"
- "}\n";
-
- Isolate* isolate = Isolate::Current();
- Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
- EXPECT_VALID(lib);
- Library& vmlib = Library::Handle();
- vmlib ^= Api::UnwrapHandle(lib);
- EXPECT(!vmlib.IsNull());
- Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
- EXPECT_VALID(result);
- const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
- EXPECT(!class_a.IsNull());
- intptr_t cid = class_a.id();
-
- // Build a mock message handler and wrap it in a dart port.
- ServiceTestMessageHandler handler;
- Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
- EXPECT_VALID(port);
- EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
-
- Array& service_msg = Array::Handle();
-
- // Request the class A over the service.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
- ExpectSubstringF(handler.msg(),
- "\"id\":\"classes\\/%" Pd "\",\"name\":\"A\",", cid);
- ExpectSubstringF(handler.msg(), "\"allocationStats\":");
- ExpectSubstringF(handler.msg(), "\"tokenPos\":");
- ExpectSubstringF(handler.msg(), "\"endTokenPos\":");
-
- // Request function 'b' from class A.
- service_msg = EvalF(lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b'],"
- "[], []]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
- ExpectSubstringF(handler.msg(),
- "\"id\":\"classes\\/%" Pd "\\/functions\\/b\","
- "\"name\":\"b\",", cid);
-
- // Invalid set source of function 'b' from class A.
- service_msg = EvalF(
- lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
- "[], []]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
- EXPECT_SUBSTRING("set_source expects a 'source' option", handler.msg());
-
- // Set source (with syntax error) of function 'b' from class A.
- service_msg = EvalF(
- lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
- "['source'], ['b() { return 4 }']]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
-
- // Set source of function 'b' from class A.
- service_msg = EvalF(
- lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'b', 'set_source'],"
- "['source'], ['b() { return 4; }']]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("Success", handler.msg());
-
- // Run function 'b' see that it is executing replaced code.
- result = Dart_Invoke(lib, NewString("runB"), 0, NULL);
- EXPECT_VALID(result);
- ASSERT(Dart_IsInteger(result));
- int64_t r;
- result = Dart_IntegerToInt64(result, &r);
- EXPECT_VALID(result);
- EXPECT_EQ(4, r);
-
- // Set source of function 'c' from class A, changing its signature.
- service_msg = EvalF(
- lib,
- "[0, port, ['classes', '%" Pd "', 'functions', 'c', 'set_source'],"
- "['source'], ['c() { return 99; }']]", cid);
- Service::HandleIsolateMessage(isolate, service_msg);
- handler.HandleNextMessage();
- EXPECT_SUBSTRING("Success", handler.msg());
-
- // Run function 'c' see that it is executing replaced code.
- result = Dart_Invoke(lib, NewString("runC"), 0, NULL);
- EXPECT_VALID(result);
- ASSERT(Dart_IsInteger(result));
- result = Dart_IntegerToInt64(result, &r);
- EXPECT_VALID(result);
- EXPECT_EQ(99, r);
-}
-
-
TEST_CASE(Service_Types) {
const char* kScript =
"var port;\n" // Set to our mock port by C++.
@@ -901,7 +710,8 @@
Array& service_msg = Array::Handle();
// Request the class A over the service.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "'], [], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "']]]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
@@ -910,8 +720,8 @@
"\"id\":\"classes\\/%" Pd "\"", cid);
// Request canonical type 0 from class A.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '0'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/types/0']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Type\"", handler.msg());
@@ -920,8 +730,8 @@
"\"id\":\"classes\\/%" Pd "\\/types\\/0\"", cid);
// Request canonical type 1 from class A.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '1'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/types/1']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("\"type\":\"Type\"", handler.msg());
@@ -930,16 +740,11 @@
"\"id\":\"classes\\/%" Pd "\\/types\\/1\"", cid);
// Request for non-existent canonical type from class A.
- service_msg = EvalF(lib, "[0, port, ['classes', '%" Pd "', 'types', '42'],"
- "[], []]", cid);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['classes/%" Pd "/types/42']]", cid);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- ExpectSubstringF(handler.msg(),
- "{\"type\":\"Error\","
- "\"message\":\"Canonical type 42 not found\""
- ",\"request\":"
- "{\"arguments\":[\"classes\",\"%" Pd "\",\"types\",\"42\"],"
- "\"option_keys\":[],\"option_values\":[]}}", cid);
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
}
@@ -991,17 +796,15 @@
Array& service_msg = Array::Handle();
// Request an invalid code object.
- service_msg = Eval(lib, "[0, port, ['code', '0'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObject', ['objectId'], ['code/0']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_STREQ(
- "{\"type\":\"Error\",\"message\":\"Malformed code id: 0\","
- "\"request\":{\"arguments\":[\"code\",\"0\"],"
- "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// The following test checks that a code object can be found only
// at compile_timestamp()-code.EntryPoint().
- service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['code/%" Px64"-%" Px "']]",
compile_timestamp,
entry);
Service::HandleIsolateMessage(isolate, service_msg);
@@ -1020,44 +823,29 @@
// Request code object at compile_timestamp-code.EntryPoint() + 16
// Expect this to fail because the address is not the entry point.
uintptr_t address = entry + 16;
- service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['code/%" Px64"-%" Px "']]",
compile_timestamp,
address);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- {
- // Only perform a partial match.
- const intptr_t kBufferSize = 512;
- char buffer[kBufferSize];
- OS::SNPrint(buffer, kBufferSize-1,
- "Could not find code with id: %" Px64 "-%" Px "",
- compile_timestamp,
- address);
- EXPECT_SUBSTRING(buffer, handler.msg());
- }
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Request code object at (compile_timestamp - 1)-code.EntryPoint()
// Expect this to fail because the timestamp is wrong.
address = entry;
- service_msg = EvalF(lib, "[0, port, ['code', '%" Px64"-%" Px "'], [], []]",
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['code/%" Px64"-%" Px "']]",
compile_timestamp - 1,
address);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- {
- // Only perform a partial match.
- const intptr_t kBufferSize = 512;
- char buffer[kBufferSize];
- OS::SNPrint(buffer, kBufferSize-1,
- "Could not find code with id: %" Px64 "-%" Px "",
- compile_timestamp - 1,
- address);
- EXPECT_SUBSTRING(buffer, handler.msg());
- }
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
// Request native code at address. Expect the null code object back.
address = last;
- service_msg = EvalF(lib, "[0, port, ['code', 'native-%" Px "'], [], []]",
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['code/native-%" Px "']]",
address);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
@@ -1066,11 +854,12 @@
handler.msg());
// Request malformed native code.
- service_msg = EvalF(lib, "[0, port, ['code', 'native%" Px "'], [], []]",
+ service_msg = EvalF(lib, "[0, port, 'getObject', ['objectId'], "
+ "['code/native%" Px "']]",
address);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"message\":\"Malformed code id:", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"Error\"", handler.msg());
}
@@ -1109,7 +898,8 @@
Array& service_msg = Array::Handle();
// Fetch object.
- service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
@@ -1170,7 +960,8 @@
Array& service_msg = Array::Handle();
// Fetch object.
- service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
// Check type.
@@ -1230,7 +1021,8 @@
Array& service_msg = Array::Handle();
// Fetch object.
- service_msg = EvalF(lib, "[0, port, ['objects', '%" Pd "'], [], []]", id);
+ service_msg = EvalF(lib, "[0, port, 'getObject', "
+ "['objectId'], ['objects/%" Pd "']]", id);
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
// Check type.
@@ -1260,7 +1052,7 @@
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, ['vm'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getVM', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
@@ -1292,7 +1084,7 @@
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, ['flags'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getFlagList', [], []]");
// Make sure we can get the FlagList.
Service::HandleRootMessage(service_msg);
@@ -1305,14 +1097,14 @@
// Modify a flag through the vm service.
service_msg = Eval(lib,
- "[0, port, ['flags', 'set'], "
+ "[0, port, 'setFlag', "
"['name', 'value'], ['service_testing_flag', 'true']]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING("Success", handler.msg());
// Make sure that the flag changed.
- service_msg = Eval(lib, "[0, port, ['flags'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getFlagList', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
EXPECT_SUBSTRING(
@@ -1346,8 +1138,9 @@
Array& service_msg = Array::Handle();
char buf[1024];
OS::SNPrint(buf, sizeof(buf),
- "[0, port, ['libraries', '%" Pd "', 'scripts', 'test-lib'], [], []]",
- vmlib.index());
+ "[0, port, 'getObject', "
+ "['objectId'], ['libraries/%" Pd "/scripts/test-lib']]",
+ vmlib.index());
service_msg = Eval(lib, buf);
Service::HandleIsolateMessage(isolate, service_msg);
@@ -1490,8 +1283,11 @@
char buf[1024];
bool ref = offset % 2 == 0;
OS::SNPrint(buf, sizeof(buf),
- ref ? "[0, port, ['address', '%" Px "'], ['ref'], ['true']]" :
- "[0, port, ['address', '%" Px "', ], [], []]",
+ (ref
+ ? "[0, port, 'getObjectByAddress', "
+ "['address', 'ref'], ['%" Px "', 'true']]"
+ : "[0, port, 'getObjectByAddress', "
+ "['address'], ['%" Px "']]"),
addr);
service_msg = Eval(lib, buf);
Service::HandleIsolateMessage(isolate, service_msg);
@@ -1502,7 +1298,8 @@
EXPECT_SUBSTRING("foobar", handler.msg());
}
// Expect null when no object is found.
- service_msg = Eval(lib, "[0, port, ['address', '7'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'getObjectByAddress', "
+ "['address'], ['7']]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
// TODO(turnidge): Should this be a ServiceException instead?
@@ -1514,8 +1311,6 @@
static const char* alpha_callback(
const char* name,
- const char** arguments,
- intptr_t num_arguments,
const char** option_keys,
const char** option_values,
intptr_t num_options,
@@ -1526,8 +1321,6 @@
static const char* beta_callback(
const char* name,
- const char** arguments,
- intptr_t num_arguments,
const char** option_keys,
const char** option_values,
intptr_t num_options,
@@ -1564,11 +1357,11 @@
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, ['alpha'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'alpha', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
EXPECT_STREQ("alpha", handler.msg());
- service_msg = Eval(lib, "[0, port, ['beta'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'beta', [], []]");
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
EXPECT_STREQ("beta", handler.msg());
@@ -1601,11 +1394,11 @@
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, ['alpha'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'alpha', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_STREQ("alpha", handler.msg());
- service_msg = Eval(lib, "[0, port, ['beta'], [], []]");
+ service_msg = Eval(lib, "[0, port, 'beta', [], []]");
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
EXPECT_STREQ("beta", handler.msg());
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 73e0b18..90a1b41 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -37,8 +37,13 @@
V(Call, "call") \
V(Current, "current") \
V(MoveNext, "moveNext") \
+ V(IsYieldEach, "isYieldEach") \
V(Value, "value") \
V(_EnumHelper, "_EnumHelper") \
+ V(_SyncIterable, "_SyncIterable") \
+ V(_SyncIterableConstructor, "_SyncIterable.") \
+ V(_SyncIterator, "_SyncIterator") \
+ V(IteratorParameter, ":iterator") \
V(Values, "values") \
V(_EnumNames, "_enum_names") \
V(ExprTemp, ":expr_temp") \
@@ -66,7 +71,7 @@
V(StringBase, "_StringBase") \
V(Interpolate, "_interpolate") \
V(InterpolateSingle, "_interpolateSingle") \
- V(GetIterator, "iterator") \
+ V(Iterator, "iterator") \
V(NoSuchMethod, "noSuchMethod") \
V(CurrentContextVar, ":current_context_var") \
V(SavedTryContextVar, ":saved_try_context_var") \
@@ -80,6 +85,8 @@
V(LoadLibrary, "loadLibrary") \
V(_LibraryPrefix, "_LibraryPrefix") \
V(Async, "async") \
+ V(Sync, "sync") \
+ V(YieldKw, "yield") \
V(AsyncCompleter, ":async_completer") \
V(AsyncOperation, ":async_op") \
V(AsyncOperationParam, ":async_result") \
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index 7a75198..f89fe9d 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -1829,7 +1829,7 @@
_StackTrace(this._exception);
String toString() {
- if (_trace != null) return _trace;
+ if (_trace != null) return JS('String', '#', _trace);
String trace;
if (JS('bool', 'typeof # === "object"', _exception)) {
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
index 35740f0..dead76f 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -25,7 +25,7 @@
final _validOptions = new Set<String>.from([
'commandLineOptions', 'checked', 'csp', 'minify', 'verbose', 'environment',
'preserveUris', 'suppressWarnings', 'suppressHints',
- 'suppressPackageWarnings', 'terse'
+ 'suppressPackageWarnings', 'terse', 'sourceMaps'
]);
/// A [Transformer] that uses dart2js's library API to transform Dart
@@ -42,7 +42,8 @@
final BarbackSettings _settings;
/// Whether source maps should be generated for the compiled JS.
- bool get _generateSourceMaps => _settings.mode != BarbackMode.RELEASE;
+ bool get _generateSourceMaps => _configBool('sourceMaps',
+ defaultsTo: _settings.mode != BarbackMode.RELEASE);
Dart2JSTransformer.withSettings(this._environment, this._settings) {
var invalidOptions = _settings.configuration.keys.toSet()
@@ -146,7 +147,7 @@
suppressPackageWarnings: _configBool(
'suppressPackageWarnings', defaultsTo: true),
terse: _configBool('terse'),
- includeSourceMapUrls: _settings.mode != BarbackMode.RELEASE);
+ includeSourceMapUrls: _generateSourceMaps);
}
/// Parses and returns the "commandLineOptions" configuration option.
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 449c482..f2be2f2 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -6,6 +6,11 @@
test/serve/web_socket/url_to_asset_id_test: Pass, Slow
test/transformer/loads_a_diamond_transformer_dependency_graph_test: Pass, Slow
+test/global/binstubs/outdated_binstub_runs_pub_global_test: Fail # 22284
+test/global/binstubs/outdated_snapshot_test: Fail # 22284
+test/global/run/recompiles_if_sdk_is_out_of_date_test: Fail # 22284
+test/snapshot/recompiles_if_the_sdk_is_out_of_date_test: Fail # 22284
+
# Pub only runs on the VM, so just rule out all compilers.
[ $compiler == dart2js || $compiler == dart2dart ]
*: Skip
diff --git a/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart b/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
new file mode 100644
index 0000000..7efba1d
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("includes source maps in a release build if sourceMaps true", () {
+ d.dir(appPath, [
+ d.pubspec({
+ 'name': 'myapp',
+ 'transformers': [{
+ '\$dart2js': {
+ 'sourceMaps': true
+ }
+ }]
+ }),
+ d.dir("web", [
+ d.file("main.dart", "void main() => print('hello');")
+ ])
+ ]).create();
+
+ schedulePub(args: ["build"],
+ output: new RegExp(r'Built \d+ files to "build".'),
+ exitCode: 0);
+
+ d.dir(appPath, [
+ d.dir('build', [
+ d.dir('web', [
+ d.matcherFile('main.dart.js',
+ contains("# sourceMappingURL=main.dart.js.map")),
+ d.matcherFile('main.dart.js.map', contains('"file": "main.dart.js"'))
+ ])
+ ])
+ ]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart b/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
new file mode 100644
index 0000000..aaecf9b
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("omits source maps from a debug build if sourceMaps false", () {
+ d.dir(appPath, [
+ d.pubspec({
+ 'name': 'myapp',
+ 'transformers': [{
+ '\$dart2js': {
+ 'sourceMaps': false
+ }
+ }]
+ }),
+ d.dir("web", [
+ d.file("main.dart", "void main() => print('hello');")
+ ])
+ ]).create();
+
+ schedulePub(args: ["build", "--mode", "debug"],
+ output: new RegExp(r'Built \d+ files to "build".'),
+ exitCode: 0);
+
+ d.dir(appPath, [
+ d.dir('build', [
+ d.dir('web', [
+ d.nothing('main.dart.js.map')
+ ])
+ ])
+ ]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart b/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
index 81212b0..2cd9deb 100644
--- a/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
+++ b/sdk/lib/_internal/pub/test/dart2js/supports_valid_options_test.dart
@@ -25,7 +25,8 @@
"suppressWarnings": true,
"suppressHints": true,
"suppressPackageWarnings": false,
- "terse": true
+ "terse": true,
+ "sourceMaps": false
}
}]
}),
diff --git a/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
index 3910ef8..b6362eb 100644
--- a/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub_generated/lib/src/barback/dart2js_transformer.dart
@@ -33,7 +33,8 @@
'suppressWarnings',
'suppressHints',
'suppressPackageWarnings',
- 'terse']);
+ 'terse',
+ 'sourceMaps']);
/// A [Transformer] that uses dart2js's library API to transform Dart
/// entrypoints in "web" to JavaScript.
@@ -49,7 +50,8 @@
final BarbackSettings _settings;
/// Whether source maps should be generated for the compiled JS.
- bool get _generateSourceMaps => _settings.mode != BarbackMode.RELEASE;
+ bool get _generateSourceMaps =>
+ _configBool('sourceMaps', defaultsTo: _settings.mode != BarbackMode.RELEASE);
Dart2JSTransformer.withSettings(this._environment, this._settings) {
var invalidOptions =
@@ -158,7 +160,7 @@
'suppressPackageWarnings',
defaultsTo: true),
terse: _configBool('terse'),
- includeSourceMapUrls: _settings.mode != BarbackMode.RELEASE);
+ includeSourceMapUrls: _generateSourceMaps);
}
/// Parses and returns the "commandLineOptions" configuration option.
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
new file mode 100644
index 0000000..f8ebaec
--- /dev/null
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/includes_source_maps_if_sourceMaps_true_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("includes source maps in a release build if sourceMaps true", () {
+ d.dir(appPath, [d.pubspec({
+ 'name': 'myapp',
+ 'transformers': [{
+ '\$dart2js': {
+ 'sourceMaps': true
+ }
+ }]
+ }),
+ d.dir(
+ "web",
+ [d.file("main.dart", "void main() => print('hello');")])]).create();
+
+ schedulePub(
+ args: ["build"],
+ output: new RegExp(r'Built \d+ files to "build".'),
+ exitCode: 0);
+
+ d.dir(
+ appPath,
+ [
+ d.dir(
+ 'build',
+ [
+ d.dir(
+ 'web',
+ [
+ d.matcherFile('main.dart.js', contains("# sourceMappingURL=main.dart.js.map")),
+ d.matcherFile(
+ 'main.dart.js.map',
+ contains('"file": "main.dart.js"'))])])]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
new file mode 100644
index 0000000..f777b91
--- /dev/null
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/omits_source_map_if_sourceMaps_false_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.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 '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("omits source maps from a debug build if sourceMaps false", () {
+ d.dir(appPath, [d.pubspec({
+ 'name': 'myapp',
+ 'transformers': [{
+ '\$dart2js': {
+ 'sourceMaps': false
+ }
+ }]
+ }),
+ d.dir(
+ "web",
+ [d.file("main.dart", "void main() => print('hello');")])]).create();
+
+ schedulePub(
+ args: ["build", "--mode", "debug"],
+ output: new RegExp(r'Built \d+ files to "build".'),
+ exitCode: 0);
+
+ d.dir(
+ appPath,
+ [d.dir('build', [d.dir('web', [d.nothing('main.dart.js.map')])])]).validate();
+ });
+}
diff --git a/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart b/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
index 07afaa9..1c43421 100644
--- a/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
+++ b/sdk/lib/_internal/pub_generated/test/dart2js/supports_valid_options_test.dart
@@ -26,7 +26,8 @@
"suppressWarnings": true,
"suppressHints": true,
"suppressPackageWarnings": false,
- "terse": true
+ "terse": true,
+ "sourceMaps": false
}
}]
}),
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index d22f5ba..de9af01 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -43,7 +43,7 @@
AsyncError(this.error, this.stackTrace);
- String toString() => error.toString();
+ String toString() => '$error';
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 793c36c..d93583c 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -146,7 +146,7 @@
@DocsEditable()
Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -247,9 +247,10 @@
@Experimental() // untriaged
String username;
+
@DomName('HTMLAnchorElement.toString')
@DocsEditable()
- String toString() native;
+ String toString() => JS('String', 'String(#)', this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -707,7 +708,7 @@
@Experimental() // untriaged
final String url;
}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -804,10 +805,10 @@
@Experimental() // untriaged
String username;
+
@DomName('HTMLAreaElement.toString')
@DocsEditable()
- @Experimental() // untriaged
- String toString() native;
+ String toString() => JS('String', 'String(#)', this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -8576,8 +8577,7 @@
@DomName('DOMException.toString')
@DocsEditable()
- String toString() native;
-
+ String toString() => JS('String', 'String(#)', this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -11095,7 +11095,9 @@
@DomName('Element.localName')
@DocsEditable()
- String get localName => _localName;
+ @Returns('String')
+ // Non-null for Elements.
+ String get localName => JS('String', '#', _localName);
/**
* A URI that identifies the XML namespace of this element.
@@ -19006,10 +19008,6 @@
@DocsEditable()
void replace(String url) native;
- @DomName('Location.toString')
- @DocsEditable()
- String toString() native;
-
@DomName('Location.origin')
String get origin {
@@ -19018,6 +19016,10 @@
}
return '${this.protocol}//${this.host}';
}
+
+ @DomName('Location.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -21926,7 +21928,10 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => nodeValue == null ? super.toString() : nodeValue;
+ String toString() {
+ String value = nodeValue; // Fetch DOM Node property once.
+ return value == null ? super.toString() : value;
+ }
// To suppress missing implicit constructor warnings.
factory Node._() { throw new UnsupportedError("Not supported"); }
@@ -28896,6 +28901,11 @@
static void revokeObjectUrl(String url) =>
JS('void',
'(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+ @DomName('URL.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+
// To suppress missing implicit constructor warnings.
factory Url._() { throw new UnsupportedError("Not supported"); }
@@ -28956,11 +28966,6 @@
@Experimental() // untriaged
String username;
- @DomName('URL.toString')
- @DocsEditable()
- @Experimental() // untriaged
- String toString() native;
-
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 1504658..b195b1a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -20860,6 +20860,7 @@
String toString() => _blink.BlinkLocation.instance.toString_Callback_0_(this);
+
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -23993,7 +23994,10 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => nodeValue == null ? super.toString() : nodeValue;
+ String toString() {
+ String value = nodeValue; // Fetch DOM Node property once.
+ return value == null ? super.toString() : value;
+ }
// To suppress missing implicit constructor warnings.
factory Node._() { throw new UnsupportedError("Not supported"); }
@@ -31432,10 +31436,10 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream)) {
+ if ((blob_OR_source_OR_stream is MediaSource)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource)) {
+ if ((blob_OR_source_OR_stream is MediaStream)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 711793a..8a493a2 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -729,7 +729,7 @@
* *NOTE* file locking does have slight differences in behavior across
* platforms:
*
- * On Linux and Mac OS this uses advisory locks, which have the
+ * On Linux and OS X this uses advisory locks, which have the
* surprising semantics that all locks associated with a given file
* are removed when *any* file descriptor for that file is closed by
* the process. Note that this does not actually lock the file for
@@ -762,7 +762,7 @@
* *NOTE* file locking does have slight differences in behavior across
* platforms:
*
- * On Linux and Mac OS this uses advisory locks, which have the
+ * On Linux and OS X this uses advisory locks, which have the
* surprising semantics that all locks associated with a given file
* are removed when *any* file descriptor for that file is closed by
* the process. Note that this does not actually lock the file for
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index f392327..642a063 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -273,7 +273,7 @@
*
* [resolveSymbolicLinks] uses the operating system's native
* file system API to resolve the path, using the `realpath` function
- * on linux and Mac OS, and the `GetFinalPathNameByHandle` function on
+ * on linux and OS X, and the `GetFinalPathNameByHandle` function on
* Windows. If the path does not point to an existing file system object,
* `resolveSymbolicLinks` throws a `FileSystemException`.
*
@@ -313,7 +313,7 @@
*
* [resolveSymbolicLinksSync] uses the operating system's native
* file system API to resolve the path, using the `realpath` function
- * on linux and Mac OS, and the `GetFinalPathNameByHandle` function on
+ * on linux and OS X, and the `GetFinalPathNameByHandle` function on
* Windows. If the path does not point to an existing file system object,
* `resolveSymbolicLinksSync` throws a `FileSystemException`.
*
@@ -418,7 +418,7 @@
* files and directories. Recursive watching is not supported.
* Note: When watching files directly, delete events might not happen
* as expected.
- * * `Mac OS`: Uses `FSEvents`. The implementation supports watching both
+ * * `OS X`: Uses `FSEvents`. The implementation supports watching both
* files and directories. Recursive watching is supported.
*
* The system will start listening for events once the returned [Stream] is
@@ -529,7 +529,7 @@
/**
* Test if [watch] is supported on the current system.
*
- * Mac OS 10.6 and below is not supported.
+ * OS X 10.6 and below is not supported.
*/
static bool get isWatchSupported => _FileSystemWatcher.isSupported;
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index b90afe4..12e152c 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -100,7 +100,7 @@
static final bool isLinux = (_operatingSystem == "linux");
/**
- * Returns true if the operating system is Mac OS.
+ * Returns true if the operating system is OS X.
*/
static final bool isMacOS = (_operatingSystem == "macos");
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 43f6bcd..2d8ecab 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -23,7 +23,7 @@
*
* The handling of exit codes is platform specific.
*
- * On Linux and Mac OS an exit code for normal termination will always
+ * On Linux and OS X an exit code for normal termination will always
* be in the range [0..255]. If an exit code outside this range is
* set the actual exit code will be the lower 8 bits masked off and
* treated as an unsigned value. E.g. using an exit code of -1 will
@@ -212,7 +212,7 @@
*
* The handling of exit codes is platform specific.
*
- * On Linux and Mac a normal exit code will be a positive value in
+ * On Linux and OS X a normal exit code will be a positive value in
* the range [0..255]. If the process was terminated due to a signal
* the exit code will be a negative value in the range [-255..-1],
* where the absolute value of the exit code is the signal
@@ -255,7 +255,7 @@
* precedence. Default is `true`.
*
* If [runInShell] is `true`, the process will be spawned through a system
- * shell. On Linux and Mac OS, [:/bin/sh:] is used, while
+ * shell. On Linux and OS X, [:/bin/sh:] is used, while
* [:%WINDIR%\system32\cmd.exe:] is used on Windows.
*
* Users must read all data coming on the [stdout] and [stderr]
@@ -320,7 +320,7 @@
* precedence. Default is `true`.
*
* If [runInShell] is true, the process will be spawned through a system
- * shell. On Linux and Mac OS, `/bin/sh` is used, while
+ * shell. On Linux and OS X, `/bin/sh` is used, while
* `%WINDIR%\system32\cmd.exe` is used on Windows.
*
* The encoding used for decoding `stdout` and `stderr` into text is
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index d9c713f..42e1478 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2957,6 +2957,11 @@
LayoutTests/fast/alignment/parse-align-items_t01: RuntimeError # Please triage this failure
LayoutTests/fast/alignment/parse-align-self_t01: RuntimeError # Please triage this failure
LayoutTests/fast/alignment/parse-justify-self_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-cancel2_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-cancel_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-timestamps-advance_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-timestamps_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/animation/request-animation-frame-within-callback_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/backgrounds/background-repeat-computed-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
LayoutTests/fast/borders/border-image-width-numbers-computed-style_t01: RuntimeError # Please triage this failure
@@ -2968,6 +2973,7 @@
LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.verySmall_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/alpha_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-arc-negative-radius_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/canvas-as-image-incremental-repaint_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/canvas/canvas-blend-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blend-solid_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-clipping_t01: RuntimeError # Please triage this failure
@@ -3021,6 +3027,7 @@
LayoutTests/fast/canvas/drawImage-with-broken-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/drawImage-with-valid-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/setWidthResetAfterForcedRender_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: RuntimeError # Please triage this failure
@@ -3099,7 +3106,7 @@
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgb565_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # Please triage this failure
@@ -3332,6 +3339,7 @@
LayoutTests/fast/dom/HTMLScriptElement/async-onbeforeload_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLScriptElement/defer-inline-script_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLScriptElement/defer-onbeforeload_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/HTMLScriptElement/script-set-src_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLSelectElement/selected-index-preserved-when-option-text-changes_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLTemplateElement/custom-element-wrapper-gc_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/HTMLTemplateElement/cycles-in-shadow_t01: RuntimeError # Please triage this failure
@@ -3408,6 +3416,7 @@
LayoutTests/fast/dom/implementation-api-args_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/implementation-createHTMLDocument_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/importNode-unsupported-node-type_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/location-hash_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/dom/location-missing-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/navigatorcontentutils/register-protocol-handler_t01: RuntimeError # Please triage this failure
@@ -3512,6 +3521,7 @@
LayoutTests/fast/events/invalid-004_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/mutation-during-replace-child-2_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/mutation-during-replace-child_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/events/overflowchanged-event-raf-timing_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/events/scroll-event-does-not-bubble_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/tabindex-removal-from-focused-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/wheelevent-constructor_t01: RuntimeError # Please triage this failure
@@ -3524,6 +3534,7 @@
LayoutTests/fast/files/blob-parts-slice-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/files/blob-slice-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/files/file-reader-abort-in-last-progress_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/files/file-reader-done-reading-abort_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/files/file-reader-methods-illegal-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/files/file-reader-readystate_t01: RuntimeError # Please triage this failure
LayoutTests/fast/files/url-null_t01: RuntimeError # Please triage this failure
@@ -3704,8 +3715,10 @@
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-inset-rounded-different-writing-modes-right_t01: RuntimeError # Please triage this failure
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-rounded-boxes_t01: RuntimeError # Please triage this failure
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-rounded-boxes_t02: RuntimeError # Please triage this failure
+LayoutTests/fast/speechsynthesis/speech-synthesis-boundary-events_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/speechsynthesis/speech-synthesis-cancel_t01: RuntimeError # Please triage this failure
LayoutTests/fast/speechsynthesis/speech-synthesis-pause-resume_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/speechsynthesis/speech-synthesis-speak_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/speechsynthesis/speech-synthesis-utterance-uses-voice_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/speechsynthesis/speech-synthesis-voices_t01: RuntimeError # Please triage this failure
LayoutTests/fast/storage/disallowed-storage_t01: RuntimeError # Please triage this failure
@@ -3918,6 +3931,7 @@
LibTest/html/Node/nodes_A01_t02: RuntimeError # Please triage this failure
LibTest/html/Node/parent_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Node/previousNode_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Window/animationFrame_A01_t01: Skip # Times out. Please triage this failure
LibTest/html/Window/close_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/document_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/find_A01_t01: RuntimeError # Please triage this failure
@@ -3931,7 +3945,7 @@
LibTest/html/Window/requestFileSystem_A01_t01: RuntimeError # Please triage this failure
LibTest/html/Window/requestFileSystem_A01_t02: RuntimeError # Please triage this failure
LibTest/html/Window/requestFileSystem_A02_t01: RuntimeError # Please triage this failure
-LibTest/html/Window/resizeBy_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Window/resizeBy_A01_t01: Skip # Times out. Please triage this failure
LibTest/html/Window/resizeTo_A01_t01: RuntimeError # Please triage this failure
LibTest/typed_data/Float32x4List/Float32x4List.view_A06_t01: RuntimeError # Please triage this failure
LibTest/typed_data/Int32x4/operator_OR_A01_t01: RuntimeError # Please triage this failure
@@ -4190,9 +4204,10 @@
WebPlatformTest/webstorage/event_local_key_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/event_session_key_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/event_session_storagearea_t01: Pass, RuntimeError # Fails on 7.1. Please triage this failure
+WebPlatformTest/webstorage/event_session_url_t01: Skip # Times out. Please triage this failure
WebPlatformTest/webstorage/storage_local_setitem_t01: RuntimeError # Please triage this failure
WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
-WebPlatformTest/webstorage/storage_session_setitem_t01: RuntimeError # Please triage this failure
+WebPlatformTest/webstorage/storage_session_setitem_t01: Skip # Times out. Please triage this failure
[ $compiler == dart2js && $runtime == safarimobilesim ]
Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # Please triage this failure
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 4e39fdf..5607f3f 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -2,9 +2,10 @@
# 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.
-async_await_syntax_test: Fail # Issue 22260
boolified_operator_test: Fail # Issue 8001
+async_await_syntax_test: Skip # Not sure how/why test cases a03b, a04c fail.
+
# simple_function_subtype_test is temporarily(?) disabled due to new method for
# building function type tests.
simple_function_subtype_test: Fail
diff --git a/tests/compiler/dart2js/expect_annotations_test.dart b/tests/compiler/dart2js/expect_annotations_test.dart
new file mode 100644
index 0000000..ed8889a
--- /dev/null
+++ b/tests/compiler/dart2js/expect_annotations_test.dart
@@ -0,0 +1,81 @@
+// 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.
+
+import 'dart:io';
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/dart2jslib.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/js_backend/js_backend.dart';
+import 'memory_compiler.dart';
+
+const Map MEMORY_SOURCE_FILES = const {
+ 'main.dart': r"""
+import 'package:expect/expect.dart';
+
+int method(String arg) => arg.length;
+
+@AssumeDynamic()
+int methodAssumeDynamic(String arg) => arg.length;
+
+@TrustTypeAnnotations()
+int methodTrustTypeAnnotations(String arg) => arg.length;
+
+@NoInlining()
+int methodNoInlining(String arg) => arg.length;
+
+@NoInlining() @TrustTypeAnnotations()
+int methodNoInliningTrustTypeAnnotations(String arg) => arg.length;
+
+void main(List<String> args) {
+ print(method(args[0]));
+ print(methodAssumeDynamic('foo'));
+ print(methodTrustTypeAnnotations(null));
+ print(methodNoInlining('bar'));
+ print(methodNoInliningTrustTypeAnnotations(null));
+}
+"""
+};
+
+main() {
+ Compiler compiler = compilerFor(MEMORY_SOURCE_FILES);
+ asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
+ Expect.isFalse(compiler.compilationFailed, 'Unsuccessful compilation');
+ JavaScriptBackend backend = compiler.backend;
+ Expect.isNotNull(backend.annotations.expectNoInliningClass,
+ 'NoInliningClass is unresolved.');
+ Expect.isNotNull(backend.annotations.expectTrustTypeAnnotationsClass,
+ 'TrustTypeAnnotations is unresolved.');
+ Expect.isNotNull(backend.annotations.expectAssumeDynamicClass,
+ 'AssumeDynamicClass is unresolved.');
+
+ void test(String name,
+ {bool expectNoInlining: false,
+ bool expectTrustTypeAnnotations: false,
+ bool expectAssumeDynamic: false}) {
+ Element method = compiler.mainApp.find(name);
+ Expect.isNotNull(method);
+ Expect.equals(
+ expectNoInlining,
+ backend.annotations.noInlining(method),
+ "Unexpected annotation of @NoInlining on '$method'.");
+ Expect.equals(
+ expectTrustTypeAnnotations,
+ backend.annotations.trustTypeAnnotations(method),
+ "Unexpected annotation of @TrustTypeAnnotations on '$method'.");
+ Expect.equals(
+ expectAssumeDynamic,
+ backend.annotations.assumeDynamic(method),
+ "Unexpected annotation of @AssumeDynamic on '$method'.");
+ }
+
+ test('method');
+ test('methodAssumeDynamic', expectAssumeDynamic: true);
+ test('methodTrustTypeAnnotations', expectTrustTypeAnnotations: true);
+ test('methodNoInlining', expectNoInlining: true);
+ test('methodNoInliningTrustTypeAnnotations',
+ expectNoInlining: true,
+ expectTrustTypeAnnotations: true);
+ }));
+}
diff --git a/tests/language/async_await_syntax_test.dart b/tests/language/async_await_syntax_test.dart
index 3c8c38b..b1affb9 100644
--- a/tests/language/async_await_syntax_test.dart
+++ b/tests/language/async_await_syntax_test.dart
@@ -15,10 +15,10 @@
a01c() sync* => null; /// a01c: compile-time error
a02a() async {} /// a02a: ok
a03a() async* {} /// a03a: ok
-a03b() async * {} /// a03b: compile-time error
+a03b() async * {} /// a03b: ok
a04a() sync* {} /// a04a: ok
a04b() sync {} /// a04b: compile-time error
-a04c() sync * {} /// a04c: compile-time error
+a04c() sync * {} /// a04c: ok
a05a() async { await 0; } /// a05a: ok
a05b() async { /// a05b: ok
await(a) {}; /// a05b: continued
diff --git a/tests/language/cyclic_type_test.dart b/tests/language/cyclic_type_test.dart
index 4de75d9..ed591fc 100644
--- a/tests/language/cyclic_type_test.dart
+++ b/tests/language/cyclic_type_test.dart
@@ -28,6 +28,11 @@
class Derived2<V> extends Base<Derived1<Derived2<V>>> {} /// 04: ok
main() {
+ // In the tests below we test that we get "int" and "bool" when calling
+ // toString() on the int and bool type respectively. This is not required
+ // behavior. However, we want to keep the original names for the most common
+ // core types so we make sure to handle these specifically in the compiler.
+
var d;
d = new Derived(); /// 00: continued
Expect.equals("Derived", d.t.toString()); /// 00: continued
@@ -37,6 +42,7 @@
Expect.equals("Derived<Derived>", d.t.toString()); /// 00: continued
d = new Derived(); /// 01: continued
+
Expect.equals("Derived<Derived<int>>", d.t.toString()); /// 01: continued
d = new Derived<bool>(); /// 01: continued
Expect.equals("Derived<Derived<int>>", d.t.toString()); /// 01: continued
diff --git a/tests/language/f_bounded_quantification5_test.dart b/tests/language/f_bounded_quantification5_test.dart
index b45cb2d..b70f061 100644
--- a/tests/language/f_bounded_quantification5_test.dart
+++ b/tests/language/f_bounded_quantification5_test.dart
@@ -25,6 +25,9 @@
main() {
bool got_type_error = false;
try {
+ // Getting "int" when calling toString() on the int type is not required.
+ // However, we want to keep the original names for the most common core
+ // types so we make sure to handle these specifically in the compiler.
Expect.equals("A<B<int>>", new A<B<int>>().runtimeType.toString());
} on TypeError catch (error) {
got_type_error = true;
diff --git a/tests/language/language.status b/tests/language/language.status
index e87eb35..acad979 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -7,7 +7,6 @@
[ $compiler == none ]
built_in_identifier_prefix_test: Fail # Issue 6970
-async_await_syntax_test/b00a: MissingCompileTimeError # Issue 21404
# These bugs refer currently ongoing language discussions.
constructor_initializer_test/none: Fail # Issue 12633
@@ -19,6 +18,7 @@
duplicate_export_negative_test: Fail # Issue 6134
[ $compiler == dart2dart ]
+
deferred_load_library_wrong_args_test/none: Fail # Issue 17523
deferred_load_inval_code_test: Fail # Issue 17523
deferred_not_loaded_check_test: Fail # Issue 17523
@@ -41,68 +41,39 @@
least_upper_bound_expansive_test/*: Fail, OK
compile_time_constant12_test: Fail # Issue 21000
-async_await_syntax_test/a07a: CompileTimeError # Issue 21404
-async_await_syntax_test/a08a: CompileTimeError # Issue 21404
async_await_syntax_test/a09a: CompileTimeError # Issue 21404
async_await_syntax_test/a10a: CompileTimeError # Issue 21404
-async_await_syntax_test/b07a: CompileTimeError # Issue 21404
-async_await_syntax_test/b08a: CompileTimeError # Issue 21404
async_await_syntax_test/b09a: CompileTimeError # Issue 21404
async_await_syntax_test/b10a: CompileTimeError # Issue 21404
-async_await_syntax_test/c07a: CompileTimeError # Issue 21404
-async_await_syntax_test/c08a: CompileTimeError # Issue 21404
async_await_syntax_test/c09a: CompileTimeError # Issue 21404
async_await_syntax_test/c10a: CompileTimeError # Issue 21404
-async_await_syntax_test/d07a: CompileTimeError # Issue 21404
-async_await_syntax_test/d08a: CompileTimeError # Issue 21404
-async_await_syntax_test/d08b: CompileTimeError # Issue 21404
async_await_syntax_test/d09a: CompileTimeError # Issue 21404
async_await_syntax_test/d10a: CompileTimeError # Issue 21404
[ $compiler == none || ($compiler == dart2dart && $builder_tag != new_backend) ]
compile_time_constant_c_test/01: Fail # Issue 21000
async_await_syntax_test/a03a: CompileTimeError # Issue 21404
-async_await_syntax_test/a04a: CompileTimeError # Issue 21404
-async_await_syntax_test/a11b: CompileTimeError # Issue 21404
+async_await_syntax_test/a03b: CompileTimeError # Issue 21404
async_await_syntax_test/a11d: CompileTimeError # Issue 21404
async_await_syntax_test/b03a: CompileTimeError # Issue 21404
-async_await_syntax_test/b04a: CompileTimeError # Issue 21404
-async_await_syntax_test/b11b: CompileTimeError # Issue 21404
async_await_syntax_test/b11d: CompileTimeError # Issue 21404
async_await_syntax_test/c03a: CompileTimeError # Issue 21404
-async_await_syntax_test/c04a: CompileTimeError # Issue 21404
async_await_syntax_test/d03a: CompileTimeError # Issue 21404
-async_await_syntax_test/d04a: CompileTimeError # Issue 21404
[ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
async_await_syntax_test/a03a: RuntimeError # Issue 21404
-async_await_syntax_test/a04a: RuntimeError # Issue 21404
-async_await_syntax_test/a07a: RuntimeError # Issue 21404
-async_await_syntax_test/a08a: RuntimeError # Issue 21404
+async_await_syntax_test/a03b: RuntimeError # Issue 21404
async_await_syntax_test/a09a: RuntimeError # Issue 21404
async_await_syntax_test/a10a: RuntimeError # Issue 21404
-async_await_syntax_test/a11b: RuntimeError # Issue 21404
async_await_syntax_test/a11d: RuntimeError # Issue 21404
-async_await_syntax_test/b00a: Fail # Issue 21404
async_await_syntax_test/b03a: RuntimeError # Issue 21404
-async_await_syntax_test/b04a: RuntimeError # Issue 21404
-async_await_syntax_test/b07a: RuntimeError # Issue 21404
-async_await_syntax_test/b08a: RuntimeError # Issue 21404
async_await_syntax_test/b09a: RuntimeError # Issue 21404
async_await_syntax_test/b10a: RuntimeError # Issue 21404
-async_await_syntax_test/b11b: RuntimeError # Issue 21404
async_await_syntax_test/b11d: RuntimeError # Issue 21404
async_await_syntax_test/c03a: RuntimeError # Issue 21404
-async_await_syntax_test/c04a: RuntimeError # Issue 21404
-async_await_syntax_test/c07a: RuntimeError # Issue 21404
-async_await_syntax_test/c08a: RuntimeError # Issue 21404
async_await_syntax_test/c09a: RuntimeError # Issue 21404
async_await_syntax_test/c10a: RuntimeError # Issue 21404
async_await_syntax_test/d03a: RuntimeError # Issue 21404
-async_await_syntax_test/d04a: RuntimeError # Issue 21404
-async_await_syntax_test/d07a: RuntimeError # Issue 21404
-async_await_syntax_test/d08a: RuntimeError # Issue 21404
-async_await_syntax_test/d08b: RuntimeError # Issue 21404
async_await_syntax_test/d09a: RuntimeError # Issue 21404
async_await_syntax_test/d10a: RuntimeError # Issue 21404
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 242a521..ffee566 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -6,12 +6,12 @@
await_backwards_compatibility_test/none: CompileTimeError # Issue 22052
await_test: CompileTimeError # Issue 22052
+sync_generator2_test: Skip #
+
async_test/type-mismatch2: MissingStaticWarning # Issue 22053
async_test/type-mismatch3: MissingStaticWarning # Issue 22053
async_test/type-mismatch4: MissingStaticWarning # Issue 22053
-async_await_syntax_test/a03b: MissingCompileTimeError # Issue 22234
-async_await_syntax_test/a04c: MissingCompileTimeError # Issue 22234
async_await_syntax_test/a05c: CompileTimeError
async_await_syntax_test/a05e: CompileTimeError
async_await_syntax_test/a05f: MissingCompileTimeError
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 793472d..b0c7bfd 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -4,9 +4,6 @@
[ $compiler == dart2analyzer ]
-async_await_syntax_test/a03b: MissingCompileTimeError # Issue 22234
-async_await_syntax_test/a04c: MissingCompileTimeError # Issue 22234
-
# Runtime negative test. No static errors or warnings.
closure_call_wrong_argument_count_negative_test: skip
@@ -16,6 +13,8 @@
enum_syntax_test/05: Fail # 21649
enum_syntax_test/06: Fail # 21649
+sync_generator1_test: Fail
+
compile_time_constant_c_test/01: Fail # Issue 21000
compile_time_constant12_test: Fail # Issue 21000
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index fd18821..9a0121e 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -15,6 +15,8 @@
await_nonfuture_test: CompileTimeError # Issue 21411
await_regression_test: CompileTimeError # Issue 21411
await_test: CompileTimeError # Issue 21411
+sync_generator1_test: Fail # Issue 21411
+sync_generator2_test/none: Fail # Issue 21411
async_await_syntax_test/a01a: CompileTimeError # Issue 21411
async_await_syntax_test/a02a: CompileTimeError # Issue 21411
async_await_syntax_test/a03a: CompileTimeError # Issue 21411
@@ -63,6 +65,9 @@
async_await_syntax_test/d08b: CompileTimeError # Issue 21411
async_await_syntax_test/d09a: CompileTimeError # Issue 21411
async_await_syntax_test/d10a: CompileTimeError # Issue 21411
+async_await_syntax_test/a04c: CompileTimeError # Issue 22259
+async_await_syntax_test/a03b: CompileTimeError # Issue 22259
+
[ $compiler == dart2js && $unchecked ]
async_test/type-mismatch1: CompileTimeError # Issue 21411
@@ -269,6 +274,16 @@
type_variable_conflict2_test/01: RuntimeError # Issue 16180
[ $compiler == dart2dart ]
+async_await_syntax_test/a04c: Fail
+async_await_syntax_test/a03b: Fail
+sync_generator2_test/07: Fail
+sync_generator2_test/08: Fail
+sync_generator2_test/10: Fail
+sync_generator2_test/20: Fail
+sync_generator2_test/30: Fail
+sync_generator2_test/51: Fail
+sync_generator2_test/52: Fail
+
regress_13494_test: Fail # Issue 13494
enum_duplicate_test/01: CompileTimeError # Issue 22169
@@ -322,6 +337,8 @@
function_subtype_call2_test: RuntimeError # Issue 21673
[ $compiler == dart2dart && $minified ]
+sync_generator1_test: Fail
+sync_generator2_test/none: Fail
cyclic_type_test/0*: Fail # Issue 12605.
cyclic_type2_test: Fail # Issue 12605.
super_getter_setter_test: Fail # Issue 11065.
diff --git a/tests/language/mixin_type_parameters_simple_test.dart b/tests/language/mixin_type_parameters_simple_test.dart
index 0df7996..c077cab 100644
--- a/tests/language/mixin_type_parameters_simple_test.dart
+++ b/tests/language/mixin_type_parameters_simple_test.dart
@@ -18,6 +18,9 @@
main() {
var a = new A<int>();
+ // Getting "int" when calling toString() on the int type is not required.
+ // However, we want to keep the original names for the most common core types
+ // so we make sure to handle these specifically in the compiler.
Expect.equals("int", a.m1().toString());
Expect.equals("int", a.m2().toString());
a = new A<String>();
diff --git a/tests/language/sync_generator1_test.dart b/tests/language/sync_generator1_test.dart
new file mode 100644
index 0000000..8da1a88
--- /dev/null
+++ b/tests/language/sync_generator1_test.dart
@@ -0,0 +1,78 @@
+// 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.
+
+// Simple test program for sync* generator functions.
+
+// VMOptions=--optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+sum10() sync* {
+ var s = 0;
+ for (var k = 1; k <= 10; k++) {
+ s += k;
+ yield s;
+ }
+}
+
+class Range {
+ int start, end;
+ Range(this.start, this.end);
+ elements() sync* {
+ var e = start;
+ while (e <= end) yield e++;
+ }
+
+ get yield sync* { // yield is a legal member name here.
+ var e = start;
+ while (e <= end) yield e++;
+ }
+}
+
+get sync sync* { // sync is a legal identifier.
+ yield "sync";
+}
+
+einsZwei() sync* {
+ yield* 1;
+ yield* [2, 3];
+ yield* [];
+ yield 5;
+ yield [6];
+}
+
+main() {
+ for (int i = 0; i < 10; i++) {
+ var sums = sum10();
+ print(sums);
+ Expect.isTrue(sums is Iterable);
+ Expect.equals(10, sums.length);
+ Expect.equals(1, sums.first);
+ Expect.equals(55, sums.last);
+ var q = "";
+ for (var n in sums.take(3)) {
+ q += "$n ";
+ }
+ Expect.equals("1 3 6 ", q);
+
+ var r = new Range(10, 12);
+ var elems1 = r.elements();
+ print(elems1);
+ var elems2 = r.yield;
+ print(elems2);
+ // Walk the elements of each iterable and compare them.
+ var i = elems1.iterator;
+ Expect.isTrue(i is Iterator);
+ elems2.forEach((e) {
+ Expect.isTrue(i.moveNext());
+ Expect.equals(e, i.current);
+ });
+
+ print(sync);
+ Expect.equals("sync", sync.single);
+
+ print(einsZwei());
+ Expect.equals("(1, 2, 3, 5, [6])", einsZwei().toString());
+ }
+}
diff --git a/tests/language/sync_generator2_test.dart b/tests/language/sync_generator2_test.dart
new file mode 100644
index 0000000..ca6920c
--- /dev/null
+++ b/tests/language/sync_generator2_test.dart
@@ -0,0 +1,64 @@
+// 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.
+
+// Simple test program for sync* generator functions.
+
+import "package:expect/expect.dart";
+import "dart:async";
+
+var sync = "topLevelSync";
+var async = "topLevelAync";
+var await = "topLevelAwait";
+var yield = "topLevelYield";
+
+test01() sync* {
+ var yield = 0; /// 01: compile-time error
+ var await = 0; /// 02: compile-time error
+ var async = 0; /// 03: compile-time error
+ bool yield() => false; /// 04: compile-time error
+ bool await() => false; /// 05: compile-time error
+ bool async() => false; /// 06: compile-time error
+
+ var x1 = sync;
+ var x2 = async; /// 07: compile-time error
+ var x3 = await; /// 08: compile-time error
+ var x4 = await 55; /// 09: compile-time error
+ var x4 = yield; /// 10: compile-time error
+
+ var stream = new Stream.fromIterable([1, 2, 3]);
+ await for (var e in stream) print(e); /// 11: compile-time error
+}
+
+test02() sync* {
+ yield 12321;
+ return null; /// 20: compile-time error
+}
+
+test03() sync* => null; /// 30: compile-time error
+
+get test04 sync* => null; /// 40: compile-time error
+set test04(a) sync* { print(a); } /// 41: compile-time error
+
+class K {
+ K() sync* {}; /// 50: compile-time error
+ get nix sync* { }
+ get garnix sync* => null; /// 51: compile-time error
+ set etwas(var z) sync* { } /// 52: compile-time error
+ sync() sync* {
+ yield sync; // Yields a tear-off of the sync() method.
+ }
+}
+
+main() {
+ var x;
+ x = test01();
+ Expect.equals("()", x.toString());
+ x = test02();
+ Expect.equals("(12321)", x.toString());
+ x = test04; /// 40: continued
+ test04 = x; /// 41: continued
+ x = new K();
+ Expect.equals(1, x.sync().length);
+ Expect.isTrue(x.sync().single is Function);
+}
\ No newline at end of file
diff --git a/tests/standalone/full_coverage_test.dart b/tests/standalone/full_coverage_test.dart
index 7bba623..04cd94e 100644
--- a/tests/standalone/full_coverage_test.dart
+++ b/tests/standalone/full_coverage_test.dart
@@ -13,7 +13,8 @@
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
-final String coverageScript = "tools/full-coverage.dart";
+final String coverageScript =
+ Platform.script.resolve('../../tools/full-coverage.dart').toFilePath();
final String packageRoot = Platform.packageRoot;
final List dartBaseArgs = ['--package-root=${packageRoot}', '--checked',];
diff --git a/tests/standalone/io/arguments_test.dart b/tests/standalone/io/arguments_test.dart
index 5a4ca68..a4ed16a 100644
--- a/tests/standalone/io/arguments_test.dart
+++ b/tests/standalone/io/arguments_test.dart
@@ -2,7 +2,7 @@
// 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.
//
-// DartOptions=tests/standalone/io/arguments_test.dart 10 arguments_test 20
+// DartOptions=10 arguments_test 20
import "package:expect/expect.dart";
diff --git a/tests/standalone/io/directory_test.dart b/tests/standalone/io/directory_test.dart
index d06c77f..14685b1 100644
--- a/tests/standalone/io/directory_test.dart
+++ b/tests/standalone/io/directory_test.dart
@@ -124,9 +124,9 @@
}
static void testListTooLongName() {
+ asyncStart();
Directory.systemTemp.createTemp('dart_directory').then((d) {
var errors = 0;
- asyncStart();
setupListHandlers(Stream<FileSystemEntity> stream) {
stream.listen(
(_) => Expect.fail("Listing of non-existing directory should fail"),
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart
index 86cb355..25cf360 100644
--- a/tests/standalone/io/file_input_stream_test.dart
+++ b/tests/standalone/io/file_input_stream_test.dart
@@ -11,8 +11,12 @@
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
-String getFilename(String path) =>
- new File(path).existsSync() ? path : '../$path';
+String getFilename(String path) {
+ var testPath = Platform.script.resolve('../../../$path');
+ return new File.fromUri(testPath).existsSync()
+ ? testPath.toFilePath()
+ : Platform.script.resolve('../../../runtime/$path').toFilePath();
+}
void testStringLineSplitter() {
String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
diff --git a/tests/standalone/io/file_invalid_arguments_test.dart b/tests/standalone/io/file_invalid_arguments_test.dart
index 58c6d7c..335e574 100644
--- a/tests/standalone/io/file_invalid_arguments_test.dart
+++ b/tests/standalone/io/file_invalid_arguments_test.dart
@@ -99,7 +99,10 @@
}
String getFilename(String path) {
- return new File(path).existsSync() ? path : 'runtime/$path';
+ var testPath = Platform.script.resolve('../../../$path');
+ return new File.fromUri(testPath).existsSync()
+ ? testPath.toFilePath()
+ : Platform.script.resolve('../../../runtime/$path').toFilePath();
}
main() {
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 0ce18ae..633fe38 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -969,7 +969,7 @@
f.readAsString(encoding: UTF8).then((text) {
Expect.isTrue(text.endsWith("42 bytes."));
Expect.equals(42, text.length);
- var name = getDataFilename("tests/standalone/io/read_as_text.dat");
+ var name = getFilename("tests/standalone/io/read_as_text.dat");
var f = new File(name);
f.readAsString(encoding: UTF8).then((text) {
Expect.equals(6, text.length);
@@ -1006,7 +1006,7 @@
var text = new File(name).readAsStringSync();
Expect.isTrue(text.endsWith("42 bytes."));
Expect.equals(42, text.length);
- name = getDataFilename("tests/standalone/io/read_as_text.dat");
+ name = getFilename("tests/standalone/io/read_as_text.dat");
text = new File(name).readAsStringSync();
Expect.equals(6, text.length);
var expected = [955, 120, 46, 32, 120, 10];
@@ -1054,7 +1054,7 @@
var line = lines[0];
Expect.isTrue(line.endsWith("42 bytes."));
Expect.equals(42, line.length);
- name = getDataFilename("tests/standalone/io/readline_test1.dat");
+ name = getFilename("tests/standalone/io/readline_test1.dat");
lines = new File(name).readAsLinesSync();
Expect.equals(10, lines.length);
}
@@ -1274,11 +1274,12 @@
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
- static String getFilename(String path) =>
- new File(path).existsSync() ? path : 'runtime/$path';
-
- static String getDataFilename(String path) =>
- new File(path).existsSync() ? path : '../$path';
+ static String getFilename(String path) {
+ var testPath = Platform.script.resolve('../../../$path');
+ return new File.fromUri(testPath).existsSync()
+ ? testPath.toFilePath()
+ : Platform.script.resolve('../../../runtime/$path').toFilePath();
+ }
// Main test entrypoint.
static testMain() {
diff --git a/tests/standalone/io/platform_test.dart b/tests/standalone/io/platform_test.dart
index 5abdc0f..bf59383 100644
--- a/tests/standalone/io/platform_test.dart
+++ b/tests/standalone/io/platform_test.dart
@@ -67,6 +67,8 @@
}
main() {
+ // This tests assumes paths relative to dart main directory
+ Directory.current = Platform.script.resolve('../../..').toFilePath();
test();
testIsolate();
}
diff --git a/tests/standalone/io/read_into_const_list_test.dart b/tests/standalone/io/read_into_const_list_test.dart
index f010a83..3eb624a 100644
--- a/tests/standalone/io/read_into_const_list_test.dart
+++ b/tests/standalone/io/read_into_const_list_test.dart
@@ -8,8 +8,13 @@
import "package:expect/expect.dart";
import "dart:io";
-String getFilename(String path) =>
- new File(path).existsSync() ? path : 'runtime/$path';
+String getFilename(String path) {
+ var testPath = Platform.script.resolve('../../../$path');
+ return new File.fromUri(testPath).existsSync()
+ ? testPath.toFilePath()
+ : Platform.script.resolve('../../../runtime/$path').toFilePath();
+}
+
void main() {
var a = const [0];
diff --git a/tools/VERSION b/tools/VERSION
index b1ada01..dacd602 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 9
PATCH 0
-PRERELEASE 6
+PRERELEASE 7
PRERELEASE_PATCH 0
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index f4bb124..91d385e 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -57,6 +57,7 @@
'Document.createNodeIterator',
'Document.createTreeWalker',
'DOMException.name',
+ 'DOMException.toString',
'Element.createShadowRoot',
'Element.insertAdjacentElement',
'Element.insertAdjacentHTML',
@@ -67,6 +68,8 @@
'ElementEvents.mouseWheel',
'ElementEvents.transitionEnd',
'FileReader.result',
+ 'HTMLAnchorElement.toString',
+ 'HTMLAreaElement.toString',
'HTMLTableElement.createTBody',
'IDBCursor.next',
'IDBDatabase.transaction',
@@ -75,6 +78,7 @@
'IDBDatabase.transactionStores',
'KeyboardEvent.initKeyboardEvent',
'Location.origin',
+ 'Location.toString',
'MouseEvent.offsetX',
'MouseEvent.offsetY',
'Navigator.language',
@@ -85,6 +89,7 @@
'URL.createObjectUrlFromStream',
'URL.createObjectUrlFromBlob',
'URL.revokeObjectURL',
+ 'URL.toString',
'WheelEvent.deltaMode',
'WheelEvent.wheelDeltaX',
'WheelEvent.wheelDeltaY',
diff --git a/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate b/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate
new file mode 100644
index 0000000..fb6ff5f
--- /dev/null
+++ b/tools/dom/templates/html/dart2js/impl_HTMLAnchorElement.darttemplate
@@ -0,0 +1,14 @@
+// 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.
+
+part of $LIBRARYNAME;
+
+@DocsEditable()
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$MIXINS$IMPLEMENTS {
+$!MEMBERS
+
+ @DomName('HTMLAnchorElement.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+}
diff --git a/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate b/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate
new file mode 100644
index 0000000..df3fdd6
--- /dev/null
+++ b/tools/dom/templates/html/dart2js/impl_HTMLAreaElement.darttemplate
@@ -0,0 +1,14 @@
+// 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.
+
+part of $LIBRARYNAME;
+
+@DocsEditable()
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$MIXINS$IMPLEMENTS {
+$!MEMBERS
+
+ @DomName('HTMLAreaElement.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+}
diff --git a/tools/dom/templates/html/dart2js/impl_URL.darttemplate b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
index d8c8a75..1e14cca 100644
--- a/tools/dom/templates/html/dart2js/impl_URL.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
@@ -23,5 +23,10 @@
static void revokeObjectUrl(String url) =>
JS('void',
'(self.URL || self.webkitURL).revokeObjectURL(#)', url);
+
+ @DomName('URL.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index db97f86..be8c36c 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -41,4 +41,9 @@
}
$endif
$!MEMBERS
+$if DART2JS
+ @DomName('DOMException.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+$endif
}
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index f263b29..22de38f 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -813,7 +813,13 @@
@DomName('Element.localName')
@DocsEditable()
+$if DART2JS
+ @Returns('String')
+ // Non-null for Elements.
+ String get localName => JS('String', '#', _localName);
+$else
String get localName => _localName;
+$endif
/**
* A URI that identifies the XML namespace of this element.
diff --git a/tools/dom/templates/html/impl/impl_Location.darttemplate b/tools/dom/templates/html/impl/impl_Location.darttemplate
index d663fcd..f69d929 100644
--- a/tools/dom/templates/html/impl/impl_Location.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Location.darttemplate
@@ -17,4 +17,10 @@
return '${this.protocol}//${this.host}';
}
$endif
+
+$if DART2JS
+ @DomName('Location.toString')
+ @DocsEditable()
+ String toString() => JS('String', 'String(#)', this);
+$endif
}
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 8307149..166c346 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -272,6 +272,9 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => nodeValue == null ? super.toString() : nodeValue;
+ String toString() {
+ String value = nodeValue; // Fetch DOM Node property once.
+ return value == null ? super.toString() : value;
+ }
$!MEMBERS
}
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 1bdf34e..1bdd0c7 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -943,8 +943,10 @@
}
bool get hasCrashed {
- // The Java dartc runner and dart2js exits with code 253 in case
- // of unhandled exceptions.
+ // dart2js exits with code 253 in case of unhandled exceptions.
+ // The dart binary exits with code 253 in case of an API error such
+ // as an invalid snapshot file.
+ // In either case an exit code of 253 is considered a crash.
if (exitCode == 253) return true;
if (io.Platform.operatingSystem == 'windows') {
// The VM uses std::abort to terminate on asserts.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index b29c3f0..b7aaedb 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1551,17 +1551,8 @@
List<String> dartOptions = optionsFromFile["dartOptions"];
assert(!isMultitest || dartOptions == null);
- if (dartOptions == null) {
- args.add(filePath.toNativePath());
- } else {
- var executable_name = dartOptions[0];
- // TODO(ager): Get rid of this hack when the runtime checkout goes away.
- var file = new File(executable_name);
- if (!file.existsSync()) {
- executable_name = '../$executable_name';
- assert(new File(executable_name).existsSync());
- dartOptions[0] = executable_name;
- }
+ args.add(filePath.toNativePath());
+ if (dartOptions != null) {
args.addAll(dartOptions);
}