Version 1.0.3.0
svn merge -r 30767:30923 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@30939 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 06e0a05..b9be96f 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -895,6 +895,8 @@
*/
SimpleIdentifier get identifier => _identifier;
+ int get precedence => 15;
+
/**
* Set the identifier representing the argument being tested to the given identifier.
*
@@ -1163,6 +1165,8 @@
*/
Expression get expression => _expression;
+ int get precedence => 7;
+
/**
* Return the name of the type being cast to.
*
@@ -1376,6 +1380,8 @@
*/
Expression get leftHandSide => _leftHandSide;
+ int get precedence => 1;
+
/**
* Return the element associated with the operator based on the propagated type of the
* left-hand-side, or `null` if the AST structure has not been resolved, if the operator is
@@ -1580,6 +1586,8 @@
*/
Expression get leftOperand => _leftOperand;
+ int get precedence => operator.type.precedence;
+
/**
* Return the element associated with the operator based on the propagated type of the left
* operand, or `null` if the AST structure has not been resolved, if the operator is not
@@ -1997,6 +2005,8 @@
Token get endToken => cascadeSections.endToken;
+ int get precedence => 2;
+
/**
* Return the target of the cascade sections.
*
@@ -3198,6 +3208,8 @@
Token get endToken => _elseExpression.endToken;
+ int get precedence => 3;
+
/**
* Return the expression that is executed if the condition evaluates to `true`.
*
@@ -4511,7 +4523,7 @@
* @coverage dart.engine.ast
*/
class EphemeralIdentifier extends SimpleIdentifier {
- EphemeralIdentifier.full(ASTNode parent, int location) : super.full(new Token(TokenType.IDENTIFIER, location)) {
+ EphemeralIdentifier.full(ASTNode parent, int location) : super.full(new StringToken(TokenType.IDENTIFIER, "", location)) {
parent.becomeParentOf(this);
}
@@ -4628,6 +4640,19 @@
}
/**
+ * Return the precedence of this expression. The precedence is a positive integer value that
+ * defines how the source code is parsed into an AST. For example `a * b + c` is parsed as
+ * `(a * b) + c` because the precedence of `*` is greater than the precedence of
+ * `+`.
+ *
+ * You should not assume that returned values will stay the same, they might change as result of
+ * specification change. Only relative order should be used.
+ *
+ * @return the precedence of this expression
+ */
+ int get precedence;
+
+ /**
* If this expression is an argument to an invocation, and the AST structure has been resolved,
* and the function being invoked is known based on propagated type information, and this
* expression corresponds to one of the parameters of the function being invoked, then return the
@@ -6110,6 +6135,8 @@
*/
FormalParameterList get parameters => _parameters;
+ int get precedence => 16;
+
/**
* Set the body of the function to the given function body.
*
@@ -6226,6 +6253,8 @@
*/
Expression get function => _function;
+ int get precedence => 15;
+
/**
* Return the element associated with the function being invoked based on propagated type
* information, or `null` if the AST structure has not been resolved or the function could
@@ -7153,6 +7182,8 @@
*/
Token get leftBracket => _leftBracket;
+ int get precedence => 15;
+
/**
* Return the element associated with the operator based on the propagated type of the target, or
* `null` if the AST structure has not been resolved or if the operator could not be
@@ -7437,6 +7468,8 @@
Token get endToken => _argumentList.endToken;
+ int get precedence => 15;
+
/**
* Return `true` if this creation expression is used to invoke a constant constructor.
*
@@ -7768,6 +7801,8 @@
*/
Expression get expression => _expression;
+ int get precedence => 7;
+
/**
* Return the name of the type being tested for.
*
@@ -8079,6 +8114,8 @@
return builder.toString();
}
+ int get precedence => 15;
+
Element get propagatedElement => null;
Element get staticElement => null;
@@ -8215,6 +8252,7 @@
* @coverage dart.engine.ast
*/
abstract class Literal extends Expression {
+ int get precedence => 16;
}
/**
@@ -8751,6 +8789,8 @@
*/
SimpleIdentifier get methodName => _methodName;
+ int get precedence => 15;
+
/**
* Return the expression used to compute the receiver of the invocation. If this invocation is not
* part of a cascade expression, then this is the same as [getTarget]. If this invocation
@@ -8903,6 +8943,8 @@
*/
Label get name => _name;
+ int get precedence => 0;
+
/**
* Set the expression with which the name is associated to the given expression.
*
@@ -9356,6 +9398,8 @@
*/
Token get leftParenthesis => _leftParenthesis;
+ int get precedence => 15;
+
/**
* Return the right parenthesis.
*
@@ -9625,6 +9669,8 @@
*/
Expression get operand => _operand;
+ int get precedence => 15;
+
/**
* Return the element associated with the operator based on the propagated type of the operand, or
* `null` if the AST structure has not been resolved, if the operator is not user definable,
@@ -9804,6 +9850,8 @@
*/
Expression get operand => _operand;
+ int get precedence => 14;
+
/**
* Return the element associated with the operator based on the propagated type of the operand, or
* `null` if the AST structure has not been resolved, if the operator is not user definable,
@@ -9972,6 +10020,8 @@
String get name => "${_prefix.name}.${_identifier.name}";
+ int get precedence => 15;
+
/**
* Return the prefix associated with the library in which the identifier is defined.
*
@@ -10081,6 +10131,8 @@
Token get endToken => _propertyName.endToken;
+ int get precedence => 15;
+
/**
* Return the name of the property being accessed.
*
@@ -10306,6 +10358,8 @@
Token get endToken => keyword;
+ int get precedence => 0;
+
void visitChildren(ASTVisitor visitor) {
}
}
@@ -10635,6 +10689,8 @@
String get name => token.lexeme;
+ int get precedence => 16;
+
Element get propagatedElement => _propagatedElement;
Element get staticElement => _staticElement;
@@ -11199,6 +11255,8 @@
Token get endToken => keyword;
+ int get precedence => 16;
+
void visitChildren(ASTVisitor visitor) {
}
}
@@ -11580,6 +11638,8 @@
Token get endToken => keyword;
+ int get precedence => 16;
+
void visitChildren(ASTVisitor visitor) {
}
}
@@ -11642,6 +11702,8 @@
*/
Expression get expression => _expression;
+ int get precedence => 0;
+
/**
* Set the expression computing the exception to be thrown to the given expression.
*
@@ -15888,9 +15950,10 @@
}
List clone3(NodeList nodes) {
+ int count = nodes.length;
List clonedNodes = new List();
- for (ASTNode node in nodes) {
- clonedNodes.add(node.accept(this) as ASTNode);
+ for (int i = 0; i < count; i++) {
+ clonedNodes.add((nodes[i]).accept(this) as ASTNode);
}
return clonedNodes;
}
@@ -15908,7 +15971,7 @@
* @param second the second node being compared
* @return `true` if the two AST nodes are equal
*/
- static bool equals3(CompilationUnit first, CompilationUnit second) {
+ static bool equals4(CompilationUnit first, CompilationUnit second) {
ASTComparator comparator = new ASTComparator();
return comparator.isEqual(first, second);
}
@@ -16176,7 +16239,7 @@
bool visitIntegerLiteral(IntegerLiteral node) {
IntegerLiteral other = this._other as IntegerLiteral;
- return isEqual6(node.literal, other.literal) && identical(node.value, other.value);
+ return isEqual6(node.literal, other.literal) && (node.value == other.value);
}
bool visitInterpolationExpression(InterpolationExpression node) {
@@ -16331,7 +16394,7 @@
bool visitSimpleStringLiteral(SimpleStringLiteral node) {
SimpleStringLiteral other = this._other as SimpleStringLiteral;
- return isEqual6(node.literal, other.literal) && identical(node.value, other.value);
+ return isEqual6(node.literal, other.literal) && (node.value == other.value);
}
bool visitStringInterpolation(StringInterpolation node) {
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index b616ffe..965bcbd 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -606,7 +606,7 @@
tails = new Set<N>();
_edges[head] = tails;
}
- javaSetAdd(tails, tail);
+ tails.add(tail);
}
/**
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index ce01e2f..c024cc0 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -182,6 +182,13 @@
bool get isAbstract;
/**
+ * Return `true` if this element has an annotation of the form '@proxy'.
+ *
+ * @return `true` if this element defines a proxy
+ */
+ bool get isProxy;
+
+ /**
* Return `true` if this class is defined by a typedef construct.
*
* @return `true` if this class is defined by a typedef construct
@@ -408,6 +415,11 @@
*/
abstract class Element {
/**
+ * An Unicode right arrow.
+ */
+ static final String RIGHT_ARROW = " \u2192 ";
+
+ /**
* A comparator that can be used to sort elements by their name offset. Elements with a smaller
* offset will be sorted to be before elements with a larger name offset.
*/
@@ -574,6 +586,31 @@
* @return the field, variable, or constructor being used as an annotation
*/
Element get element;
+
+ /**
+ * Return `true` if this annotation marks the associated element as being deprecated.
+ *
+ * @return `true` if this annotation marks the associated element as being deprecated
+ */
+ bool get isDeprecated;
+
+ /**
+ * Return `true` if this annotation marks the associated method as being expected to
+ * override an inherited method.
+ *
+ * @return `true` if this annotation marks the associated method as overriding another
+ * method
+ */
+ bool get isOverride;
+
+ /**
+ * Return `true` if this annotation marks the associated class as implementing a proxy
+ * object.
+ *
+ * @return `true` if this annotation marks the associated class as implementing a proxy
+ * object
+ */
+ bool get isProxy;
}
/**
@@ -2102,7 +2139,7 @@
classesToVisit.add(this);
while (!classesToVisit.isEmpty) {
ClassElement currentElement = classesToVisit.removeAt(0);
- if (javaSetAdd(visitedClasses, currentElement)) {
+ if (visitedClasses.add(currentElement)) {
for (FieldElement field in currentElement.fields) {
if (!field.isFinal && !field.isConst && !field.isStatic && !field.isSynthetic) {
return true;
@@ -2128,6 +2165,15 @@
bool get isAbstract => hasModifier(Modifier.ABSTRACT);
+ bool get isProxy {
+ for (ElementAnnotation annotation in metadata) {
+ if (annotation.isProxy) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool get isTypedef => hasModifier(Modifier.TYPEDEF);
bool get isValidMixin => hasModifier(Modifier.MIXIN);
@@ -2136,7 +2182,7 @@
Set<ClassElement> visitedClasses = new Set<ClassElement>();
ClassElement currentElement = this;
while (currentElement != null && !visitedClasses.contains(currentElement)) {
- javaSetAdd(visitedClasses, currentElement);
+ visitedClasses.add(currentElement);
PropertyAccessorElement element = currentElement.getGetter(getterName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -2163,7 +2209,7 @@
Set<ClassElement> visitedClasses = new Set<ClassElement>();
ClassElement currentElement = this;
while (currentElement != null && !visitedClasses.contains(currentElement)) {
- javaSetAdd(visitedClasses, currentElement);
+ visitedClasses.add(currentElement);
MethodElement element = currentElement.getMethod(methodName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -2190,7 +2236,7 @@
Set<ClassElement> visitedClasses = new Set<ClassElement>();
ClassElement currentElement = this;
while (currentElement != null && !visitedClasses.contains(currentElement)) {
- javaSetAdd(visitedClasses, currentElement);
+ visitedClasses.add(currentElement);
PropertyAccessorElement element = currentElement.getSetter(setterName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -2886,6 +2932,27 @@
static List<ElementAnnotationImpl> EMPTY_ARRAY = new List<ElementAnnotationImpl>(0);
/**
+ * The name of the class used to mark an element as being deprecated.
+ */
+ static String _DEPRECATED_CLASS_NAME = "Deprecated";
+
+ /**
+ * The name of the top-level variable used to mark an element as being deprecated.
+ */
+ static String _DEPRECATED_VARIABLE_NAME = "deprecated";
+
+ /**
+ * The name of the top-level variable used to mark a method as being expected to override an
+ * inherited method.
+ */
+ static String _OVERRIDE_VARIABLE_NAME = "override";
+
+ /**
+ * The name of the top-level variable used to mark a class as implementing a proxy object.
+ */
+ static String _PROXY_VARIABLE_NAME = "proxy";
+
+ /**
* Initialize a newly created annotation.
*
* @param element the element representing the field, variable, or constructor being used as an
@@ -2897,6 +2964,47 @@
Element get element => _element;
+ bool get isDeprecated {
+ if (_element != null) {
+ LibraryElement library = _element.library;
+ if (library != null && library.isDartCore) {
+ if (_element is ConstructorElement) {
+ ConstructorElement constructorElement = _element as ConstructorElement;
+ if (constructorElement.enclosingElement.name == _DEPRECATED_CLASS_NAME) {
+ return true;
+ }
+ } else if (_element is PropertyAccessorElement && _element.name == _DEPRECATED_VARIABLE_NAME) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool get isOverride {
+ if (_element != null) {
+ LibraryElement library = _element.library;
+ if (library != null && library.isDartCore) {
+ if (_element is PropertyAccessorElement && _element.name == _OVERRIDE_VARIABLE_NAME) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool get isProxy {
+ if (_element != null) {
+ LibraryElement library = _element.library;
+ if (library != null && library.isDartCore) {
+ if (_element is PropertyAccessorElement && _element.name == _PROXY_VARIABLE_NAME) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
String toString() => "@${_element.toString()}";
}
@@ -3037,19 +3145,8 @@
bool get isDeprecated {
for (ElementAnnotation annotation in _metadata) {
- Element element = annotation.element;
- if (element != null) {
- LibraryElement lib = element.library;
- if (lib != null && lib.isDartCore) {
- if (element is ConstructorElement) {
- ConstructorElement constructorElement = element as ConstructorElement;
- if (constructorElement.enclosingElement.name == "Deprecated") {
- return true;
- }
- } else if (element is PropertyAccessorElement && element.name == "deprecated") {
- return true;
- }
- }
+ if (annotation.isDeprecated) {
+ return true;
}
}
return false;
@@ -3578,7 +3675,7 @@
}
builder.append(")");
if (_type != null) {
- builder.append(" -> ");
+ builder.append(Element.RIGHT_ARROW);
builder.append(_type.returnType);
}
}
@@ -3819,6 +3916,45 @@
accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
+ /**
+ * Treating the set of arrays defined in [ExecutableElementImpl] as one long array, this
+ * returns the index position of the passed child in this [FunctionElement]. This gives a
+ * unique integer for each element, this is provided primarily for function elements that do not
+ * have a name (closures), which cannot use [Element#getNameOffset]. If there is no such
+ * element, `-1` is returned.
+ *
+ * @param element the element to find and return an integer for, if there is no such element,
+ * `-1` is returned
+ */
+ int getIndexPosition(Element element) {
+ List<FunctionElement> functions = this.functions;
+ List<LabelElement> labels = this.labels;
+ List<LocalVariableElement> localVariables = this.localVariables;
+ List<ParameterElement> parameters = this.parameters;
+ int count = 0;
+ for (int i = 0; i < functions.length; i++, count++) {
+ if (identical(element, functions[i])) {
+ return count;
+ }
+ }
+ for (int i = 0; i < labels.length; i++, count++) {
+ if (identical(element, labels[i])) {
+ return count;
+ }
+ }
+ for (int i = 0; i < localVariables.length; i++, count++) {
+ if (identical(element, localVariables[i])) {
+ return count;
+ }
+ }
+ for (int i = 0; i < parameters.length; i++, count++) {
+ if (identical(element, parameters[i])) {
+ return count;
+ }
+ }
+ return -1;
+ }
+
ElementKind get kind => ElementKind.FUNCTION;
SourceRange get visibleRange {
@@ -4017,7 +4153,7 @@
}
builder.append(")");
if (_type != null) {
- builder.append(" -> ");
+ builder.append(Element.RIGHT_ARROW);
builder.append(_type.returnType);
}
}
@@ -4371,7 +4507,7 @@
*/
static bool isUpToDate(LibraryElement library, int timeStamp, Set<LibraryElement> visitedLibraries) {
if (!visitedLibraries.contains(library)) {
- javaSetAdd(visitedLibraries, library);
+ visitedLibraries.add(library);
if (timeStamp < library.definingCompilationUnit.source.modificationStamp) {
return false;
}
@@ -4472,7 +4608,7 @@
for (ExportElement element in _exports) {
LibraryElement library = element.exportedLibrary;
if (library != null) {
- javaSetAdd(libraries, library);
+ libraries.add(library);
}
}
return new List.from(libraries);
@@ -4485,7 +4621,7 @@
for (ImportElement element in _imports) {
LibraryElement library = element.importedLibrary;
if (library != null) {
- javaSetAdd(libraries, library);
+ libraries.add(library);
}
}
return new List.from(libraries);
@@ -4504,7 +4640,7 @@
for (ImportElement element in _imports) {
PrefixElement prefix = element.prefix;
if (prefix != null) {
- javaSetAdd(prefixes, prefix);
+ prefixes.add(prefix);
}
}
return new List.from(prefixes);
@@ -4896,10 +5032,10 @@
static void add(Set<Element> elements, Element element) {
if (element is MultiplyDefinedElementImpl) {
for (Element conflictingElement in (element as MultiplyDefinedElementImpl)._conflictingElements) {
- javaSetAdd(elements, conflictingElement);
+ elements.add(conflictingElement);
}
} else {
- javaSetAdd(elements, element);
+ elements.add(element);
}
}
@@ -5806,7 +5942,7 @@
}
builder.append(")");
if (type != null) {
- builder.append(" -> ");
+ builder.append(Element.RIGHT_ARROW);
builder.append(type.returnType);
}
return builder.toString();
@@ -5873,6 +6009,24 @@
}
/**
+ * Instances of the class `FieldFormalParameterMember` represent a parameter element defined
+ * in a parameterized type where the values of the type parameters are known.
+ */
+class FieldFormalParameterMember extends ParameterMember implements FieldFormalParameterElement {
+ /**
+ * Initialize a newly created element to represent a parameter of the given parameterized type.
+ *
+ * @param baseElement the element on which the parameterized element was created
+ * @param definingType the type in which the element is defined
+ */
+ FieldFormalParameterMember(FieldFormalParameterElement baseElement, ParameterizedType definingType) : super(baseElement, definingType);
+
+ accept(ElementVisitor visitor) => visitor.visitFieldFormalParameterElement(this);
+
+ FieldElement get field => (baseElement as FieldFormalParameterElement).field;
+}
+
+/**
* Instances of the class `FieldMember` represent a field element defined in a parameterized
* type where the values of the type parameters are known.
*/
@@ -6119,7 +6273,7 @@
}
builder.append(")");
if (type != null) {
- builder.append(" -> ");
+ builder.append(Element.RIGHT_ARROW);
builder.append(type.returnType);
}
return builder.toString();
@@ -6146,7 +6300,8 @@
if (baseParameter == null || definingType.typeArguments.length == 0) {
return baseParameter;
}
- if (baseParameter is! FieldFormalParameterElement) {
+ bool isFieldFormal = baseParameter is FieldFormalParameterElement;
+ if (!isFieldFormal) {
Type2 baseType = baseParameter.type;
List<Type2> argumentTypes = definingType.typeArguments;
List<Type2> parameterTypes = TypeParameterTypeImpl.getTypes(definingType.typeParameters);
@@ -6155,6 +6310,9 @@
return baseParameter;
}
}
+ if (isFieldFormal) {
+ return new FieldFormalParameterMember(baseParameter as FieldFormalParameterElement, definingType);
+ }
return new ParameterMember(baseParameter, definingType);
}
@@ -6324,7 +6482,7 @@
}
builder.append(")");
if (type != null) {
- builder.append(" -> ");
+ builder.append(Element.RIGHT_ARROW);
builder.append(type.returnType);
}
return builder.toString();
@@ -6386,13 +6544,13 @@
bool get isBottom => true;
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) => true;
-
- bool isSubtypeOf(Type2 type) => true;
-
bool isSupertypeOf(Type2 type) => false;
BottomTypeImpl substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) => this;
+
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) => true;
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
}
/**
@@ -6417,15 +6575,6 @@
bool get isDynamic => true;
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
- if (identical(this, type)) {
- return true;
- }
- return withDynamic;
- }
-
- bool isSubtypeOf(Type2 type) => true;
-
bool isSupertypeOf(Type2 type) => true;
Type2 substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) {
@@ -6437,6 +6586,15 @@
}
return this;
}
+
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+ if (identical(this, type)) {
+ return true;
+ }
+ return withDynamic;
+ }
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
}
/**
@@ -6557,7 +6715,8 @@
builder.append("}");
needsComma = true;
}
- builder.append(") -> ");
+ builder.append(")");
+ builder.append(Element.RIGHT_ARROW);
if (returnType == null) {
builder.append("null");
} else {
@@ -6656,9 +6815,7 @@
return element.hashCode;
}
- bool isAssignableTo(Type2 type) => this.isSubtypeOf(type);
-
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
if (type == null) {
return false;
} else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
@@ -6682,7 +6839,7 @@
return false;
} else if (t.normalParameterTypes.length > 0) {
for (int i = 0; i < tTypes.length; i++) {
- if (!tTypes[i].isMoreSpecificThan3(sTypes[i], withDynamic)) {
+ if (!(tTypes[i] as TypeImpl).isMoreSpecificThan3(sTypes[i], withDynamic, visitedTypePairs)) {
return false;
}
}
@@ -6699,7 +6856,7 @@
if (typeT == null) {
return false;
}
- if (!typeT.isMoreSpecificThan3(entryS.getValue(), withDynamic)) {
+ if (!(typeT as TypeImpl).isMoreSpecificThan3(entryS.getValue(), withDynamic, visitedTypePairs)) {
return false;
}
}
@@ -6713,7 +6870,7 @@
}
if (tOpTypes.length == 0 && sOpTypes.length == 0) {
for (int i = 0; i < sTypes.length; i++) {
- if (!tTypes[i].isMoreSpecificThan3(sTypes[i], withDynamic)) {
+ if (!(tTypes[i] as TypeImpl).isMoreSpecificThan3(sTypes[i], withDynamic, visitedTypePairs)) {
return false;
}
}
@@ -6733,7 +6890,7 @@
sAllTypes[i] = sOpTypes[j];
}
for (int i = 0; i < sAllTypes.length; i++) {
- if (!tAllTypes[i].isMoreSpecificThan3(sAllTypes[i], withDynamic)) {
+ if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan3(sAllTypes[i], withDynamic, visitedTypePairs)) {
return false;
}
}
@@ -6741,94 +6898,10 @@
}
Type2 tRetType = t.returnType;
Type2 sRetType = s.returnType;
- return sRetType.isVoid || tRetType.isMoreSpecificThan3(sRetType, withDynamic);
+ return sRetType.isVoid || (tRetType as TypeImpl).isMoreSpecificThan3(sRetType, withDynamic, visitedTypePairs);
}
- bool isSubtypeOf(Type2 type) {
- if (type == null) {
- return false;
- } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
- return true;
- } else if (type is! FunctionType) {
- return false;
- } else if (this == type) {
- return true;
- }
- FunctionType t = this;
- FunctionType s = type as FunctionType;
- List<Type2> tTypes = t.normalParameterTypes;
- List<Type2> tOpTypes = t.optionalParameterTypes;
- List<Type2> sTypes = s.normalParameterTypes;
- List<Type2> sOpTypes = s.optionalParameterTypes;
- if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
- return false;
- }
- if (t.namedParameterTypes.length > 0) {
- if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
- return false;
- } else if (t.normalParameterTypes.length > 0) {
- for (int i = 0; i < tTypes.length; i++) {
- if (!tTypes[i].isAssignableTo(sTypes[i])) {
- return false;
- }
- }
- }
- Map<String, Type2> namedTypesT = t.namedParameterTypes;
- Map<String, Type2> namedTypesS = s.namedParameterTypes;
- if (namedTypesT.length < namedTypesS.length) {
- return false;
- }
- JavaIterator<MapEntry<String, Type2>> iteratorS = new JavaIterator(getMapEntrySet(namedTypesS));
- while (iteratorS.hasNext) {
- MapEntry<String, Type2> entryS = iteratorS.next();
- Type2 typeT = namedTypesT[entryS.getKey()];
- if (typeT == null) {
- return false;
- }
- if (!typeT.isAssignableTo(entryS.getValue())) {
- return false;
- }
- }
- } else if (s.namedParameterTypes.length > 0) {
- return false;
- } else {
- int tArgLength = tTypes.length + tOpTypes.length;
- int sArgLength = sTypes.length + sOpTypes.length;
- if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
- return false;
- }
- if (tOpTypes.length == 0 && sOpTypes.length == 0) {
- for (int i = 0; i < sTypes.length; i++) {
- if (!tTypes[i].isAssignableTo(sTypes[i])) {
- return false;
- }
- }
- } else {
- List<Type2> tAllTypes = new List<Type2>(sArgLength);
- for (int i = 0; i < tTypes.length; i++) {
- tAllTypes[i] = tTypes[i];
- }
- for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
- tAllTypes[i] = tOpTypes[j];
- }
- List<Type2> sAllTypes = new List<Type2>(sArgLength);
- for (int i = 0; i < sTypes.length; i++) {
- sAllTypes[i] = sTypes[i];
- }
- for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
- sAllTypes[i] = sOpTypes[j];
- }
- for (int i = 0; i < sAllTypes.length; i++) {
- if (!tAllTypes[i].isAssignableTo(sAllTypes[i])) {
- return false;
- }
- }
- }
- }
- Type2 tRetType = t.returnType;
- Type2 sRetType = s.returnType;
- return sRetType.isVoid || tRetType.isAssignableTo(sRetType);
- }
+ bool isAssignableTo(Type2 type) => isSubtypeOf3(type, new Set<TypeImpl_TypePair>());
/**
* Set the actual types of the type arguments to the given types.
@@ -6907,7 +6980,8 @@
builder.append("}");
needsComma = true;
}
- builder.append(") -> ");
+ builder.append(")");
+ builder.append(Element.RIGHT_ARROW);
if (returnType == null) {
builder.append("null");
} else {
@@ -6927,6 +7001,92 @@
}
}
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+ if (type == null) {
+ return false;
+ } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
+ return true;
+ } else if (type is! FunctionType) {
+ return false;
+ } else if (this == type) {
+ return true;
+ }
+ FunctionType t = this;
+ FunctionType s = type as FunctionType;
+ List<Type2> tTypes = t.normalParameterTypes;
+ List<Type2> tOpTypes = t.optionalParameterTypes;
+ List<Type2> sTypes = s.normalParameterTypes;
+ List<Type2> sOpTypes = s.optionalParameterTypes;
+ if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
+ return false;
+ }
+ if (t.namedParameterTypes.length > 0) {
+ if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+ return false;
+ } else if (t.normalParameterTypes.length > 0) {
+ for (int i = 0; i < tTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isAssignableTo2(sTypes[i], visitedTypePairs)) {
+ return false;
+ }
+ }
+ }
+ Map<String, Type2> namedTypesT = t.namedParameterTypes;
+ Map<String, Type2> namedTypesS = s.namedParameterTypes;
+ if (namedTypesT.length < namedTypesS.length) {
+ return false;
+ }
+ JavaIterator<MapEntry<String, Type2>> iteratorS = new JavaIterator(getMapEntrySet(namedTypesS));
+ while (iteratorS.hasNext) {
+ MapEntry<String, Type2> entryS = iteratorS.next();
+ Type2 typeT = namedTypesT[entryS.getKey()];
+ if (typeT == null) {
+ return false;
+ }
+ if (!(typeT as TypeImpl).isAssignableTo2(entryS.getValue(), visitedTypePairs)) {
+ return false;
+ }
+ }
+ } else if (s.namedParameterTypes.length > 0) {
+ return false;
+ } else {
+ int tArgLength = tTypes.length + tOpTypes.length;
+ int sArgLength = sTypes.length + sOpTypes.length;
+ if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
+ return false;
+ }
+ if (tOpTypes.length == 0 && sOpTypes.length == 0) {
+ for (int i = 0; i < sTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isAssignableTo2(sTypes[i], visitedTypePairs)) {
+ return false;
+ }
+ }
+ } else {
+ List<Type2> tAllTypes = new List<Type2>(sArgLength);
+ for (int i = 0; i < tTypes.length; i++) {
+ tAllTypes[i] = tTypes[i];
+ }
+ for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
+ tAllTypes[i] = tOpTypes[j];
+ }
+ List<Type2> sAllTypes = new List<Type2>(sArgLength);
+ for (int i = 0; i < sTypes.length; i++) {
+ sAllTypes[i] = sTypes[i];
+ }
+ for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
+ sAllTypes[i] = sOpTypes[j];
+ }
+ for (int i = 0; i < sAllTypes.length; i++) {
+ if (!(tAllTypes[i] as TypeImpl).isAssignableTo2(sAllTypes[i], visitedTypePairs)) {
+ return false;
+ }
+ }
+ }
+ }
+ Type2 tRetType = t.returnType;
+ Type2 sRetType = s.returnType;
+ return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo2(sRetType, visitedTypePairs);
+ }
+
/**
* Return the return type defined by this function's element.
*
@@ -6994,7 +7154,7 @@
}
int longestPath = 1;
try {
- javaSetAdd(visitedClasses, classElement);
+ visitedClasses.add(classElement);
List<InterfaceType> superinterfaces = classElement.interfaces;
int pathLength;
if (superinterfaces.length > 0) {
@@ -7032,13 +7192,13 @@
ClassElement classElement = element as ClassElement;
List<InterfaceType> superinterfaces = classElement.interfaces;
for (InterfaceType superinterface in superinterfaces) {
- if (javaSetAdd(set, superinterface)) {
+ if (set.add(superinterface)) {
computeSuperinterfaceSet2(superinterface, set);
}
}
InterfaceType supertype = classElement.supertype;
if (supertype != null) {
- if (javaSetAdd(set, supertype)) {
+ if (set.add(supertype)) {
computeSuperinterfaceSet2(supertype, set);
}
}
@@ -7066,7 +7226,7 @@
for (InterfaceType secondType in second) {
InterfaceType firstType = firstMap[secondType.element];
if (firstType != null) {
- javaSetAdd(result, leastUpperBound(firstType, secondType));
+ result.add(leastUpperBound(firstType, secondType));
}
}
return new List.from(result);
@@ -7205,8 +7365,8 @@
InterfaceType j = type as InterfaceType;
Set<InterfaceType> si = computeSuperinterfaceSet(i);
Set<InterfaceType> sj = computeSuperinterfaceSet(j);
- javaSetAdd(si, i);
- javaSetAdd(sj, j);
+ si.add(i);
+ sj.add(j);
List<InterfaceType> s = intersection(si, sj);
List<int> depths = new List<int>.filled(s.length, 0);
int maxDepth = 0;
@@ -7319,37 +7479,8 @@
return false;
}
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
- if (identical(type, DynamicTypeImpl.instance)) {
- return true;
- } else if (type is! InterfaceType) {
- return false;
- }
- return isMoreSpecificThan2(type as InterfaceType, new Set<ClassElement>(), withDynamic);
- }
-
bool get isObject => element.supertype == null;
- bool isSubtypeOf(Type2 type) {
- if (identical(type, DynamicTypeImpl.instance)) {
- return true;
- } else if (type is TypeParameterType) {
- return true;
- } else if (type is FunctionType) {
- ClassElement element = this.element;
- MethodElement callMethod = element.lookUpMethod("call", element.library);
- if (callMethod != null) {
- return callMethod.type.isSubtypeOf(type);
- }
- return false;
- } else if (type is! InterfaceType) {
- return false;
- } else if (this == type) {
- return true;
- }
- return isSubtypeOf2(type as InterfaceType, new Set<ClassElement>());
- }
-
ConstructorElement lookUpConstructor(String constructorName, LibraryElement library) {
ConstructorElement constructorElement;
if (constructorName == null) {
@@ -7382,7 +7513,7 @@
InterfaceType supertype = superclass;
ClassElement supertypeElement = supertype == null ? null : supertype.element;
while (supertype != null && !visitedClasses.contains(supertypeElement)) {
- javaSetAdd(visitedClasses, supertypeElement);
+ visitedClasses.add(supertypeElement);
PropertyAccessorElement element = supertype.getGetter(getterName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -7418,7 +7549,7 @@
InterfaceType supertype = superclass;
ClassElement supertypeElement = supertype == null ? null : supertype.element;
while (supertype != null && !visitedClasses.contains(supertypeElement)) {
- javaSetAdd(visitedClasses, supertypeElement);
+ visitedClasses.add(supertypeElement);
MethodElement element = supertype.getMethod(methodName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -7454,7 +7585,7 @@
InterfaceType supertype = superclass;
ClassElement supertypeElement = supertype == null ? null : supertype.element;
while (supertype != null && !visitedClasses.contains(supertypeElement)) {
- javaSetAdd(visitedClasses, supertypeElement);
+ visitedClasses.add(supertypeElement);
PropertyAccessorElement element = supertype.getSetter(setterName);
if (element != null && element.isAccessibleIn(library)) {
return element;
@@ -7513,7 +7644,36 @@
}
}
- bool isMoreSpecificThan2(InterfaceType s, Set<ClassElement> visitedClasses, bool withDynamic) {
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+ if (identical(type, DynamicTypeImpl.instance)) {
+ return true;
+ } else if (type is! InterfaceType) {
+ return false;
+ }
+ return isMoreSpecificThan2(type as InterfaceType, new Set<ClassElement>(), withDynamic, visitedTypePairs);
+ }
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+ if (identical(type, DynamicTypeImpl.instance)) {
+ return true;
+ } else if (type is TypeParameterType) {
+ return true;
+ } else if (type is FunctionType) {
+ ClassElement element = this.element;
+ MethodElement callMethod = element.lookUpMethod("call", element.library);
+ if (callMethod != null) {
+ return callMethod.type.isSubtypeOf(type);
+ }
+ return false;
+ } else if (type is! InterfaceType) {
+ return false;
+ } else if (this == type) {
+ return true;
+ }
+ return isSubtypeOf2(type as InterfaceType, new Set<ClassElement>(), visitedTypePairs);
+ }
+
+ bool isMoreSpecificThan2(InterfaceType s, Set<ClassElement> visitedClasses, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
if (this == s) {
return true;
}
@@ -7529,7 +7689,7 @@
return false;
}
for (int i = 0; i < tArguments.length; i++) {
- if (!tArguments[i].isMoreSpecificThan3(sArguments[i], withDynamic)) {
+ if (!(tArguments[i] as TypeImpl).isMoreSpecificThan3(sArguments[i], withDynamic, visitedTypePairs)) {
return false;
}
}
@@ -7539,32 +7699,32 @@
if (element == null || visitedClasses.contains(element)) {
return false;
}
- javaSetAdd(visitedClasses, element);
+ visitedClasses.add(element);
InterfaceType supertype = superclass;
- if (supertype != null && (supertype as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+ if (supertype != null && (supertype as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
return true;
}
for (InterfaceType interfaceType in interfaces) {
- if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+ if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
return true;
}
}
for (InterfaceType mixinType in mixins) {
- if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+ if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
return true;
}
}
return false;
}
- bool isSubtypeOf2(InterfaceType type, Set<ClassElement> visitedClasses) {
+ bool isSubtypeOf2(InterfaceType type, Set<ClassElement> visitedClasses, Set<TypeImpl_TypePair> visitedTypePairs) {
InterfaceType typeT = this;
InterfaceType typeS = type;
ClassElement elementT = element;
if (elementT == null || visitedClasses.contains(elementT)) {
return false;
}
- javaSetAdd(visitedClasses, elementT);
+ visitedClasses.add(elementT);
if (typeT == typeS) {
return true;
} else if (elementT == typeS.element) {
@@ -7574,7 +7734,7 @@
return false;
}
for (int i = 0; i < typeTArgs.length; i++) {
- if (!typeTArgs[i].isSubtypeOf(typeSArgs[i])) {
+ if (!(typeTArgs[i] as TypeImpl).isSubtypeOf3(typeSArgs[i], visitedTypePairs)) {
return false;
}
}
@@ -7583,18 +7743,18 @@
return true;
}
InterfaceType supertype = superclass;
- if (supertype != null && (supertype as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+ if (supertype != null && (supertype as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
return true;
}
List<InterfaceType> interfaceTypes = interfaces;
for (InterfaceType interfaceType in interfaceTypes) {
- if ((interfaceType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+ if ((interfaceType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
return true;
}
}
List<InterfaceType> mixinTypes = mixins;
for (InterfaceType mixinType in mixinTypes) {
- if ((mixinType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+ if ((mixinType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
return true;
}
}
@@ -7665,7 +7825,22 @@
String get name => _name;
- bool isAssignableTo(Type2 type) => this.isSubtypeOf(type) || type.isSubtypeOf(this);
+ bool isAssignableTo(Type2 type) => isAssignableTo2(type, new Set<TypeImpl_TypePair>());
+
+ /**
+ * Return `true` if this type is assignable to the given type. A type <i>T</i> may be
+ * assigned to a type <i>S</i>, written <i>T</i> ⇔ <i>S</i>, iff either <i>T</i> <: <i>S</i>
+ * or <i>S</i> <: <i>T</i>.
+ *
+ * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+ * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+ * used to prevent infinite loops.
+ *
+ * @param type the type being compared with this type
+ * @param visitedPairs the set of pairs of types used to prevent infinite loops
+ * @return `true` if this type is assignable to the given type
+ */
+ bool isAssignableTo2(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => isSubtypeOf3(type, visitedTypePairs) || (type as TypeImpl).isSubtypeOf3(this, visitedTypePairs);
bool get isBottom => false;
@@ -7673,12 +7848,55 @@
bool get isDynamic => false;
- bool isMoreSpecificThan(Type2 type) => isMoreSpecificThan3(type, false);
+ bool isMoreSpecificThan(Type2 type) => isMoreSpecificThan3(type, false, new Set<TypeImpl_TypePair>());
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) => false;
+ /**
+ * Return `true` if this type is more specific than the given type.
+ *
+ * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+ * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+ * used to prevent infinite loops.
+ *
+ * @param type the type being compared with this type
+ * @param withDynamic `true` if "dynamic" should be considered as a subtype of any type
+ * @param visitedPairs the set of pairs of types used to prevent infinite loops
+ * @return `true` if this type is more specific than the given type
+ */
+ bool isMoreSpecificThan3(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+ TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
+ if (!visitedTypePairs.add(typePair)) {
+ return false;
+ }
+ bool result = internalIsMoreSpecificThan(type, withDynamic, visitedTypePairs);
+ visitedTypePairs.remove(typePair);
+ return result;
+ }
bool get isObject => false;
+ bool isSubtypeOf(Type2 type) => isSubtypeOf3(type, new Set<TypeImpl_TypePair>());
+
+ /**
+ * Return `true` if this type is a subtype of the given type.
+ *
+ * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+ * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+ * used to prevent infinite loops.
+ *
+ * @param type the type being compared with this type
+ * @param visitedPairs the set of pairs of types used to prevent infinite loops
+ * @return `true` if this type is a subtype of the given type
+ */
+ bool isSubtypeOf3(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+ TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
+ if (!visitedTypePairs.add(typePair)) {
+ return false;
+ }
+ bool result = internalIsSubtypeOf(type, visitedTypePairs);
+ visitedTypePairs.remove(typePair);
+ return result;
+ }
+
bool isSupertypeOf(Type2 type) => type.isSubtypeOf(this);
bool get isVoid => false;
@@ -7701,6 +7919,44 @@
builder.append(_name);
}
}
+
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs);
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs);
+}
+
+class TypeImpl_TypePair {
+ Type2 _firstType;
+
+ Type2 _secondType;
+
+ TypeImpl_TypePair(Type2 firstType, Type2 secondType) {
+ this._firstType = firstType;
+ this._secondType = secondType;
+ }
+
+ bool operator ==(Object object) {
+ if (identical(object, this)) {
+ return true;
+ }
+ if (object is TypeImpl_TypePair) {
+ TypeImpl_TypePair typePair = object as TypeImpl_TypePair;
+ return _firstType == typePair._firstType && _secondType != null && _secondType == typePair._secondType;
+ }
+ return false;
+ }
+
+ int get hashCode {
+ int firstHashCode = 0;
+ if (_firstType != null) {
+ firstHashCode = _firstType.element == null ? 0 : _firstType.element.hashCode;
+ }
+ int secondHashCode = 0;
+ if (_secondType != null) {
+ secondHashCode = _secondType.element == null ? 0 : _secondType.element.hashCode;
+ }
+ return firstHashCode + secondHashCode;
+ }
}
/**
@@ -7749,21 +8005,6 @@
int get hashCode => element.hashCode;
- bool isMoreSpecificThan3(Type2 s, bool withDynamic) {
- if (this == s) {
- return true;
- }
- if (s.isBottom) {
- return true;
- }
- if (s.isDynamic) {
- return true;
- }
- return isMoreSpecificThan4(s, new Set<Type2>(), withDynamic);
- }
-
- bool isSubtypeOf(Type2 s) => isMoreSpecificThan3(s, true);
-
Type2 substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) {
int length = parameterTypes.length;
for (int i = 0; i < length; i++) {
@@ -7774,7 +8015,22 @@
return this;
}
- bool isMoreSpecificThan4(Type2 s, Set<Type2> visitedTypes, bool withDynamic) {
+ bool internalIsMoreSpecificThan(Type2 s, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+ if (this == s) {
+ return true;
+ }
+ if (s.isBottom) {
+ return true;
+ }
+ if (s.isDynamic) {
+ return true;
+ }
+ return isMoreSpecificThan4(s, new Set<Type2>(), withDynamic, visitedTypePairs);
+ }
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => isMoreSpecificThan3(type, true, new Set<TypeImpl_TypePair>());
+
+ bool isMoreSpecificThan4(Type2 s, Set<Type2> visitedTypes, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
Type2 bound = element.bound;
if (s == bound) {
return true;
@@ -7790,10 +8046,10 @@
if (visitedTypes.contains(bound)) {
return false;
}
- javaSetAdd(visitedTypes, bound);
- return boundTypeParameter.isMoreSpecificThan4(s, visitedTypes, withDynamic);
+ visitedTypes.add(bound);
+ return boundTypeParameter.isMoreSpecificThan4(s, visitedTypes, withDynamic, visitedTypePairs);
}
- return bound.isMoreSpecificThan3(s, withDynamic);
+ return (bound as TypeImpl).isMoreSpecificThan3(s, withDynamic, visitedTypePairs);
}
}
@@ -7815,13 +8071,13 @@
bool operator ==(Object object) => identical(object, this);
- bool isMoreSpecificThan3(Type2 type, bool withDynamic) => isSubtypeOf(type);
-
- bool isSubtypeOf(Type2 type) => identical(type, this) || identical(type, DynamicTypeImpl.instance);
-
bool get isVoid => true;
VoidTypeImpl substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) => this;
+
+ bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) => isSubtypeOf(type);
+
+ bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => identical(type, this) || identical(type, DynamicTypeImpl.instance);
}
/**
@@ -8375,15 +8631,6 @@
bool isMoreSpecificThan(Type2 type);
/**
- * Return `true` if this type is more specific than the given type.
- *
- * @param type the type being compared with this type
- * @param withDynamic `true` if "dynamic" should be considered as a subtype of any type
- * @return `true` if this type is more specific than the given type
- */
- bool isMoreSpecificThan3(Type2 type, bool withDynamic);
-
- /**
* Return `true` if this type represents the type 'Object'.
*
* @return `true` if this type represents the type 'Object'
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 5ca1fee..2e6b37e 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -16,7 +16,7 @@
import 'sdk.dart' show DartSdk;
import 'element.dart';
import 'resolver.dart';
-import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlUnit;
+import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlScriptTagNode, HtmlUnit;
/**
* The unique instance of the class `AnalysisEngine` serves as the entry point for the
@@ -711,14 +711,6 @@
* @return `true` if analysis is to generate hint results
*/
bool get hint;
-
- /**
- * Return `true` if analysis is to use strict mode. In strict mode, error reporting is based
- * exclusively on the static type information.
- *
- * @return `true` if analysis is to use strict mode
- */
- bool get strictMode;
}
/**
@@ -2365,7 +2357,12 @@
/**
* The data descriptor representing the hints resulting from auditing the source.
*/
- static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("DartEntry.HINTS");
+ static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.HINTS");
+
+ /**
+ * The data descriptor representing the errors resulting from parsing the source.
+ */
+ static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.PARSE_ERRORS");
/**
* The data descriptor representing the parsed AST structure.
@@ -2409,13 +2406,24 @@
HtmlUnit _parsedUnit;
/**
+ * The state of the cached parse errors.
+ */
+ CacheState _parseErrorsState = CacheState.INVALID;
+
+ /**
+ * The errors produced while scanning and parsing the HTML, or `null` if the errors are not
+ * currently cached.
+ */
+ List<AnalysisError> _parseErrors = AnalysisError.NO_ERRORS;
+
+ /**
* The state of the cached resolution errors.
*/
CacheState _resolutionErrorsState = CacheState.INVALID;
/**
- * The errors produced while resolving the compilation unit, or `null` if the errors are not
- * currently cached.
+ * The errors produced while resolving the HTML, or `null` if the errors are not currently
+ * cached.
*/
List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
@@ -2453,6 +2461,9 @@
List<AnalysisError> get allErrors {
List<AnalysisError> errors = new List<AnalysisError>();
+ for (AnalysisError error in _parseErrors) {
+ errors.add(error);
+ }
for (AnalysisError error in _resolutionErrors) {
errors.add(error);
}
@@ -2470,6 +2481,8 @@
CacheState getState(DataDescriptor descriptor) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _elementState;
+ } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+ return _parseErrorsState;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnitState;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
@@ -2485,6 +2498,8 @@
Object getValue(DataDescriptor descriptor) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _element as Object;
+ } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+ return _parseErrors as Object;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnit as Object;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
@@ -2508,6 +2523,8 @@
*/
void invalidateAllInformation() {
setState(SourceEntry.LINE_INFO, CacheState.INVALID);
+ _parseErrors = AnalysisError.NO_ERRORS;
+ _parseErrorsState = CacheState.INVALID;
_parsedUnit = null;
_parsedUnitState = CacheState.INVALID;
_referencedLibraries = Source.EMPTY_ARRAY;
@@ -2533,6 +2550,7 @@
*/
void recordParseError() {
setState(SourceEntry.LINE_INFO, CacheState.ERROR);
+ setState(HtmlEntry.PARSE_ERRORS, CacheState.ERROR);
setState(HtmlEntry.PARSED_UNIT, CacheState.ERROR);
setState(HtmlEntry.REFERENCED_LIBRARIES, CacheState.ERROR);
recordResolutionError();
@@ -2552,6 +2570,9 @@
if (identical(descriptor, HtmlEntry.ELEMENT)) {
_element = updatedValue(state, _element, null);
_elementState = state;
+ } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+ _parseErrors = updatedValue(state, _parseErrors, null);
+ _parseErrorsState = state;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = updatedValue(state, _parsedUnit, null);
_parsedUnitState = state;
@@ -2573,6 +2594,9 @@
if (identical(descriptor, HtmlEntry.ELEMENT)) {
_element = value as HtmlElement;
_elementState = CacheState.VALID;
+ } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+ _parseErrors = value as List<AnalysisError>;
+ _parseErrorsState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = value as HtmlUnit;
_parsedUnitState = CacheState.VALID;
@@ -2593,6 +2617,8 @@
void copyFrom(SourceEntryImpl entry) {
super.copyFrom(entry);
HtmlEntryImpl other = entry as HtmlEntryImpl;
+ _parseErrorsState = other._parseErrorsState;
+ _parseErrors = other._parseErrors;
_parsedUnitState = other._parsedUnitState;
_parsedUnit = other._parsedUnit;
_referencedLibrariesState = other._referencedLibrariesState;
@@ -2608,6 +2634,8 @@
void writeOn(JavaStringBuilder builder) {
builder.append("Html: ");
super.writeOn(builder);
+ builder.append("; parseErrors = ");
+ builder.append(_parseErrorsState);
builder.append("; parsedUnit = ");
builder.append(_parsedUnitState);
builder.append("; resolutionErrors = ");
@@ -2900,7 +2928,7 @@
if (identical(state, CacheState.ERROR)) {
AnalysisException exception = dartEntry.exception;
if (exception != null) {
- javaSetAdd(_exceptions, exception);
+ _exceptions.add(exception);
}
}
}
@@ -3649,7 +3677,6 @@
}
this._options.dart2jsHint = options.dart2jsHint;
this._options.hint = options.hint;
- this._options.strictMode = options.strictMode;
if (needsRecompute) {
invalidateAllResolutionInformation();
}
@@ -3678,16 +3705,14 @@
void setChangedContents(Source source, String contents, int offset, int oldLength, int newLength) {
{
String originalContents = _sourceFactory.setContents(source, contents);
- if (originalContents == null) {
- if (contents != null) {
+ if (contents != null) {
+ if (contents != originalContents) {
_incrementalAnalysisCache = IncrementalAnalysisCache.update(_incrementalAnalysisCache, source, originalContents, contents, offset, oldLength, newLength, getReadableSourceEntry(source));
sourceChanged(source);
}
- } else if (originalContents != contents) {
- _incrementalAnalysisCache = IncrementalAnalysisCache.update(_incrementalAnalysisCache, source, originalContents, contents, offset, oldLength, newLength, getReadableSourceEntry(source));
- sourceChanged(source);
- } else if (contents == null) {
+ } else if (originalContents != null) {
_incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
+ sourceChanged(source);
}
}
}
@@ -3695,14 +3720,15 @@
void setContents(Source source, String contents) {
{
String originalContents = _sourceFactory.setContents(source, contents);
- if (originalContents == null) {
- if (contents != null) {
+ if (contents != null) {
+ if (contents != originalContents) {
+ _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
sourceChanged(source);
}
- } else if (originalContents != contents) {
+ } else if (originalContents != null) {
+ _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
sourceChanged(source);
}
- _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
}
}
@@ -4427,13 +4453,13 @@
DartEntry dartEntry = sourceEntry as DartEntry;
CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
if (isPriority) {
CompilationUnit parseUnit = dartEntry.anyParsedCompilationUnit;
if (parseUnit == null) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
}
@@ -4442,14 +4468,14 @@
if (libraryEntry is DartEntry) {
CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
CacheState resolvedUnitState = dartEntry.getState2(DartEntry.RESOLVED_UNIT, librarySource);
if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
if (libraryElement != null) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
}
@@ -4457,7 +4483,7 @@
if (identical(verificationErrorsState, CacheState.INVALID) || (isPriority && identical(verificationErrorsState, CacheState.FLUSHED))) {
LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
if (libraryElement != null) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
}
@@ -4466,7 +4492,7 @@
if (identical(hintsState, CacheState.INVALID) || (isPriority && identical(hintsState, CacheState.FLUSHED))) {
LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
if (libraryElement != null) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
}
@@ -4477,12 +4503,12 @@
HtmlEntry htmlEntry = sourceEntry as HtmlEntry;
CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT);
if (identical(parsedUnitState, CacheState.INVALID) || (isPriority && identical(parsedUnitState, CacheState.FLUSHED))) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
- javaSetAdd(sources, source);
+ sources.add(source);
return;
}
}
@@ -4550,7 +4576,7 @@
if (library.source == htmlSource) {
return true;
}
- javaSetAdd(visitedLibraries, library);
+ visitedLibraries.add(library);
for (LibraryElement imported in library.importedLibraries) {
if (isClient(imported, htmlSource, visitedLibraries)) {
return true;
@@ -4852,6 +4878,7 @@
HtmlUnit unit = task.htmlUnit;
htmlCopy.setValue(SourceEntry.LINE_INFO, lineInfo);
htmlCopy.setValue(HtmlEntry.PARSED_UNIT, unit);
+ htmlCopy.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
htmlCopy.setValue(HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries);
ChangeNoticeImpl notice = getNotice(source);
notice.setErrors(htmlEntry.allErrors, lineInfo);
@@ -5154,9 +5181,9 @@
List<Source> containingLibraries = getLibrariesContaining(source);
Set<Source> librariesToInvalidate = new Set<Source>();
for (Source containingLibrary in containingLibraries) {
- javaSetAdd(librariesToInvalidate, containingLibrary);
+ librariesToInvalidate.add(containingLibrary);
for (Source dependentLibrary in getLibrariesDependingOn(containingLibrary)) {
- javaSetAdd(librariesToInvalidate, dependentLibrary);
+ librariesToInvalidate.add(dependentLibrary);
}
}
for (Source library in librariesToInvalidate) {
@@ -5179,9 +5206,9 @@
if (sourceEntry is DartEntry) {
Set<Source> libraries = new Set<Source>();
for (Source librarySource in getLibrariesContaining(source)) {
- javaSetAdd(libraries, librarySource);
+ libraries.add(librarySource);
for (Source dependentLibrary in getLibrariesDependingOn(librarySource)) {
- javaSetAdd(libraries, dependentLibrary);
+ libraries.add(dependentLibrary);
}
}
for (Source librarySource in libraries) {
@@ -5310,12 +5337,6 @@
bool _hint = true;
/**
- * A flag indicating whether analysis is to use strict mode. In strict mode, error reporting is
- * based exclusively on the static type information.
- */
- bool _strictMode = true;
-
- /**
* Initialize a newly created set of analysis options to have their default values.
*/
AnalysisOptionsImpl();
@@ -5330,7 +5351,6 @@
_cacheSize = options.cacheSize;
_dart2jsHint = options.dart2jsHint;
_hint = options.hint;
- _strictMode = options.strictMode;
}
int get cacheSize => _cacheSize;
@@ -5340,14 +5360,6 @@
bool get hint => _hint;
/**
- * Return `true` if analysis is to use strict mode. In strict mode, error reporting is based
- * exclusively on the static type information.
- *
- * @return `true` if analysis is to use strict mode
- */
- bool get strictMode => _strictMode;
-
- /**
* Set the maximum number of sources for which AST structures should be kept in the cache to the
* given size.
*
@@ -5376,16 +5388,6 @@
void set hint(bool hint) {
this._hint = hint;
}
-
- /**
- * Set whether analysis is to use strict mode to the given value. In strict mode, error reporting
- * is based exclusively on the static type information.
- *
- * @param isStrict `true` if analysis is to use strict mode
- */
- void set strictMode(bool isStrict) {
- _strictMode = isStrict;
- }
}
/**
@@ -5818,7 +5820,7 @@
*
* @param cache the prior cache or `null` if none
* @param source the source being updated (not `null`)
- * @param oldContents the original source contents prior to this update (not `null`)
+ * @param oldContents the original source contents prior to this update (may be `null`)
* @param newContents the new contents after this incremental change (not `null`)
* @param offset the offset at which the change occurred
* @param oldLength the length of the text being replaced
@@ -5878,7 +5880,7 @@
*/
static IncrementalAnalysisCache verifyStructure(IncrementalAnalysisCache cache, Source source, CompilationUnit unit) {
if (cache != null && unit != null && cache.source == source) {
- if (!ASTComparator.equals3(cache.resolvedUnit, unit)) {
+ if (!ASTComparator.equals4(cache.resolvedUnit, unit)) {
return null;
}
}
@@ -6685,7 +6687,7 @@
errorsForSource = new Set<AnalysisError>();
_errors[source] = errorsForSource;
}
- javaSetAdd(errorsForSource, error);
+ errorsForSource.add(error);
}
}
@@ -7322,7 +7324,7 @@
List<Token> token = [null];
TimeCounter_TimeCounterHandle timeCounterScan = PerformanceStatistics.scan.start();
try {
- Source_ContentReceiver receiver = new Source_ContentReceiver_12(this, errorListener, token);
+ Source_ContentReceiver receiver = new Source_ContentReceiver_11(this, errorListener, token);
try {
source.getContents(receiver);
} on JavaException catch (exception) {
@@ -7341,19 +7343,19 @@
if (directive is ExportDirective) {
Source exportSource = resolveSource(source, directive as ExportDirective);
if (exportSource != null) {
- javaSetAdd(_exportedSources, exportSource);
+ _exportedSources.add(exportSource);
}
} else if (directive is ImportDirective) {
Source importSource = resolveSource(source, directive as ImportDirective);
if (importSource != null) {
- javaSetAdd(_importedSources, importSource);
+ _importedSources.add(importSource);
}
} else if (directive is LibraryDirective) {
_hasLibraryDirective2 = true;
} else if (directive is PartDirective) {
Source partSource = resolveSource(source, directive as PartDirective);
if (partSource != null) {
- javaSetAdd(_includedSources, partSource);
+ _includedSources.add(partSource);
}
} else if (directive is PartOfDirective) {
_hasPartOfDirective2 = true;
@@ -7406,14 +7408,14 @@
}
}
-class Source_ContentReceiver_12 implements Source_ContentReceiver {
+class Source_ContentReceiver_11 implements Source_ContentReceiver {
final ParseDartTask ParseDartTask_this;
RecordingErrorListener errorListener;
List<Token> token;
- Source_ContentReceiver_12(this.ParseDartTask_this, this.errorListener, this.token);
+ Source_ContentReceiver_11(this.ParseDartTask_this, this.errorListener, this.token);
void accept(CharBuffer contents, int modificationTime) {
ParseDartTask_this.modificationTime = modificationTime;
@@ -7455,6 +7457,11 @@
HtmlUnit htmlUnit;
/**
+ * The errors that were produced by scanning and parsing the source.
+ */
+ List<AnalysisError> errors = AnalysisError.NO_ERRORS;
+
+ /**
* An array containing the sources of the libraries that are referenced within the HTML.
*/
List<Source> referencedLibraries = Source.EMPTY_ARRAY;
@@ -7509,8 +7516,10 @@
HtmlScanResult scannerResult = scanner.result;
modificationTime = scannerResult.modificationTime;
lineInfo = new LineInfo(scannerResult.lineStarts);
- HtmlParseResult result = new HtmlParser(source).parse(scannerResult);
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ HtmlParseResult result = new HtmlParser(source, errorListener).parse(scannerResult);
htmlUnit = result.htmlUnit;
+ errors = errorListener.getErrors2(source);
referencedLibraries = librarySources;
}
@@ -7521,7 +7530,7 @@
*/
List<Source> get librarySources {
List<Source> libraries = new List<Source>();
- htmlUnit.accept(new RecursiveXmlVisitor_13(this, libraries));
+ htmlUnit.accept(new RecursiveXmlVisitor_12(this, libraries));
if (libraries.isEmpty) {
return Source.EMPTY_ARRAY;
}
@@ -7529,39 +7538,32 @@
}
}
-class RecursiveXmlVisitor_13 extends RecursiveXmlVisitor<Object> {
+class RecursiveXmlVisitor_12 extends RecursiveXmlVisitor<Object> {
final ParseHtmlTask ParseHtmlTask_this;
List<Source> libraries;
- RecursiveXmlVisitor_13(this.ParseHtmlTask_this, this.libraries) : super();
+ RecursiveXmlVisitor_12(this.ParseHtmlTask_this, this.libraries) : super();
- Object visitXmlTagNode(XmlTagNode node) {
- if (javaStringEqualsIgnoreCase(node.tag.lexeme, ParseHtmlTask._TAG_SCRIPT)) {
- bool isDartScript = false;
- XmlAttributeNode scriptAttribute = null;
- for (XmlAttributeNode attribute in node.attributes) {
- if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_SRC)) {
- scriptAttribute = attribute;
- } else if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_TYPE)) {
- if (javaStringEqualsIgnoreCase(attribute.text, ParseHtmlTask._TYPE_DART)) {
- isDartScript = true;
- }
- }
- }
- if (isDartScript && scriptAttribute != null) {
- try {
- Uri uri = new Uri(path: scriptAttribute.text);
- String fileName = uri.path;
- Source librarySource = ParseHtmlTask_this.context.sourceFactory.resolveUri(ParseHtmlTask_this.source, fileName);
- if (librarySource != null && librarySource.exists()) {
- libraries.add(librarySource);
- }
- } on URISyntaxException catch (e) {
- }
+ Object visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+ XmlAttributeNode scriptAttribute = null;
+ for (XmlAttributeNode attribute in node.attributes) {
+ if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_SRC)) {
+ scriptAttribute = attribute;
}
}
- return super.visitXmlTagNode(node);
+ if (scriptAttribute != null) {
+ try {
+ Uri uri = new Uri(path: scriptAttribute.text);
+ String fileName = uri.path;
+ Source librarySource = ParseHtmlTask_this.context.sourceFactory.resolveUri(ParseHtmlTask_this.source, fileName);
+ if (librarySource != null && librarySource.exists()) {
+ libraries.add(librarySource);
+ }
+ } on URISyntaxException catch (e) {
+ }
+ }
+ return super.visitHtmlScriptTagNode(node);
}
}
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 70123b4..804608e 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -115,6 +115,21 @@
}
/**
+ * Instances of the class `BooleanErrorListener` implement a listener that keeps track of
+ * whether an error has been reported to it.
+ */
+class BooleanErrorListener implements AnalysisErrorListener {
+ /**
+ * A flag indicating whether an error has been reported to this listener.
+ */
+ bool errorReported = false;
+
+ void onError(AnalysisError error) {
+ errorReported = true;
+ }
+}
+
+/**
* Instances of the class `ErrorReporter` wrap an error listener with utility methods used to
* create the errors being reported.
*
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index e55e7da..3924cec 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -7,7 +7,11 @@
import 'java_core.dart';
import 'java_engine.dart';
import 'source.dart';
-import 'element.dart' show HtmlElementImpl;
+import 'error.dart' show AnalysisErrorListener;
+import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token;
+import 'parser.dart' show Parser;
+import 'ast.dart' show ASTVisitor, CompilationUnit, Expression;
+import 'element.dart' show HtmlElementImpl, HtmlScriptElement;
import 'engine.dart' show AnalysisEngine;
/**
@@ -105,6 +109,45 @@
}
/**
+ * Instances of the class `EmbeddedExpression` represent an expression enclosed between
+ * <code>{{</code> and <code>}}</code> delimiters.
+ */
+class EmbeddedExpression {
+ /**
+ * The offset of the first character of the opening delimiter.
+ */
+ int openingOffset = 0;
+
+ /**
+ * The expression that is enclosed between the delimiters.
+ */
+ Expression expression;
+
+ /**
+ * The offset of the first character of the closing delimiter.
+ */
+ int closingOffset = 0;
+
+ /**
+ * An empty array of embedded expressions.
+ */
+ static List<EmbeddedExpression> EMPTY_ARRAY = new List<EmbeddedExpression>(0);
+
+ /**
+ * Initialize a newly created embedded expression to represent the given expression.
+ *
+ * @param openingOffset the offset of the first character of the opening delimiter
+ * @param expression the expression that is enclosed between the delimiters
+ * @param closingOffset the offset of the first character of the closing delimiter
+ */
+ EmbeddedExpression(int openingOffset, Expression expression, int closingOffset) {
+ this.openingOffset = openingOffset;
+ this.expression = expression;
+ this.closingOffset = closingOffset;
+ }
+}
+
+/**
* Instances of `HtmlParseResult` hold the result of parsing an HTML file.
*
* @coverage dart.engine.html
@@ -121,6 +164,36 @@
}
/**
+ * Instances of the class `TagWithEmbeddedExpressions` represent a tag whose text content
+ * contains one or more embedded expressions.
+ */
+class TagWithEmbeddedExpressions extends XmlTagNode {
+ /**
+ * The expressions that are embedded in the tag's content.
+ */
+ List<EmbeddedExpression> _expressions;
+
+ /**
+ * Initialize a newly created tag whose text content contains one or more embedded expressions.
+ *
+ * @param nodeStart the token marking the beginning of the tag
+ * @param tag the name of the tag
+ * @param attributes the attributes in the tag
+ * @param attributeEnd the token terminating the region where attributes can be
+ * @param tagNodes the children of the tag
+ * @param contentEnd the token that starts the closing tag
+ * @param closingTag the name of the tag that occurs in the closing tag
+ * @param nodeEnd the last token in the tag
+ * @param expressions the expressions that are embedded in the value
+ */
+ TagWithEmbeddedExpressions(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd, List<EmbeddedExpression> expressions) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd) {
+ this._expressions = expressions;
+ }
+
+ List<EmbeddedExpression> get expressions => _expressions;
+}
+
+/**
* Instances of the class `RecursiveXmlVisitor` implement an XML visitor that will recursively
* visit all of the nodes in an XML structure. For example, using an instance of this class to visit
* a [XmlTagNode] will also cause all of the contained [XmlAttributeNode]s and
@@ -133,6 +206,11 @@
* @coverage dart.engine.html
*/
class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
+ R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+ node.visitChildren(this);
+ return null;
+ }
+
R visitHtmlUnit(HtmlUnit node) {
node.visitChildren(this);
return null;
@@ -150,6 +228,56 @@
}
/**
+ * Instances of the class `HtmlScriptTagNode` represent a script tag within an HTML file that
+ * references a Dart script.
+ */
+class HtmlScriptTagNode extends XmlTagNode {
+ /**
+ * The AST structure representing the Dart code within this tag.
+ */
+ CompilationUnit _script;
+
+ /**
+ * The element representing this script.
+ */
+ HtmlScriptElement scriptElement;
+
+ /**
+ * Initialize a newly created node to represent a script tag within an HTML file that references a
+ * Dart script.
+ *
+ * @param nodeStart the token marking the beginning of the tag
+ * @param tag the name of the tag
+ * @param attributes the attributes in the tag
+ * @param attributeEnd the token terminating the region where attributes can be
+ * @param tagNodes the children of the tag
+ * @param contentEnd the token that starts the closing tag
+ * @param closingTag the name of the tag that occurs in the closing tag
+ * @param nodeEnd the last token in the tag
+ */
+ HtmlScriptTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+
+ accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
+
+ /**
+ * Return the AST structure representing the Dart code within this tag, or `null` if this
+ * tag references an external script.
+ *
+ * @return the AST structure representing the Dart code within this tag
+ */
+ CompilationUnit get script => _script;
+
+ /**
+ * Set the AST structure representing the Dart code within this tag to the given compilation unit.
+ *
+ * @param unit the AST structure representing the Dart code within this tag
+ */
+ void set script(CompilationUnit unit) {
+ _script = unit;
+ }
+}
+
+/**
* The abstract class `XmlNode` defines behavior common to all XML/HTML nodes.
*
* @coverage dart.engine.html
@@ -330,12 +458,39 @@
}
/**
+ * Instances of the class `AttributeWithEmbeddedExpressions` represent an attribute whose
+ * value contains one or more embedded expressions.
+ */
+class AttributeWithEmbeddedExpressions extends XmlAttributeNode {
+ /**
+ * The expressions that are embedded in the attribute's value.
+ */
+ List<EmbeddedExpression> _expressions;
+
+ /**
+ * Initialize a newly created attribute whose value contains one or more embedded expressions.
+ *
+ * @param name the name of the attribute
+ * @param equals the equals sign separating the name from the value
+ * @param value the value of the attribute
+ * @param expressions the expressions that are embedded in the value
+ */
+ AttributeWithEmbeddedExpressions(Token name, Token equals, Token value, List<EmbeddedExpression> expressions) : super(name, equals, value) {
+ this._expressions = expressions;
+ }
+
+ List<EmbeddedExpression> get expressions => _expressions;
+}
+
+/**
* Instances of the class `SimpleXmlVisitor` implement an AST visitor that will do nothing
* when visiting an AST node. It is intended to be a superclass for classes that use the visitor
* pattern primarily as a dispatch mechanism (and hence don't need to recursively visit a whole
* structure) and that only need to visit a small number of node types.
*/
class SimpleXmlVisitor<R> implements XmlVisitor<R> {
+ R visitHtmlScriptTagNode(HtmlScriptTagNode node) => null;
+
R visitHtmlUnit(HtmlUnit htmlUnit) => null;
R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode) => null;
@@ -814,6 +969,8 @@
this._writer = writer;
}
+ Object visitHtmlScriptTagNode(HtmlScriptTagNode node) => visitXmlTagNode(node);
+
Object visitHtmlUnit(HtmlUnit node) {
for (XmlTagNode child in node.tagNodes) {
visit(child);
@@ -968,6 +1125,13 @@
Token get endToken => value;
/**
+ * Return the expressions that are embedded in the attribute's value.
+ *
+ * @return the expressions that are embedded in the attribute's value
+ */
+ List<EmbeddedExpression> get expressions => EmbeddedExpression.EMPTY_ARRAY;
+
+ /**
* Answer the lexeme for the value token without the leading and trailing quotes.
*
* @return the text or `null` if the value is not specified
@@ -1001,12 +1165,65 @@
}
/**
+ * Instances of the class `EmbeddedDartVisitor` implement a recursive visitor for HTML files
+ * that will invoke another visitor on all embedded dart scripts and expressions.
+ */
+class EmbeddedDartVisitor<R> implements XmlVisitor<R> {
+ /**
+ * The visitor used to visit embedded Dart code.
+ */
+ ASTVisitor<R> _dartVisitor;
+
+ /**
+ * Initialize a newly created visitor to visit all of the nodes in an HTML structure and to use
+ * the given visitor to visit all of the nodes representing any embedded scripts or expressions.
+ *
+ * @param dartVisitor the visitor used to visit embedded Dart code
+ */
+ EmbeddedDartVisitor(ASTVisitor<R> dartVisitor) {
+ this._dartVisitor = dartVisitor;
+ }
+
+ R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+ node.visitChildren(this);
+ CompilationUnit script = node.script;
+ if (script != null) {
+ script.accept(_dartVisitor);
+ }
+ return null;
+ }
+
+ R visitHtmlUnit(HtmlUnit node) {
+ node.visitChildren(this);
+ return null;
+ }
+
+ R visitXmlAttributeNode(XmlAttributeNode node) {
+ node.visitChildren(this);
+ for (EmbeddedExpression expression in node.expressions) {
+ expression.expression.accept(_dartVisitor);
+ }
+ return null;
+ }
+
+ R visitXmlTagNode(XmlTagNode node) {
+ node.visitChildren(this);
+ for (EmbeddedExpression expression in node.expressions) {
+ expression.expression.accept(_dartVisitor);
+ }
+ return null;
+ }
+}
+
+/**
* The interface `XmlVisitor` defines the behavior of objects that can be used to visit an
* [XmlNode] structure.
*
* @coverage dart.engine.html
*/
abstract class XmlVisitor<R> {
+ R visitHtmlScriptTagNode(HtmlScriptTagNode node);
+
R visitHtmlUnit(HtmlUnit htmlUnit);
R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
@@ -1107,6 +1324,31 @@
}
/**
+ * Create a node representing an attribute.
+ *
+ * @param name the name of the attribute
+ * @param equals the equals sign, or `null` if there is no value
+ * @param value the value of the attribute
+ * @return the node that was created
+ */
+ XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) => new XmlAttributeNode(name, equals, value);
+
+ /**
+ * Create a node representing a tag.
+ *
+ * @param nodeStart the token marking the beginning of the tag
+ * @param tag the name of the tag
+ * @param attributes the attributes in the tag
+ * @param attributeEnd the token terminating the region where attributes can be
+ * @param tagNodes the children of the tag
+ * @param contentEnd the token that starts the closing tag
+ * @param closingTag the name of the tag that occurs in the closing tag
+ * @param nodeEnd the last token in the tag
+ * @return the node that was created
+ */
+ XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) => new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+
+ /**
* Answer `true` if the specified tag is self closing and thus should never have content or
* child tag nodes.
*
@@ -1179,7 +1421,7 @@
reportUnexpectedToken();
value = insertSyntheticToken(TokenType.STRING);
}
- return new XmlAttributeNode(name, equals, value);
+ return createAttributeNode(name, equals, value);
}
/**
@@ -1265,7 +1507,7 @@
attributeEnd = insertSyntheticToken(TokenType.SLASH_GT);
}
if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag)) {
- return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, currentToken, null, attributeEnd);
+ return createTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, currentToken, null, attributeEnd);
}
List<XmlTagNode> tagNodes = parseChildTagNodes();
Token contentEnd;
@@ -1292,7 +1534,7 @@
reportUnexpectedToken();
nodeEnd = insertSyntheticToken(TokenType.GT);
}
- return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+ return createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
}
/**
@@ -1486,6 +1728,13 @@
return tag;
}
+ /**
+ * Return the expressions that are embedded in the tag's content.
+ *
+ * @return the expressions that are embedded in the tag's content
+ */
+ List<EmbeddedExpression> get expressions => EmbeddedExpression.EMPTY_ARRAY;
+
void visitChildren(XmlVisitor visitor) {
for (XmlAttributeNode node in attributes) {
node.accept(visitor);
@@ -1513,14 +1762,64 @@
* @coverage dart.engine.html
*/
class HtmlParser extends XmlParser {
+ /**
+ * The line information associated with the source being parsed.
+ */
+ LineInfo _lineInfo;
+
+ /**
+ * The error listener to which errors will be reported.
+ */
+ AnalysisErrorListener _errorListener;
+
+ static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\"";
+
+ static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'";
+
+ static String _OPENING_DELIMITER = "{{";
+
+ static String _CLOSING_DELIMITER = "}}";
+
+ static String _SCRIPT = "script";
+
+ static String _TYPE = "type";
+
+ /**
+ * A set containing the names of tags that do not have a closing tag.
+ */
static Set<String> SELF_CLOSING = new Set<String>();
/**
* Construct a parser for the specified source.
*
* @param source the source being parsed
+ * @param errorListener the error listener to which errors will be reported
*/
- HtmlParser(Source source) : super(source);
+ HtmlParser(Source source, AnalysisErrorListener errorListener) : super(source) {
+ this._errorListener = errorListener;
+ }
+
+ Token getEndToken(Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
+ if (nodeEnd != null) {
+ return nodeEnd;
+ }
+ if (closingTag != null) {
+ return closingTag;
+ }
+ if (contentEnd != null) {
+ return contentEnd;
+ }
+ if (!tagNodes.isEmpty) {
+ return tagNodes[tagNodes.length - 1].endToken;
+ }
+ if (attributeEnd != null) {
+ return attributeEnd;
+ }
+ if (!attributes.isEmpty) {
+ return attributes[attributes.length - 1].endToken;
+ }
+ return tag;
+ }
/**
* Parse the tokens specified by the given scan result.
@@ -1529,6 +1828,8 @@
* @return the parse result (not `null`)
*/
HtmlParseResult parse(HtmlScanResult scanResult) {
+ List<int> lineStarts = scanResult.lineStarts;
+ _lineInfo = new LineInfo(lineStarts);
Token firstToken = scanResult.token;
List<XmlTagNode> tagNodes = parseTopTagNodes(firstToken);
HtmlUnit unit = new HtmlUnit(firstToken, tagNodes, currentToken);
@@ -1547,7 +1848,109 @@
return parse(scanner.result);
}
+ XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) {
+ List<EmbeddedExpression> expressions = new List<EmbeddedExpression>();
+ addEmbeddedExpressions(expressions, value);
+ if (expressions.isEmpty) {
+ return new XmlAttributeNode(name, equals, value);
+ }
+ return new AttributeWithEmbeddedExpressions(name, equals, value, new List.from(expressions));
+ }
+
+ XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
+ if (isScriptNode(tag, attributes, tagNodes)) {
+ HtmlScriptTagNode tagNode = new HtmlScriptTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+ String contents = tagNode.content;
+ int contentOffset = attributeEnd.end;
+ LineInfo_Location location = _lineInfo.getLocation(contentOffset);
+ sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+ scanner.setSourceStart(location.lineNumber, location.columnNumber);
+ sc.Token firstToken = scanner.tokenize();
+ Parser parser = new Parser(source, _errorListener);
+ CompilationUnit unit = parser.parseCompilationUnit(firstToken);
+ unit.lineInfo = _lineInfo;
+ tagNode.script = unit;
+ return tagNode;
+ }
+ Token token = nodeStart;
+ Token endToken = getEndToken(tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+ List<EmbeddedExpression> expressions = new List<EmbeddedExpression>();
+ while (token != endToken) {
+ if (identical(token.type, TokenType.TEXT)) {
+ addEmbeddedExpressions(expressions, token);
+ }
+ token = token.next;
+ }
+ if (expressions.isEmpty) {
+ return super.createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+ }
+ return new TagWithEmbeddedExpressions(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd, new List.from(expressions));
+ }
+
bool isSelfClosing(Token tag) => SELF_CLOSING.contains(tag.lexeme);
+
+ /**
+ * Parse the value of the given token for embedded expressions, and add any embedded expressions
+ * that are found to the given list of expressions.
+ *
+ * @param expressions the list to which embedded expressions are to be added
+ * @param token the token whose value is to be parsed
+ */
+ void addEmbeddedExpressions(List<EmbeddedExpression> expressions, Token token) {
+ String lexeme = token.lexeme;
+ int startIndex = lexeme.indexOf(_OPENING_DELIMITER);
+ while (startIndex >= 0) {
+ int endIndex = JavaString.indexOf(lexeme, _CLOSING_DELIMITER, startIndex + 2);
+ if (endIndex < 0) {
+ return;
+ } else if (startIndex + 2 < endIndex) {
+ int offset = token.offset;
+ expressions.add(new EmbeddedExpression(startIndex, parseEmbeddedExpression(lexeme.substring(startIndex + 2, endIndex), offset + startIndex), endIndex));
+ }
+ startIndex = JavaString.indexOf(lexeme, _OPENING_DELIMITER, endIndex + 2);
+ }
+ }
+
+ /**
+ * Determine if the specified node is a Dart script.
+ *
+ * @param node the node to be tested (not `null`)
+ * @return `true` if the node is a Dart script
+ */
+ bool isScriptNode(Token tag, List<XmlAttributeNode> attributes, List<XmlTagNode> tagNodes) {
+ if (tagNodes.length != 0 || tag.lexeme != _SCRIPT) {
+ return false;
+ }
+ for (XmlAttributeNode attribute in attributes) {
+ if (attribute.name.lexeme == _TYPE) {
+ Token valueToken = attribute.value;
+ if (valueToken != null) {
+ String value = valueToken.lexeme;
+ if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Given the contents of an embedded expression that occurs at the given offset, parse it as a
+ * Dart expression. The contents should not include the expression's delimiters.
+ *
+ * @param contents the contents of the expression
+ * @param contentOffset the offset of the expression in the larger file
+ * @return the Dart expression that was parsed
+ */
+ Expression parseEmbeddedExpression(String contents, int contentOffset) {
+ LineInfo_Location location = _lineInfo.getLocation(contentOffset);
+ sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+ scanner.setSourceStart(location.lineNumber, location.columnNumber);
+ sc.Token firstToken = scanner.tokenize();
+ Parser parser = new Parser(source, _errorListener);
+ return parser.parseExpression(firstToken);
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/generated/instrumentation.dart b/pkg/analyzer/lib/src/generated/instrumentation.dart
index 50ddb07..a9c7b7b 100644
--- a/pkg/analyzer/lib/src/generated/instrumentation.dart
+++ b/pkg/analyzer/lib/src/generated/instrumentation.dart
@@ -40,13 +40,13 @@
/**
* A builder that will silently ignore all data and logging requests.
*/
- static final InstrumentationBuilder nullBuilder = new InstrumentationBuilder_17();
+ static final InstrumentationBuilder nullBuilder = new InstrumentationBuilder_18();
/**
* An instrumentation logger that can be used when no other instrumentation logger has been
* configured. This logger will silently ignore all data and logging requests.
*/
- static InstrumentationLogger _NULL_LOGGER = new InstrumentationLogger_18();
+ static InstrumentationLogger _NULL_LOGGER = new InstrumentationLogger_19();
/**
* The current instrumentation logger.
@@ -92,7 +92,7 @@
}
}
-class InstrumentationBuilder_17 implements InstrumentationBuilder {
+class InstrumentationBuilder_18 implements InstrumentationBuilder {
InstrumentationBuilder data(String name, bool value) => this;
InstrumentationBuilder data2(String name, int value) => this;
@@ -120,7 +120,7 @@
InstrumentationBuilder record(Exception exception) => this;
}
-class InstrumentationLogger_18 implements InstrumentationLogger {
+class InstrumentationLogger_19 implements InstrumentationLogger {
InstrumentationBuilder createBuilder(String name) => Instrumentation.nullBuilder;
}
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index 46fdaae..ea75f59 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -82,6 +82,9 @@
class JavaArrays {
static bool equals(List a, List b) {
+ if (identical(a, b)) {
+ return true;
+ }
if (a.length != b.length) {
return false;
}
@@ -401,14 +404,6 @@
return oldValue;
}
-bool javaSetAdd(Set s, o) {
- if (!s.contains(o)) {
- s.add(o);
- return true;
- }
- return false;
-}
-
bool javaCollectionContainsAll(Iterable list, Iterable c) {
return c.fold(true, (bool prev, e) => prev && list.contains(e));
}
@@ -419,12 +414,6 @@
return oldValue;
}
-void javaMapPutAll(Map target, Map source) {
- source.forEach((k, v) {
- target[k] = v;
- });
-}
-
bool javaStringEqualsIgnoreCase(String a, String b) {
return a.toLowerCase() == b.toLowerCase();
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 465cf56..fc20dc5 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -1163,60 +1163,69 @@
}
/**
- * Given a range of tokens that were re-scanned, re-parse the minimimum number of tokens to
- * produce a consistent AST structure. The range is represented by the first and last tokens in
- * the range. The tokens are assumed to be contained in the same token stream.
+ * Given a range of tokens that were re-scanned, re-parse the minimum number of tokens to produce
+ * a consistent AST structure. The range is represented by the first and last tokens in the range.
+ * The tokens are assumed to be contained in the same token stream.
*
- * @param firstToken the first token in the range of tokens that were re-scanned or `null`
- * if no new tokens were inserted
- * @param lastToken the last token in the range of tokens that were re-scanned or `null` if
- * no new tokens were inserted
+ * @param leftToken the token in the new token stream immediately to the left of the range of
+ * tokens that were inserted
+ * @param rightToken the token in the new token stream immediately to the right of the range of
+ * tokens that were inserted
* @param originalStart the offset in the original source of the first character that was modified
* @param originalEnd the offset in the original source of the last character that was modified
*/
- ASTNode reparse(ASTNode originalStructure, Token firstToken, Token lastToken, int originalStart, int originalEnd) {
+ ASTNode reparse(ASTNode originalStructure, Token leftToken, Token rightToken, int originalStart, int originalEnd) {
ASTNode oldNode = null;
ASTNode newNode = null;
- if (firstToken != null) {
- if (originalEnd < originalStart) {
- oldNode = new NodeLocator.con1(originalStart).searchWithin(originalStructure);
- } else {
- oldNode = new NodeLocator.con2(originalStart, originalEnd).searchWithin(originalStructure);
- }
- int originalOffset = oldNode.offset;
- Token parseToken = findTokenAt(firstToken, originalOffset);
- if (parseToken == null) {
- return null;
- }
- Parser parser = new Parser(_source, _errorListener);
- parser.currentToken = parseToken;
- while (newNode == null) {
- ASTNode parent = oldNode.parent;
- if (parent == null) {
- parseToken = findFirstToken(parseToken);
- parser.currentToken = parseToken;
- return parser.parseCompilationUnit2() as ASTNode;
- }
- try {
- IncrementalParseDispatcher dispatcher = new IncrementalParseDispatcher(parser, oldNode);
- newNode = parent.accept(dispatcher);
- } on InsufficientContextException catch (exception) {
- oldNode = parent;
- originalOffset = oldNode.offset;
- parseToken = findTokenAt(parseToken, originalOffset);
- parser.currentToken = parseToken;
- } on JavaException catch (exception) {
- return null;
- }
- }
- if (newNode.offset != originalOffset) {
- return null;
- }
- if (identical(oldNode, originalStructure)) {
- return newNode as ASTNode;
- }
- ResolutionCopier.copyResolutionData(oldNode, newNode);
+ Token firstToken = leftToken.next;
+ if (identical(firstToken, rightToken)) {
+ firstToken = leftToken;
}
+ if (originalEnd < originalStart) {
+ oldNode = new NodeLocator.con1(originalStart).searchWithin(originalStructure);
+ } else {
+ oldNode = new NodeLocator.con2(originalStart, originalEnd).searchWithin(originalStructure);
+ }
+ int originalOffset = oldNode.offset;
+ Token parseToken = findTokenAt(firstToken, originalOffset);
+ if (parseToken == null) {
+ return null;
+ }
+ Parser parser = new Parser(_source, _errorListener);
+ parser.currentToken = parseToken;
+ while (newNode == null) {
+ ASTNode parent = oldNode.parent;
+ if (parent == null) {
+ parseToken = findFirstToken(parseToken);
+ parser.currentToken = parseToken;
+ return parser.parseCompilationUnit2() as ASTNode;
+ }
+ bool advanceToParent = false;
+ try {
+ IncrementalParseDispatcher dispatcher = new IncrementalParseDispatcher(parser, oldNode);
+ newNode = parent.accept(dispatcher);
+ Token mappedToken = _tokenMap.get(oldNode.endToken.next);
+ if (mappedToken == null || mappedToken.offset != newNode.endToken.next.offset || newNode.offset != oldNode.offset) {
+ advanceToParent = true;
+ }
+ } on InsufficientContextException catch (exception) {
+ advanceToParent = true;
+ } on JavaException catch (exception) {
+ return null;
+ }
+ if (advanceToParent) {
+ newNode = null;
+ oldNode = parent;
+ originalOffset = oldNode.offset;
+ parseToken = findTokenAt(parseToken, originalOffset);
+ parser.currentToken = parseToken;
+ }
+ }
+ if (identical(oldNode, originalStructure)) {
+ ResolutionCopier.copyResolutionData(oldNode, newNode);
+ return newNode as ASTNode;
+ }
+ ResolutionCopier.copyResolutionData(oldNode, newNode);
IncrementalASTCloner cloner = new IncrementalASTCloner(oldNode, newNode, _tokenMap);
return originalStructure.accept(cloner) as ASTNode;
}
@@ -1342,9 +1351,7 @@
InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseCompilationUnit");
try {
_currentToken = token;
- CompilationUnit compilationUnit = parseCompilationUnit2();
- gatherTodoComments(token);
- return compilationUnit;
+ return parseCompilationUnit2();
} finally {
instrumentation.log2(2);
}
@@ -1722,8 +1729,9 @@
if (partOfDirectiveFound) {
reportError9(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
} else {
- for (Directive precedingDirective in directives) {
- reportError10(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, precedingDirective.keyword, []);
+ int directiveCount = directives.length;
+ for (int i = 0; i < directiveCount; i++) {
+ reportError10(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
}
partOfDirectiveFound = true;
}
@@ -2529,7 +2537,15 @@
*
* @return the synthetic identifier that was created
*/
- SimpleIdentifier createSyntheticIdentifier() => new SimpleIdentifier.full(createSyntheticToken2(TokenType.IDENTIFIER));
+ SimpleIdentifier createSyntheticIdentifier() {
+ Token syntheticToken;
+ if (identical(_currentToken.type, TokenType.KEYWORD)) {
+ syntheticToken = injectToken(new SyntheticStringToken(TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
+ } else {
+ syntheticToken = createSyntheticToken2(TokenType.IDENTIFIER);
+ }
+ return new SimpleIdentifier.full(syntheticToken);
+ }
/**
* Create a synthetic string literal.
@@ -2543,14 +2559,14 @@
*
* @return the synthetic token that was created
*/
- Token createSyntheticToken(Keyword keyword) => new Parser_SyntheticKeywordToken(keyword, _currentToken.offset);
+ Token createSyntheticToken(Keyword keyword) => injectToken(new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
/**
* Create a synthetic token with the given type.
*
* @return the synthetic token that was created
*/
- Token createSyntheticToken2(TokenType type) => new StringToken(type, "", _currentToken.offset);
+ Token createSyntheticToken2(TokenType type) => injectToken(new StringToken(type, "", _currentToken.offset));
/**
* Check that the given expression is assignable and report an error if it isn't.
@@ -2617,7 +2633,9 @@
* @return the range that was found
*/
List<int> findRange(List<List<int>> ranges, int index) {
- for (List<int> range in ranges) {
+ int rangeCount = ranges.length;
+ for (int i = 0; i < rangeCount; i++) {
+ List<int> range = ranges[i];
if (range[0] <= index && index <= range[1]) {
return range;
} else if (index < range[0]) {
@@ -2627,19 +2645,6 @@
return null;
}
- void gatherTodoComments(Token token) {
- while (token != null && token.type != TokenType.EOF) {
- Token commentToken = token.precedingComments;
- while (commentToken != null) {
- if (identical(commentToken.type, TokenType.SINGLE_LINE_COMMENT) || identical(commentToken.type, TokenType.MULTI_LINE_COMMENT)) {
- scrapeTodoComment(commentToken);
- }
- commentToken = commentToken.next;
- }
- token = token.next;
- }
- }
-
/**
* Advance to the next token in the token stream, making it the new current token.
*
@@ -2726,6 +2731,19 @@
}
/**
+ * Inject the given token into the token stream immediately before the current token.
+ *
+ * @param token the token to be added to the token stream
+ * @return the token that was just added to the token stream
+ */
+ Token injectToken(Token token) {
+ Token previous = _currentToken.previous;
+ token.setNext(_currentToken);
+ previous.setNext(token);
+ return token;
+ }
+
+ /**
* Return `true` if the current token appears to be the beginning of a function declaration.
*
* @return `true` if the current token appears to be the beginning of a function declaration
@@ -3623,12 +3641,11 @@
return null;
}
try {
- List<bool> errorFound = [false];
- AnalysisErrorListener listener = new AnalysisErrorListener_16(errorFound);
+ BooleanErrorListener listener = new BooleanErrorListener();
Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence(referenceSource), sourceOffset), listener);
scanner.setSourceStart(1, 1);
Token firstToken = scanner.tokenize();
- if (errorFound[0]) {
+ if (listener.errorReported) {
return null;
}
Token newKeyword = null;
@@ -3869,7 +3886,7 @@
}
} else {
body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
- if (constKeyword != null && factoryKeyword != null) {
+ if (constKeyword != null && factoryKeyword != null && externalKeyword == null) {
reportError10(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
} else if (body is EmptyFunctionBody) {
if (factoryKeyword != null && externalKeyword == null) {
@@ -5577,7 +5594,7 @@
if (definedLabels.contains(label)) {
reportError10(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
} else {
- javaSetAdd(definedLabels, label);
+ definedLabels.add(label);
}
Token colon = expect2(TokenType.COLON);
labels.add(new Label.full(identifier, colon));
@@ -6032,20 +6049,6 @@
}
/**
- * Look for user defined tasks in comments and convert them into info level analysis issues.
- *
- * @param commentToken the comment token to analyze
- */
- void scrapeTodoComment(Token commentToken) {
- JavaPatternMatcher matcher = new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
- if (matcher.find()) {
- int offset = commentToken.offset + matcher.start() + matcher.group(1).length;
- int length = matcher.group(2).length;
- // _errorListener.onError(new AnalysisError.con2(_source, offset, length, TodoCode.TODO, [matcher.group(2)]));
- }
- }
-
- /**
* Parse the 'final', 'const', 'var' or type preceding a variable declaration, starting at the
* given token, without actually creating a type or changing the current token. Return the token
* following the type that was parsed, or `null` if the given token is not the first token
@@ -6843,16 +6846,6 @@
int get length => 0;
}
-class AnalysisErrorListener_16 implements AnalysisErrorListener {
- List<bool> errorFound;
-
- AnalysisErrorListener_16(this.errorFound);
-
- void onError(AnalysisError error) {
- errorFound[0] = true;
- }
-}
-
/**
* The enumeration `ParserErrorCode` defines the error codes used for errors detected by the
* parser. The convention for this class is for the name of the error code to indicate the problem
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a329dae..c9f6551 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -152,8 +152,9 @@
element.methods = holder.methods;
element.typeParameters = typeParameters;
element.validMixin = _isValidMixin;
- for (FunctionTypeImpl functionType in _functionTypesToFix) {
- functionType.typeArguments = typeArguments;
+ int functionTypeCount = _functionTypesToFix.length;
+ for (int i = 0; i < functionTypeCount; i++) {
+ _functionTypesToFix[i].typeArguments = typeArguments;
}
_functionTypesToFix = null;
_currentHolder.addType(element);
@@ -1108,16 +1109,8 @@
* Instances of the class `HtmlUnitBuilder` build an element model for a single HTML unit.
*/
class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
- static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\"";
-
- static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'";
-
- static String _SCRIPT = "script";
-
static String _SRC = "src";
- static String _TYPE = "type";
-
/**
* The analysis context in which the element model will be built.
*/
@@ -1199,6 +1192,52 @@
return result;
}
+ Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
+ if (_parentNodes.contains(node)) {
+ return reportCircularity(node);
+ }
+ _parentNodes.add(node);
+ try {
+ Source htmlSource = _htmlElement.source;
+ ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
+ String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
+ if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
+ EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
+ try {
+ LibraryResolver resolver = new LibraryResolver(_context);
+ LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSource, _modificationStamp, node.script, true) as LibraryElementImpl;
+ script.scriptLibrary = library;
+ resolvedLibraries.addAll(resolver.resolvedLibraries);
+ errorListener.addAll(resolver.errorListener);
+ } on AnalysisException catch (exception) {
+ AnalysisEngine.instance.logger.logError3(exception);
+ }
+ node.scriptElement = script;
+ _scripts.add(script);
+ } else {
+ ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
+ if (scriptSourcePath != null) {
+ try {
+ scriptSourcePath = Uri.encodeFull(scriptSourcePath);
+ parseUriWithException(scriptSourcePath);
+ Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
+ script.scriptSource = scriptSource;
+ if (scriptSource == null || !scriptSource.exists()) {
+ reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute, [scriptSourcePath]);
+ }
+ } on URISyntaxException catch (exception) {
+ reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, [scriptSourcePath]);
+ }
+ }
+ node.scriptElement = script;
+ _scripts.add(script);
+ }
+ } finally {
+ _parentNodes.remove(node);
+ }
+ return null;
+ }
+
Object visitHtmlUnit(ht.HtmlUnit node) {
_parentNodes = new List<ht.XmlTagNode>();
_scripts = new List<HtmlScriptElement>();
@@ -1212,78 +1251,23 @@
return null;
}
- Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
+ Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
+ for (ht.EmbeddedExpression expression in node.expressions) {
+ resolveExpression(expression.expression);
+ }
+ return null;
+ }
Object visitXmlTagNode(ht.XmlTagNode node) {
if (_parentNodes.contains(node)) {
- JavaStringBuilder builder = new JavaStringBuilder();
- builder.append("Found circularity in XML nodes: ");
- bool first = true;
- for (ht.XmlTagNode pathNode in _parentNodes) {
- if (first) {
- first = false;
- } else {
- builder.append(", ");
- }
- String tagName = pathNode.tag.lexeme;
- if (identical(pathNode, node)) {
- builder.append("*");
- builder.append(tagName);
- builder.append("*");
- } else {
- builder.append(tagName);
- }
- }
- AnalysisEngine.instance.logger.logError(builder.toString());
- return null;
+ return reportCircularity(node);
}
_parentNodes.add(node);
try {
- if (isScriptNode(node)) {
- Source htmlSource = _htmlElement.source;
- ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
- String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
- if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
- EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
- String contents = node.content;
- int attributeEnd = node.attributeEnd.end;
- LineInfo_Location location = _lineInfo.getLocation(attributeEnd);
- sc.Scanner scanner = new sc.Scanner(htmlSource, new sc.SubSequenceReader(new CharSequence(contents), attributeEnd), errorListener);
- scanner.setSourceStart(location.lineNumber, location.columnNumber);
- sc.Token firstToken = scanner.tokenize();
- List<int> lineStarts = scanner.lineStarts;
- Parser parser = new Parser(htmlSource, errorListener);
- CompilationUnit unit = parser.parseCompilationUnit(firstToken);
- try {
- LibraryResolver resolver = new LibraryResolver(_context);
- LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSource, _modificationStamp, unit, true) as LibraryElementImpl;
- script.scriptLibrary = library;
- resolvedLibraries.addAll(resolver.resolvedLibraries);
- errorListener.addAll(resolver.errorListener);
- } on AnalysisException catch (exception) {
- AnalysisEngine.instance.logger.logError3(exception);
- }
- _scripts.add(script);
- } else {
- ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
- if (scriptSourcePath != null) {
- try {
- scriptSourcePath = Uri.encodeFull(scriptSourcePath);
- parseUriWithException(scriptSourcePath);
- Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
- script.scriptSource = scriptSource;
- if (scriptSource == null || !scriptSource.exists()) {
- reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute, [scriptSourcePath]);
- }
- } on URISyntaxException catch (exception) {
- reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, [scriptSourcePath]);
- }
- }
- _scripts.add(script);
- }
- } else {
- node.visitChildren(this);
+ for (ht.EmbeddedExpression expression in node.expressions) {
+ resolveExpression(expression.expression);
}
+ node.visitChildren(this);
} finally {
_parentNodes.remove(node);
}
@@ -1305,28 +1289,27 @@
return null;
}
- /**
- * Determine if the specified node is a Dart script.
- *
- * @param node the node to be tested (not `null`)
- * @return `true` if the node is a Dart script
- */
- bool isScriptNode(ht.XmlTagNode node) {
- if (node.tagNodes.length != 0 || node.tag.lexeme != _SCRIPT) {
- return false;
- }
- for (ht.XmlAttributeNode attribute in node.attributes) {
- if (attribute.name.lexeme == _TYPE) {
- ht.Token valueToken = attribute.value;
- if (valueToken != null) {
- String value = valueToken.lexeme;
- if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
- return true;
- }
- }
+ Object reportCircularity(ht.XmlTagNode node) {
+ JavaStringBuilder builder = new JavaStringBuilder();
+ builder.append("Found circularity in XML nodes: ");
+ bool first = true;
+ for (ht.XmlTagNode pathNode in _parentNodes) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(", ");
+ }
+ String tagName = pathNode.tag.lexeme;
+ if (identical(pathNode, node)) {
+ builder.append("*");
+ builder.append(tagName);
+ builder.append("*");
+ } else {
+ builder.append(tagName);
}
}
- return false;
+ AnalysisEngine.instance.logger.logError(builder.toString());
+ return null;
}
/**
@@ -1356,6 +1339,9 @@
int length = attribute.value.length - 2;
reportError(errorCode, offset, length, arguments);
}
+
+ void resolveExpression(Expression expression) {
+ }
}
/**
@@ -1589,7 +1575,11 @@
* @see HintCode#DEPRECATED_MEMBER_USE
*/
bool checkForDeprecatedMemberUse2(SimpleIdentifier identifier) {
- if (identifier.inDeclarationContext() || (identifier.parent is ConstructorName && identical(identifier, (identifier.parent as ConstructorName).name)) || (identifier.parent is SuperConstructorInvocation && identical(identifier, (identifier.parent as SuperConstructorInvocation).constructorName))) {
+ if (identifier.inDeclarationContext()) {
+ return false;
+ }
+ ASTNode parent = identifier.parent;
+ if ((parent is ConstructorName && identical(identifier, (parent as ConstructorName).name)) || (parent is SuperConstructorInvocation && identical(identifier, (parent as SuperConstructorInvocation).constructorName)) || parent is HideCombinator) {
return false;
}
return checkForDeprecatedMemberUse(identifier.bestElement, identifier);
@@ -2087,6 +2077,7 @@
new Dart2JSVerifier(errorReporter).visitCompilationUnit(unit);
}
new BestPracticesVerifier(errorReporter).visitCompilationUnit(unit);
+ new ToDoFinder(errorReporter).findIn(unit);
}
}
@@ -2547,6 +2538,68 @@
}
/**
+ * Instances of the class `ToDoFinder` find to-do comments in Dart code.
+ */
+class ToDoFinder {
+ /**
+ * The error reporter by which to-do comments will be reported.
+ */
+ ErrorReporter _errorReporter;
+
+ /**
+ * Initialize a newly created to-do finder to report to-do comments to the given reporter.
+ *
+ * @param errorReporter the error reporter by which to-do comments will be reported
+ */
+ ToDoFinder(ErrorReporter errorReporter) {
+ this._errorReporter = errorReporter;
+ }
+
+ /**
+ * Search the comments in the given compilation unit for to-do comments and report an error for
+ * each.
+ *
+ * @param unit the compilation unit containing the to-do comments
+ */
+ void findIn(CompilationUnit unit) {
+ gatherTodoComments(unit.beginToken);
+ }
+
+ /**
+ * Search the comment tokens reachable from the given token and create errors for each to-do
+ * comment.
+ *
+ * @param token the head of the list of tokens being searched
+ */
+ void gatherTodoComments(sc.Token token) {
+ while (token != null && token.type != sc.TokenType.EOF) {
+ sc.Token commentToken = token.precedingComments;
+ while (commentToken != null) {
+ if (identical(commentToken.type, sc.TokenType.SINGLE_LINE_COMMENT) || identical(commentToken.type, sc.TokenType.MULTI_LINE_COMMENT)) {
+ scrapeTodoComment(commentToken);
+ }
+ commentToken = commentToken.next;
+ }
+ token = token.next;
+ }
+ }
+
+ /**
+ * Look for user defined tasks in comments and convert them into info level analysis issues.
+ *
+ * @param commentToken the comment token to analyze
+ */
+ void scrapeTodoComment(sc.Token commentToken) {
+ JavaPatternMatcher matcher = new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
+ if (matcher.find()) {
+ int offset = commentToken.offset + matcher.start() + matcher.group(1).length;
+ int length = matcher.group(2).length;
+ _errorReporter.reportError4(TodoCode.TODO, offset, length, [matcher.group(2)]);
+ }
+ }
+}
+
+/**
* Instances of the class `DeclarationMatcher` determine whether the element model defined by
* a given AST structure matches an existing element model.
*/
@@ -3154,8 +3207,8 @@
GeneralizingElementVisitor_7(this.DeclarationMatcher_this) : super();
Object visitElement(Element element) {
- javaSetAdd(DeclarationMatcher_this._allElements, element);
- javaSetAdd(DeclarationMatcher_this._unmatchedElements, element);
+ DeclarationMatcher_this._allElements.add(element);
+ DeclarationMatcher_this._unmatchedElements.add(element);
return super.visitElement(element);
}
}
@@ -3806,12 +3859,6 @@
LibraryElement _definingLibrary;
/**
- * A flag indicating whether we are running in strict mode. In strict mode, error reporting is
- * based exclusively on the static type information.
- */
- bool _strictMode = false;
-
- /**
* A flag indicating whether we should generate hints.
*/
bool _enableHints = false;
@@ -3857,7 +3904,6 @@
this._resolver = resolver;
this._definingLibrary = resolver.definingLibrary;
AnalysisOptions options = _definingLibrary.context.analysisOptions;
- _strictMode = options.strictMode;
_enableHints = options.hint;
_dynamicType = resolver.typeProvider.dynamicType;
_typeType = resolver.typeProvider.typeType;
@@ -3879,7 +3925,7 @@
Type2 propagatedType = getPropagatedType(leftHandSide);
MethodElement propagatedMethod = lookUpMethod(leftHandSide, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -3909,7 +3955,7 @@
Type2 propagatedType = getPropagatedType(leftOperand);
MethodElement propagatedMethod = lookUpMethod(leftOperand, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4246,6 +4292,9 @@
Object visitMethodInvocation(MethodInvocation node) {
SimpleIdentifier methodName = node.methodName;
+ if (methodName.isSynthetic) {
+ return null;
+ }
Expression target = node.realTarget;
if (target is SuperExpression && !isSuperInValidContext(target as SuperExpression)) {
return null;
@@ -4368,7 +4417,7 @@
Type2 propagatedType = getPropagatedType(operand);
MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4442,7 +4491,7 @@
Type2 propagatedType = getPropagatedType(operand);
MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
node.propagatedElement = propagatedMethod;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4497,6 +4546,9 @@
}
Object visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.isSynthetic) {
+ return null;
+ }
if (node.staticElement != null) {
return null;
}
@@ -4603,8 +4655,9 @@
* @param annotations the AST nodes used to generate new elements
*/
void addAnnotations(List<ElementAnnotationImpl> annotationList, NodeList<Annotation> annotations) {
- for (Annotation annotationNode in annotations) {
- Element resolvedElement = annotationNode.element;
+ int annotationCount = annotations.length;
+ for (int i = 0; i < annotationCount; i++) {
+ Element resolvedElement = annotations[i].element;
if (resolvedElement != null) {
annotationList.add(new ElementAnnotationImpl(resolvedElement));
}
@@ -4690,7 +4743,7 @@
* @return `true` if and only if an error code is generated on the passed node
*/
bool checkForUndefinedIndexOperator(IndexExpression node, Expression target, String methodName, MethodElement staticMethod, MethodElement propagatedMethod, Type2 staticType, Type2 propagatedType) {
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4973,7 +5026,7 @@
if (visitedInterfaces.contains(targetClass)) {
return null;
}
- javaSetAdd(visitedInterfaces, targetClass);
+ visitedInterfaces.add(targetClass);
if (includeTargetType) {
PropertyAccessorElement getter = targetType.getGetter(getterName);
if (getter != null && getter.isAccessibleIn(_definingLibrary)) {
@@ -5042,7 +5095,7 @@
if (visitedInterfaces.contains(targetClass)) {
return null;
}
- javaSetAdd(visitedInterfaces, targetClass);
+ visitedInterfaces.add(targetClass);
if (includeTargetType) {
ExecutableElement member = targetType.getMethod(memberName);
if (member != null) {
@@ -5156,7 +5209,7 @@
if (visitedInterfaces.contains(targetClass)) {
return null;
}
- javaSetAdd(visitedInterfaces, targetClass);
+ visitedInterfaces.add(targetClass);
if (includeTargetType) {
MethodElement method = targetType.getMethod(methodName);
if (method != null && method.isAccessibleIn(_definingLibrary)) {
@@ -5226,7 +5279,7 @@
if (visitedInterfaces.contains(targetClass)) {
return null;
}
- javaSetAdd(visitedInterfaces, targetClass);
+ visitedInterfaces.add(targetClass);
if (includeTargetType) {
PropertyAccessorElement setter = targetType.getSetter(setterName);
if (setter != null && setter.isAccessibleIn(_definingLibrary)) {
@@ -5485,7 +5538,7 @@
resolvedParameters[i] = element;
nameNode.staticElement = element;
}
- if (!javaSetAdd(usedNames, name)) {
+ if (!usedNames.add(name)) {
_resolver.reportError6(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
}
} else {
@@ -5655,7 +5708,7 @@
}
propertyName.staticElement = staticElement;
propertyName.propagatedElement = propagatedElement;
- bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticElement) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedElement));
+ bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticElement);
bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedElement) : false;
if (shouldReportMissingMember_propagated) {
if (memberFoundInSubclass(propagatedType.element, propertyName.name, false, true)) {
@@ -5758,15 +5811,6 @@
}
/**
- * Return the propagated element if it is not `null`, or the static element if it is.
- *
- * @param staticElement the element computed using static type information
- * @param propagatedElement the element computed using propagated type information
- * @return the more specific of the two elements
- */
- ExecutableElement select(ExecutableElement staticElement, ExecutableElement propagatedElement) => propagatedElement != null ? propagatedElement : staticElement;
-
- /**
* Given a node that can have annotations associated with it and the element to which that node
* has been resolved, create the annotations in the element model representing the annotations on
* the node.
@@ -5843,6 +5887,8 @@
String get name => _name;
+ int get precedence => 16;
+
Element get propagatedElement => null;
Element get staticElement => null;
@@ -6191,7 +6237,7 @@
}
if (superclassElt != null) {
if (!visitedClasses.contains(superclassElt)) {
- javaSetAdd(visitedClasses, classElt);
+ visitedClasses.add(classElt);
resultMap = new MemberMap.con2(computeClassChainLookupMap(superclassElt, visitedClasses));
} else {
_classLookup[superclassElt] = resultMap;
@@ -6281,7 +6327,7 @@
if (superclassElement != null) {
if (!visitedInterfaces.contains(superclassElement)) {
try {
- javaSetAdd(visitedInterfaces, superclassElement);
+ visitedInterfaces.add(superclassElement);
MemberMap map = computeInterfaceLookupMap(superclassElement, visitedInterfaces);
map = new MemberMap.con2(map);
substituteTypeParametersDownHierarchy(supertype, map);
@@ -6310,7 +6356,7 @@
if (interfaceElement != null) {
if (!visitedInterfaces.contains(interfaceElement)) {
try {
- javaSetAdd(visitedInterfaces, interfaceElement);
+ visitedInterfaces.add(interfaceElement);
MemberMap map = computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
map = new MemberMap.con2(map);
substituteTypeParametersDownHierarchy(interfaceType, map);
@@ -6346,7 +6392,7 @@
set = new Set<ExecutableElement>();
unionMap[key] = set;
}
- javaSetAdd(set, lookupMap.getValue(i));
+ set.add(lookupMap.getValue(i));
}
}
for (MapEntry<String, Set<ExecutableElement>> entry in getMapEntrySet(unionMap)) {
@@ -6479,7 +6525,7 @@
errorSet = new Set<AnalysisError>();
_errorsInClassElement[classElt] = errorSet;
}
- javaSetAdd(errorSet, new AnalysisError.con2(classElt.source, offset, length, errorCode, arguments));
+ errorSet.add(new AnalysisError.con2(classElt.source, offset, length, errorCode, arguments));
}
/**
@@ -6646,10 +6692,10 @@
List<Library> get importsAndExports {
Set<Library> libraries = new Set<Library>();
for (Library library in imports) {
- javaSetAdd(libraries, library);
+ libraries.add(library);
}
for (Library library in exports) {
- javaSetAdd(libraries, library);
+ libraries.add(library);
}
return new List.from(libraries);
}
@@ -7101,7 +7147,10 @@
Library targetLibrary = createLibrary(librarySource);
_coreLibrary = _libraryMap[_coreLibrarySource];
if (_coreLibrary == null) {
- _coreLibrary = createLibrary(_coreLibrarySource);
+ _coreLibrary = createLibraryOrNull(_coreLibrarySource);
+ if (_coreLibrary == null) {
+ throw new AnalysisException.con1("Core library does not exist");
+ }
}
instrumentation.metric3("createLibrary", "complete");
computeLibraryDependencies(targetLibrary);
@@ -7158,7 +7207,7 @@
* libraries are referenced
*/
void addLibrariesInCycle(Library library, Set<Library> librariesInCycle, Map<Library, List<Library>> dependencyMap) {
- if (javaSetAdd(librariesInCycle, library)) {
+ if (librariesInCycle.add(library)) {
List<Library> dependentLibraries = dependencyMap[library];
if (dependentLibraries != null) {
for (Library dependentLibrary in dependentLibraries) {
@@ -7178,7 +7227,7 @@
* recursion
*/
void addToDependencyMap(Library library, Map<Library, List<Library>> dependencyMap, Set<Library> visitedLibraries) {
- if (javaSetAdd(visitedLibraries, library)) {
+ if (visitedLibraries.add(library)) {
for (Library referencedLibrary in library.importsAndExports) {
addDependencyToMap(dependencyMap, library, referencedLibrary);
addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries);
@@ -7258,7 +7307,7 @@
}
directive.element = importElement;
imports.add(importElement);
- if (doesCompilationUnitHavePartOfDirective(importedLibrary.getAST(importedSource))) {
+ if (analysisContext.computeKindOf(importedSource) != SourceKind.LIBRARY) {
errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
}
}
@@ -7278,7 +7327,7 @@
}
directive.element = exportElement;
exports.add(exportElement);
- if (doesCompilationUnitHavePartOfDirective(exportedLibrary.getAST(exportedSource))) {
+ if (analysisContext.computeKindOf(exportedSource) != SourceKind.LIBRARY) {
StringLiteral uriLiteral = exportDirective.uri;
errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
}
@@ -7391,12 +7440,12 @@
if (directive is ExportDirective) {
Source exportSource = resolveSource(librarySource, directive as ExportDirective);
if (exportSource != null) {
- javaSetAdd(exportedSources, exportSource);
+ exportedSources.add(exportSource);
}
} else if (directive is ImportDirective) {
Source importSource = resolveSource(librarySource, directive as ImportDirective);
if (importSource != null) {
- javaSetAdd(importedSources, importSource);
+ importedSources.add(importSource);
}
}
}
@@ -7508,22 +7557,6 @@
}
/**
- * Return `true` if and only if the passed [CompilationUnit] has a part-of directive.
- *
- * @param node the [CompilationUnit] to test
- * @return `true` if and only if the passed [CompilationUnit] has a part-of directive
- */
- bool doesCompilationUnitHavePartOfDirective(CompilationUnit node) {
- NodeList<Directive> directives = node.directives;
- for (Directive directive in directives) {
- if (directive is PartOfDirective) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Return an array containing the lexical identifiers associated with the nodes in the given list.
*
* @param names the AST nodes representing the identifiers
@@ -7787,32 +7820,12 @@
*/
class ProxyConditionalAnalysisError {
/**
- * The name of the proxy annotation, from dart:core.
- */
- static String _PROXY_ANNOTATION_NAME = "proxy";
-
- /**
* Return `true` if the given element represents a class that has the proxy annotation.
*
* @param element the class being tested
* @return `true` if the given element represents a class that has the proxy annotation
*/
- static bool classHasProxyAnnotation(Element element) {
- if (element is ClassElement) {
- ClassElement classElement = element as ClassElement;
- List<ElementAnnotation> annotations = classElement.metadata;
- for (ElementAnnotation annotation in annotations) {
- Element elementAnnotation = annotation.element;
- if (elementAnnotation != null) {
- LibraryElement lib = elementAnnotation.library;
- if (lib != null && lib.isDartCore && elementAnnotation.name == _PROXY_ANNOTATION_NAME) {
- return true;
- }
- }
- }
- }
- return false;
- }
+ static bool classHasProxyAnnotation(Element element) => (element is ClassElement) && (element as ClassElement).isProxy;
/**
* The enclosing [ClassElement], this is what will determine if the error code should, or
@@ -8030,19 +8043,24 @@
Object visitCompilationUnit(CompilationUnit node) {
try {
overrideManager.enterScope();
- for (Directive directive in node.directives) {
- directive.accept(this);
+ NodeList<Directive> directives = node.directives;
+ int directiveCount = directives.length;
+ for (int i = 0; i < directiveCount; i++) {
+ directives[i].accept(this);
}
- List<CompilationUnitMember> classes = new List<CompilationUnitMember>();
- for (CompilationUnitMember declaration in node.declarations) {
- if (declaration is ClassDeclaration) {
- classes.add(declaration);
- } else {
+ NodeList<CompilationUnitMember> declarations = node.declarations;
+ int declarationCount = declarations.length;
+ for (int i = 0; i < declarationCount; i++) {
+ CompilationUnitMember declaration = declarations[i];
+ if (declaration is! ClassDeclaration) {
declaration.accept(this);
}
}
- for (CompilationUnitMember declaration in classes) {
- declaration.accept(this);
+ for (int i = 0; i < declarationCount; i++) {
+ CompilationUnitMember declaration = declarations[i];
+ if (declaration is ClassDeclaration) {
+ declaration.accept(this);
+ }
}
} finally {
overrideManager.exitScope();
@@ -9449,18 +9467,20 @@
* its declaration statement.
*/
void hideNamesDefinedInBlock(EnclosedScope scope, Block block) {
- for (Statement statement in block.statements) {
+ NodeList<Statement> statements = block.statements;
+ int statementCount = statements.length;
+ for (int i = 0; i < statementCount; i++) {
+ Statement statement = statements[i];
if (statement is VariableDeclarationStatement) {
VariableDeclarationStatement vds = statement as VariableDeclarationStatement;
- for (VariableDeclaration variableDeclaration in vds.variables.variables) {
- Element element = variableDeclaration.element;
- scope.hide(element);
+ NodeList<VariableDeclaration> variables = vds.variables.variables;
+ int variableCount = variables.length;
+ for (int j = 0; j < variableCount; j++) {
+ scope.hide(variables[j].element);
}
- }
- if (statement is FunctionDeclarationStatement) {
+ } else if (statement is FunctionDeclarationStatement) {
FunctionDeclarationStatement fds = statement as FunctionDeclarationStatement;
- Element element = fds.functionDeclaration.element;
- scope.hide(element);
+ scope.hide(fds.functionDeclaration.element);
}
}
}
@@ -10157,6 +10177,15 @@
Object visitMethodInvocation(MethodInvocation node) {
SimpleIdentifier methodNameNode = node.methodName;
Element staticMethodElement = methodNameNode.staticElement;
+ if (staticMethodElement is LocalVariableElement) {
+ LocalVariableElement variable = staticMethodElement as LocalVariableElement;
+ Type2 staticType = variable.type;
+ recordStaticType(methodNameNode, staticType);
+ Type2 propagatedType = _overrideManager.getType(variable);
+ if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+ recordPropagatedType2(methodNameNode, propagatedType);
+ }
+ }
Type2 staticStaticType = computeStaticReturnType(staticMethodElement);
recordStaticType(node, staticStaticType);
Type2 staticPropagatedType = computePropagatedReturnType(staticMethodElement);
@@ -11119,7 +11148,7 @@
* @param allSubtypes the computed set of subtypes of the passed class element
*/
void computeAllSubtypes2(ClassElement classElement, Set<ClassElement> visitedClasses, Set<ClassElement> allSubtypes) {
- if (!javaSetAdd(visitedClasses, classElement)) {
+ if (!visitedClasses.add(classElement)) {
return;
}
Set<ClassElement> subtypes = _subtypeMap[classElement];
@@ -11188,7 +11217,7 @@
if (libraryElement == null || _visitedLibraries.contains(libraryElement)) {
return;
}
- javaSetAdd(_visitedLibraries, libraryElement);
+ _visitedLibraries.add(libraryElement);
computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit);
List<CompilationUnitElement> parts = libraryElement.parts;
for (CompilationUnitElement part in parts) {
@@ -11216,7 +11245,7 @@
subtypes = new Set<ClassElement>();
_subtypeMap[supertypeElement] = subtypes;
}
- javaSetAdd(subtypes, subtypeElement);
+ subtypes.add(subtypeElement);
}
}
@@ -13165,7 +13194,7 @@
* A list of the namespaces representing the names that are available in this scope from imported
* libraries.
*/
- List<Namespace> _importedNamespaces = new List<Namespace>();
+ List<Namespace> _importedNamespaces;
/**
* Initialize a newly created scope representing the names imported into the given library.
@@ -13229,8 +13258,11 @@
*/
void createImportedNamespaces(LibraryElement definingLibrary) {
NamespaceBuilder builder = new NamespaceBuilder();
- for (ImportElement element in definingLibrary.imports) {
- _importedNamespaces.add(builder.createImportNamespace(element));
+ List<ImportElement> imports = definingLibrary.imports;
+ int count = imports.length;
+ _importedNamespaces = new List<Namespace>(count);
+ for (int i = 0; i < count; i++) {
+ _importedNamespaces[i] = builder.createImportNamespace(imports[i]);
}
}
@@ -13579,7 +13611,7 @@
* @return the mapping table that was created
*/
Map<String, Element> createExportMapping(LibraryElement library, Set<LibraryElement> visitedElements) {
- javaSetAdd(visitedElements, library);
+ visitedElements.add(library);
try {
Map<String, Element> definedNames = new Map<String, Element>();
for (ExportElement element in library.exports) {
@@ -14017,7 +14049,7 @@
if (keys.contains(value)) {
invalidKeys.add(key);
} else {
- javaSetAdd(keys, value);
+ keys.add(value);
}
}
} else {
@@ -14027,7 +14059,7 @@
if (keys.contains(value)) {
invalidKeys.add(key);
} else {
- javaSetAdd(keys, value);
+ keys.add(value);
}
} else {
reportEqualKeys = false;
@@ -14166,7 +14198,7 @@
* @param expression the expression to validate
*/
void validateInitializerExpression(List<ParameterElement> parameterElements, Expression expression) {
- EvaluationResultImpl result = expression.accept(new ConstantVisitor_14(this, parameterElements));
+ EvaluationResultImpl result = expression.accept(new ConstantVisitor_13(this, parameterElements));
reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
}
@@ -14212,12 +14244,12 @@
}
}
-class ConstantVisitor_14 extends ConstantVisitor {
+class ConstantVisitor_13 extends ConstantVisitor {
final ConstantVerifier ConstantVerifier_this;
List<ParameterElement> parameterElements;
- ConstantVisitor_14(this.ConstantVerifier_this, this.parameterElements) : super();
+ ConstantVisitor_13(this.ConstantVerifier_this, this.parameterElements) : super();
EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) {
Element element = node.staticElement;
@@ -14286,12 +14318,6 @@
InheritanceManager _inheritanceManager;
/**
- * A flag indicating whether we are running in strict mode. In strict mode, error reporting is
- * based exclusively on the static type information.
- */
- bool _strictMode = false;
-
- /**
* This is set to `true` iff the visitor is currently visiting children nodes of a
* [ConstructorDeclaration] and the constructor is 'const'.
*
@@ -14439,7 +14465,6 @@
this._isInSystemLibrary = currentLibrary.source.isInSystemLibrary;
this._typeProvider = typeProvider;
this._inheritanceManager = inheritanceManager;
- _strictMode = currentLibrary.context.analysisOptions.strictMode;
_isEnclosingConstructorConst = false;
_isInCatchClause = false;
_isInStaticVariableDeclaration = false;
@@ -14993,7 +15018,7 @@
checkForInvalidAssignment2(nameNode, initializerNode);
nameNode.accept(this);
String name = nameNode.name;
- javaSetAdd(_namesForReferenceToDeclaredVariableInInitializer, name);
+ _namesForReferenceToDeclaredVariableInInitializer.add(name);
_isInInstanceVariableInitializer = _isInInstanceVariableDeclaration;
try {
if (initializerNode != null) {
@@ -15160,7 +15185,7 @@
InterfaceType superclassType = _enclosingClass.supertype;
ClassElement superclassElement = superclassType == null ? null : superclassType.element;
while (superclassElement != null && !visitedClasses.contains(superclassElement)) {
- javaSetAdd(visitedClasses, superclassElement);
+ visitedClasses.add(superclassElement);
LibraryElement superclassLibrary = superclassElement.library;
List<FieldElement> fieldElts = superclassElement.fields;
for (FieldElement fieldElt in fieldElts) {
@@ -15650,30 +15675,12 @@
if (actualStaticType == null || expectedStaticType == null) {
return false;
}
- if (_strictMode) {
- if (actualStaticType.isAssignableTo(expectedStaticType)) {
- return false;
- }
- _errorReporter.reportError2(errorCode, expression, [
- actualStaticType.displayName,
- expectedStaticType.displayName]);
- return true;
- }
- if (actualPropagatedType == null || expectedPropagatedType == null) {
- if (actualStaticType.isAssignableTo(expectedStaticType)) {
- return false;
- }
- _errorReporter.reportError2(errorCode, expression, [
- actualStaticType.displayName,
- expectedStaticType.displayName]);
- return true;
- }
- if (actualStaticType.isAssignableTo(expectedStaticType) || actualStaticType.isAssignableTo(expectedPropagatedType) || actualPropagatedType.isAssignableTo(expectedStaticType) || actualPropagatedType.isAssignableTo(expectedPropagatedType)) {
+ if (actualStaticType.isAssignableTo(expectedStaticType)) {
return false;
}
_errorReporter.reportError2(errorCode, expression, [
- (actualPropagatedType == null ? actualStaticType : actualPropagatedType).displayName,
- (expectedPropagatedType == null ? expectedStaticType : expectedPropagatedType).displayName]);
+ actualStaticType.displayName,
+ expectedStaticType.displayName]);
return true;
}
@@ -16628,26 +16635,11 @@
}
if (staticType.isAssignableTo(fieldType)) {
return false;
- } else if (_strictMode) {
- if (_isEnclosingConstructorConst) {
- _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
- } else {
- _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
- }
- return true;
- }
- Type2 propagatedType = expression.propagatedType;
- if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
- return false;
}
if (_isEnclosingConstructorConst) {
- _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [
- (propagatedType == null ? staticType : propagatedType).displayName,
- fieldType.displayName]);
+ _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
} else {
- _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [
- (propagatedType == null ? staticType : propagatedType).displayName,
- fieldType.displayName]);
+ _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
}
return true;
}
@@ -17023,18 +17015,9 @@
Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
Type2 staticRightType = getStaticType(rhs);
bool isStaticAssignable = staticRightType.isAssignableTo(leftType);
- Type2 propagatedRightType = rhs.propagatedType;
- if (_strictMode || propagatedRightType == null) {
- if (!isStaticAssignable) {
- _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
- return true;
- }
- } else {
- bool isPropagatedAssignable = propagatedRightType.isAssignableTo(leftType);
- if (!isStaticAssignable && !isPropagatedAssignable) {
- _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
- return true;
- }
+ if (!isStaticAssignable) {
+ _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
+ return true;
}
return false;
}
@@ -17434,11 +17417,11 @@
if (methodName == ElementResolver.NO_SUCH_METHOD_METHOD_NAME) {
return false;
}
- javaSetAdd(methodsInEnclosingClass, methodName);
+ methodsInEnclosingClass.add(methodName);
}
Set<String> accessorsInEnclosingClass = new Set<String>();
for (PropertyAccessorElement accessor in accessors) {
- javaSetAdd(accessorsInEnclosingClass, accessor.name);
+ accessorsInEnclosingClass.add(accessor.name);
}
Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>();
MemberMap membersInheritedFromInterfaces = _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
@@ -17459,11 +17442,11 @@
}
if (executableElt is MethodElement) {
if (!methodsInEnclosingClass.contains(memberName) && !memberHasConcreteMethodImplementationInSuperclassChain(_enclosingClass, memberName, new List<ClassElement>())) {
- javaSetAdd(missingOverrides, executableElt);
+ missingOverrides.add(executableElt);
}
} else if (executableElt is PropertyAccessorElement) {
if (!accessorsInEnclosingClass.contains(memberName) && !memberHasConcreteAccessorImplementationInSuperclassChain(_enclosingClass, memberName, new List<ClassElement>())) {
- javaSetAdd(missingOverrides, executableElt);
+ missingOverrides.add(executableElt);
}
}
}
@@ -17931,27 +17914,14 @@
return true;
}
bool isStaticAssignable = staticReturnType.isAssignableTo(expectedReturnType);
- Type2 propagatedReturnType = returnExpression.propagatedType;
- if (_strictMode || propagatedReturnType == null) {
- if (isStaticAssignable) {
- return false;
- }
- _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
- staticReturnType.displayName,
- expectedReturnType.displayName,
- _enclosingFunction.displayName]);
- return true;
- } else {
- bool isPropagatedAssignable = propagatedReturnType.isAssignableTo(expectedReturnType);
- if (isStaticAssignable || isPropagatedAssignable) {
- return false;
- }
- _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
- staticReturnType.displayName,
- expectedReturnType.displayName,
- _enclosingFunction.displayName]);
- return true;
+ if (isStaticAssignable) {
+ return false;
}
+ _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
+ staticReturnType.displayName,
+ expectedReturnType.displayName,
+ _enclosingFunction.displayName]);
+ return true;
}
/**
@@ -18394,7 +18364,7 @@
if (constructors.contains(current)) {
return identical(current, element);
}
- javaSetAdd(constructors, current);
+ constructors.add(current);
current = current.redirectedConstructor;
if (current is ConstructorMember) {
current = (current as ConstructorMember).baseElement;
@@ -18431,8 +18401,8 @@
break;
}
}
- current.accept(new GeneralizingElementVisitor_15(target, toCheck));
- javaSetAdd(checked, current);
+ current.accept(new GeneralizingElementVisitor_14(target, toCheck));
+ checked.add(current);
}
}
@@ -18641,12 +18611,12 @@
INIT_STATE(String name, int ordinal) : super(name, ordinal);
}
-class GeneralizingElementVisitor_15 extends GeneralizingElementVisitor<Object> {
+class GeneralizingElementVisitor_14 extends GeneralizingElementVisitor<Object> {
Element target;
List<Element> toCheck;
- GeneralizingElementVisitor_15(this.target, this.toCheck) : super();
+ GeneralizingElementVisitor_14(this.target, this.toCheck) : super();
bool _inClass = false;
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index ff0a29a..413cf3b 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -526,6 +526,24 @@
}
/**
+ * Synthetic `StringToken` represent a token whose value is independent of it's type.
+ *
+ * @coverage dart.engine.parser
+ */
+class SyntheticStringToken extends StringToken {
+ /**
+ * Initialize a newly created token to represent a token of the given type with the given value.
+ *
+ * @param type the type of the token
+ * @param value the lexeme represented by this token
+ * @param offset the offset from the beginning of the file to the first character in the token
+ */
+ SyntheticStringToken(TokenType type, String value, int offset) : super(type, value, offset);
+
+ bool get isSynthetic => true;
+}
+
+/**
* Instances of the class `IncrementalScanner` implement a scanner that scans a subset of a
* string and inserts the resulting tokens into the middle of an existing token stream.
*
@@ -543,16 +561,23 @@
final TokenMap tokenMap = new TokenMap();
/**
- * The first token in the range of tokens that are different from the tokens in the original token
- * stream.
+ * The token in the new token stream immediately to the left of the range of tokens that were
+ * inserted, or the token immediately to the left of the modified region if there were no new
+ * tokens.
*/
- Token _firstToken;
+ Token leftToken;
/**
- * The last token in the range of tokens that are different from the tokens in the original token
- * stream.
+ * The token in the new token stream immediately to the right of the range of tokens that were
+ * inserted, or the token immediately to the right of the modified region if there were no new
+ * tokens.
*/
- Token lastToken;
+ Token rightToken;
+
+ /**
+ * A flag indicating whether there were any tokens changed as a result of the modification.
+ */
+ bool _hasNonWhitespaceChange2 = false;
/**
* Initialize a newly created scanner.
@@ -566,13 +591,12 @@
}
/**
- * Return the first token in the range of tokens that are different from the tokens in the
- * original token stream or `null` if the new tokens are the same as the original tokens
- * except for offset.
+ * Return `true` if there were any tokens either added or removed (or both) as a result of
+ * the modification.
*
- * @return the first token in the range of new tokens
+ * @return `true` if there were any tokens changed as a result of the modification
*/
- Token get firstToken => _firstToken;
+ bool hasNonWhitespaceChange() => _hasNonWhitespaceChange2;
/**
* Given the stream of tokens scanned from the original source, the modified source (the result of
@@ -590,39 +614,64 @@
while (originalStream.type != TokenType.EOF && originalStream.end < index) {
originalStream = copyAndAdvance(originalStream, 0);
}
- Token lastCopied = tail;
- int modifiedEnd = index + insertedLength - 1;
- if (originalStream.offset < index) {
- modifiedEnd += originalStream.end - index - removedLength;
- }
- _reader.offset = Math.min(originalStream.offset, index) - 1;
- int next = _reader.advance();
- while (next != -1 && _reader.offset <= modifiedEnd) {
- next = bigSwitch(next);
- }
- _firstToken = lastCopied.next;
- lastToken = tail;
- if (_firstToken == null || identical(_firstToken.type, TokenType.EOF)) {
- _firstToken = null;
- lastToken = null;
- } else if (originalStream.end == index && _firstToken.end == index) {
- tokenMap.put(originalStream, _firstToken);
- if (identical(lastToken, _firstToken)) {
- lastToken = lastToken.next;
- }
- _firstToken = _firstToken.next;
- }
- int removedEnd = index + removedLength - 1 + Math.max(0, tail.end - index - insertedLength);
- while (originalStream.offset <= removedEnd) {
+ Token oldFirst = originalStream;
+ Token oldLeftToken = originalStream.previous;
+ leftToken = tail;
+ int removedEnd = index + (removedLength == 0 ? 0 : removedLength - 1);
+ while (originalStream.type != TokenType.EOF && originalStream.offset <= removedEnd) {
originalStream = originalStream.next;
}
- int delta = insertedLength - removedLength;
- while (originalStream.type != TokenType.EOF) {
- originalStream = copyAndAdvance(originalStream, delta);
+ Token oldLast;
+ Token oldRightToken;
+ if (originalStream.type != TokenType.EOF && removedEnd + 1 == originalStream.offset) {
+ oldLast = originalStream;
+ originalStream = originalStream.next;
+ oldRightToken = originalStream;
+ } else {
+ oldLast = originalStream.previous;
+ oldRightToken = originalStream;
}
- Token eof = copyAndAdvance(originalStream, delta);
- eof.setNextWithoutSettingPrevious(eof);
- return super.firstToken;
+ int delta = insertedLength - removedLength;
+ int scanStart = Math.min(oldFirst.offset, index);
+ int oldEnd = oldLast.end + delta - 1;
+ int newEnd = index + insertedLength - 1;
+ int scanEnd = Math.max(newEnd, oldEnd);
+ _reader.offset = scanStart - 1;
+ int next = _reader.advance();
+ while (next != -1 && _reader.offset <= scanEnd) {
+ next = bigSwitch(next);
+ }
+ if (identical(originalStream.type, TokenType.EOF)) {
+ copyAndAdvance(originalStream, delta);
+ rightToken = tail;
+ rightToken.setNextWithoutSettingPrevious(rightToken);
+ } else {
+ originalStream = copyAndAdvance(originalStream, delta);
+ rightToken = tail;
+ while (originalStream.type != TokenType.EOF) {
+ originalStream = copyAndAdvance(originalStream, delta);
+ }
+ Token eof = copyAndAdvance(originalStream, delta);
+ eof.setNextWithoutSettingPrevious(eof);
+ }
+ Token newFirst = leftToken.next;
+ while (newFirst != rightToken && oldFirst != oldRightToken && newFirst.type != TokenType.EOF && equals3(oldFirst, newFirst)) {
+ tokenMap.put(oldFirst, newFirst);
+ oldLeftToken = oldFirst;
+ oldFirst = oldFirst.next;
+ leftToken = newFirst;
+ newFirst = newFirst.next;
+ }
+ Token newLast = rightToken.previous;
+ while (newLast != leftToken && oldLast != oldLeftToken && newLast.type != TokenType.EOF && equals3(oldLast, newLast)) {
+ tokenMap.put(oldLast, newLast);
+ oldRightToken = oldLast;
+ oldLast = oldLast.previous;
+ rightToken = newLast;
+ newLast = newLast.previous;
+ }
+ _hasNonWhitespaceChange2 = leftToken.next != rightToken || oldLeftToken.next != oldRightToken;
+ return firstToken;
}
Token copyAndAdvance(Token originalToken, int delta) {
@@ -639,6 +688,16 @@
}
return originalToken.next;
}
+
+ /**
+ * Return `true` if the two tokens are equal to each other. For the purposes of the
+ * incremental scanner, two tokens are equal if they have the same type and lexeme.
+ *
+ * @param oldToken the token from the old stream that is being compared
+ * @param newToken the token from the new stream that is being compared
+ * @return `true` if the two tokens are equal to each other
+ */
+ bool equals3(Token oldToken, Token newToken) => identical(oldToken.type, newToken.type) && oldToken.length == newToken.length && oldToken.lexeme == newToken.lexeme;
}
/**
@@ -1823,8 +1882,7 @@
/**
* Return `true` if this token is a synthetic token. A synthetic token is a token that was
- * introduced by the parser in order to recover from an error in the code. Synthetic tokens always
- * have a length of zero (`0`).
+ * introduced by the parser in order to recover from an error in the code.
*
* @return `true` if this token is a synthetic token
*/
@@ -2065,17 +2123,17 @@
/**
* A value used to indicate that the token type is a bitwise-and operator.
*/
- static final TokenClass BITWISE_AND_OPERATOR = new TokenClass.con2('BITWISE_AND_OPERATOR', 3, 8);
+ static final TokenClass BITWISE_AND_OPERATOR = new TokenClass.con2('BITWISE_AND_OPERATOR', 3, 10);
/**
* A value used to indicate that the token type is a bitwise-or operator.
*/
- static final TokenClass BITWISE_OR_OPERATOR = new TokenClass.con2('BITWISE_OR_OPERATOR', 4, 6);
+ static final TokenClass BITWISE_OR_OPERATOR = new TokenClass.con2('BITWISE_OR_OPERATOR', 4, 8);
/**
* A value used to indicate that the token type is a bitwise-xor operator.
*/
- static final TokenClass BITWISE_XOR_OPERATOR = new TokenClass.con2('BITWISE_XOR_OPERATOR', 5, 7);
+ static final TokenClass BITWISE_XOR_OPERATOR = new TokenClass.con2('BITWISE_XOR_OPERATOR', 5, 9);
/**
* A value used to indicate that the token type is a cascade operator.
@@ -2090,7 +2148,7 @@
/**
* A value used to indicate that the token type is an equality operator.
*/
- static final TokenClass EQUALITY_OPERATOR = new TokenClass.con2('EQUALITY_OPERATOR', 8, 9);
+ static final TokenClass EQUALITY_OPERATOR = new TokenClass.con2('EQUALITY_OPERATOR', 8, 6);
/**
* A value used to indicate that the token type is a logical-and operator.
@@ -2110,7 +2168,7 @@
/**
* A value used to indicate that the token type is a relational operator.
*/
- static final TokenClass RELATIONAL_OPERATOR = new TokenClass.con2('RELATIONAL_OPERATOR', 12, 10);
+ static final TokenClass RELATIONAL_OPERATOR = new TokenClass.con2('RELATIONAL_OPERATOR', 12, 7);
/**
* A value used to indicate that the token type is a shift operator.
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index c4985f0..e06e06b 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -62,11 +62,6 @@
static String _CHROMIUM_DIRECTORY_NAME = "chromium";
/**
- * The name of the environment variable whose value is the path to the default Dart SDK directory.
- */
- static String _DART_SDK_ENVIRONMENT_VARIABLE_NAME = "DART_SDK";
-
- /**
* The name of the file containing the Dartium executable on Linux.
*/
static String _DARTIUM_EXECUTABLE_NAME_LINUX = "chrome";
@@ -154,36 +149,16 @@
}
/**
- * Return the default Dart SDK, or `null` if the directory containing the default SDK cannot
- * be determined (or does not exist).
- *
- * Added in order to test AnalysisContextImpl2.
- *
- * @return the default Dart SDK
- */
- static DirectoryBasedDartSdk get defaultSdk2 {
- JavaFile sdkDirectory = defaultSdkDirectory;
- if (sdkDirectory == null) {
- return null;
- }
- return new DirectoryBasedDartSdk.con1(sdkDirectory, true);
- }
-
- /**
* Return the default directory for the Dart SDK, or `null` if the directory cannot be
* determined (or does not exist). The default directory is provided by a [System] property
- * named `com.google.dart.sdk`, or, if the property is not defined, an environment variable
- * named `DART_SDK`.
+ * named `com.google.dart.sdk`.
*
* @return the default directory for the Dart SDK
*/
static JavaFile get defaultSdkDirectory {
String sdkProperty = JavaSystemIO.getProperty(_DEFAULT_DIRECTORY_PROPERTY_NAME);
if (sdkProperty == null) {
- sdkProperty = JavaSystemIO.getenv(_DART_SDK_ENVIRONMENT_VARIABLE_NAME);
- if (sdkProperty == null) {
- return null;
- }
+ return null;
}
JavaFile sdkDirectory = new JavaFile(sdkProperty);
if (!sdkDirectory.exists()) {
@@ -471,14 +446,13 @@
* @return the library map read from the given source
*/
LibraryMap readFrom(JavaFile librariesFile, String libraryFileContents) {
- List<bool> foundError = [false];
- AnalysisErrorListener errorListener = new AnalysisErrorListener_11(foundError);
+ BooleanErrorListener errorListener = new BooleanErrorListener();
Source source = new FileBasedSource.con2(null, librariesFile, UriKind.FILE_URI);
Scanner scanner = new Scanner(source, new CharSequenceReader(new CharSequence(libraryFileContents)), errorListener);
Parser parser = new Parser(source, errorListener);
CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
SdkLibrariesReader_LibraryBuilder libraryBuilder = new SdkLibrariesReader_LibraryBuilder();
- if (!foundError[0]) {
+ if (!errorListener.errorReported) {
unit.accept(libraryBuilder);
}
return libraryBuilder.librariesMap;
@@ -564,16 +538,4 @@
}
return null;
}
-}
-
-class AnalysisErrorListener_11 implements AnalysisErrorListener {
- List<bool> foundError;
-
- AnalysisErrorListener_11(this.foundError);
-
- void onError(AnalysisError error) {
- if (error != null && error.errorCode.type != ErrorType.TODO) {
- foundError[0] = true;
- }
- }
}
\ No newline at end of file
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 7c3206e..f817d7b 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -8,6 +8,50 @@
import 'engine.dart' show AnalysisContext;
/**
+ * Instances of interface `LocalSourcePredicate` are used to determine if the given
+ * [Source] is "local" in some sense, so can be updated.
+ *
+ * @coverage dart.engine.source
+ */
+abstract class LocalSourcePredicate {
+ /**
+ * Instance of [LocalSourcePredicate] that always returns `false`.
+ */
+ static final LocalSourcePredicate _FALSE = new LocalSourcePredicate_15();
+
+ /**
+ * Instance of [LocalSourcePredicate] that always returns `true`.
+ */
+ static final LocalSourcePredicate _TRUE = new LocalSourcePredicate_16();
+
+ /**
+ * Instance of [LocalSourcePredicate] that returns `true` for all [Source]s
+ * except of SDK.
+ */
+ static final LocalSourcePredicate _NOT_SDK = new LocalSourcePredicate_17();
+
+ /**
+ * Determines if the given [Source] is local.
+ *
+ * @param source the [Source] to analyze
+ * @return `true` if the given [Source] is local
+ */
+ bool isLocal(Source source);
+}
+
+class LocalSourcePredicate_15 implements LocalSourcePredicate {
+ bool isLocal(Source source) => false;
+}
+
+class LocalSourcePredicate_16 implements LocalSourcePredicate {
+ bool isLocal(Source source) => true;
+}
+
+class LocalSourcePredicate_17 implements LocalSourcePredicate {
+ bool isLocal(Source source) => source.uriKind != UriKind.DART_URI;
+}
+
+/**
* Instances of the class `SourceFactory` resolve possibly relative URI's against an existing
* [Source].
*
@@ -20,14 +64,19 @@
AnalysisContext context;
/**
+ * A cache of content used to override the default content of a source.
+ */
+ ContentCache contentCache;
+
+ /**
* The resolvers used to resolve absolute URI's.
*/
List<UriResolver> _resolvers;
/**
- * A cache of content used to override the default content of a source.
+ * The predicate to determine is [Source] is local.
*/
- ContentCache contentCache;
+ LocalSourcePredicate _localSourcePredicate;
/**
* Initialize a newly created source factory.
@@ -38,6 +87,7 @@
SourceFactory.con1(ContentCache contentCache, List<UriResolver> resolvers) {
this.contentCache = contentCache;
this._resolvers = resolvers;
+ this._localSourcePredicate = LocalSourcePredicate._NOT_SDK;
}
/**
@@ -113,6 +163,14 @@
}
/**
+ * Determines if the given [Source] is local.
+ *
+ * @param source the [Source] to analyze
+ * @return `true` if the given [Source] is local
+ */
+ bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
+
+ /**
* Return a source object representing the URI that results from resolving the given (possibly
* relative) contained URI against the URI associated with an existing source object, or
* `null` if either the contained URI is invalid or if it cannot be resolved against the
@@ -161,6 +219,15 @@
String setContents(Source source, String contents) => contentCache.setContents(source, contents);
/**
+ * Sets the [LocalSourcePredicate].
+ *
+ * @param localSourcePredicate the predicate to determine is [Source] is local
+ */
+ void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
+ this._localSourcePredicate = localSourcePredicate;
+ }
+
+ /**
* Return the contents of the given source, or `null` if this factory does not override the
* contents of the source.
*
@@ -501,6 +568,11 @@
*/
class SourceRange {
/**
+ * An empty [SourceRange] with offset `0` and length `0`.
+ */
+ static SourceRange EMPTY = new SourceRange(0, 0);
+
+ /**
* The 0-based index of the first character of the source code for this element, relative to the
* source buffer in which this element is contained.
*/
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index e2ea6be..60bc557 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -10,6 +10,50 @@
export 'source.dart';
/**
+ * Instances of interface `LocalSourcePredicate` are used to determine if the given
+ * [Source] is "local" in some sense, so can be updated.
+ *
+ * @coverage dart.engine.source
+ */
+abstract class LocalSourcePredicate {
+ /**
+ * Instance of [LocalSourcePredicate] that always returns `false`.
+ */
+ static final LocalSourcePredicate _FALSE = new LocalSourcePredicate_15();
+
+ /**
+ * Instance of [LocalSourcePredicate] that always returns `true`.
+ */
+ static final LocalSourcePredicate _TRUE = new LocalSourcePredicate_16();
+
+ /**
+ * Instance of [LocalSourcePredicate] that returns `true` for all [Source]s
+ * except of SDK.
+ */
+ static final LocalSourcePredicate _NOT_SDK = new LocalSourcePredicate_17();
+
+ /**
+ * Determines if the given [Source] is local.
+ *
+ * @param source the [Source] to analyze
+ * @return `true` if the given [Source] is local
+ */
+ bool isLocal(Source source);
+}
+
+class LocalSourcePredicate_15 implements LocalSourcePredicate {
+ bool isLocal(Source source) => false;
+}
+
+class LocalSourcePredicate_16 implements LocalSourcePredicate {
+ bool isLocal(Source source) => true;
+}
+
+class LocalSourcePredicate_17 implements LocalSourcePredicate {
+ bool isLocal(Source source) => source.uriKind != UriKind.DART_URI;
+}
+
+/**
* Instances of the class `FileBasedSource` implement a source that represents a file.
*
* @coverage dart.engine.source
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index ccb5b6d..f54675a 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -355,6 +355,10 @@
/// A counter for spaces that should be emitted preceding the next token.
int leadingSpaces = 0;
+ /// A flag to specify whether line-leading spaces should be preserved (and
+ /// addded to the indent level).
+ bool allowLineLeadingSpaces;
+
/// Used for matching EOL comments
final twoSlashes = new RegExp(r'//[^/]');
@@ -393,7 +397,7 @@
visitArgumentList(ArgumentList node) {
token(node.leftParenthesis);
- visitNodes(node.arguments, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.arguments);
token(node.rightParenthesis);
}
@@ -462,7 +466,7 @@
visitCatchClause(CatchClause node) {
- token(node.onKeyword, precededBy: space, followedBy: space);
+ token(node.onKeyword, followedBy: space);
visit(node.exceptionType);
if (node.catchKeyword != null) {
@@ -595,9 +599,10 @@
space();
for (var i = 0; i < node.initializers.length; i++) {
if (i > 0) {
- comma();
+ // preceding comma
+ token(node.initializers[i].beginToken.previous);
newlines();
- space(2);
+ space(n: 2, allowLineLeading: true);
}
node.initializers[i].accept(this);
}
@@ -606,7 +611,7 @@
visitConstructorRedirects(ConstructorDeclaration node) {
token(node.separator /* = */, precededBy: space, followedBy: space);
- visitNodes(node.initializers, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.initializers);
visit(node.redirectedConstructor);
}
@@ -764,15 +769,24 @@
if (node.initialization != null) {
visit(node.initialization);
} else {
- visit(node.variables);
+ if (node.variables == null) {
+ space();
+ } else {
+ visit(node.variables);
+ }
}
token(node.leftSeparator);
space();
visit(node.condition);
token(node.rightSeparator);
- visitNodes(node.updaters, precededBy: space, separatedBy: space);
+ if (node.updaters != null) {
+ space();
+ visitCommaSeparatedNodes(node.updaters);
+ }
token(node.rightParenthesis);
- space();
+ if (node.body is! EmptyStatement) {
+ space();
+ }
visit(node.body);
}
@@ -817,7 +831,7 @@
visitHideCombinator(HideCombinator node) {
token(node.keyword);
space();
- visitNodes(node.hiddenNames, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.hiddenNames);
}
visitIfStatement(IfStatement node) {
@@ -842,7 +856,7 @@
visitImplementsClause(ImplementsClause node) {
token(node.keyword);
space();
- visitNodes(node.interfaces, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.interfaces);
}
visitImportDirective(ImportDirective node) {
@@ -926,8 +940,10 @@
modifier(node.constKeyword);
visit(node.typeArguments);
token(node.leftBracket);
- visitNodes(node.elements, separatedBy: commaSeperator);
+ indent();
+ visitCommaSeparatedNodes(node.elements);
optionalTrailingComma(node.rightBracket);
+ unindent();
token(node.rightBracket);
}
@@ -935,8 +951,10 @@
modifier(node.constKeyword);
visitNode(node.typeArguments, followedBy: space);
token(node.leftBracket);
- visitNodes(node.entries, separatedBy: commaSeperator);
+ indent();
+ visitCommaSeparatedNodes(node.entries);
optionalTrailingComma(node.rightBracket);
+ unindent();
token(node.rightBracket);
}
@@ -1068,7 +1086,7 @@
visitShowCombinator(ShowCombinator node) {
token(node.keyword);
space();
- visitNodes(node.shownNames, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.shownNames);
}
visitSimpleFormalParameter(SimpleFormalParameter node) {
@@ -1165,7 +1183,7 @@
visitTypeArgumentList(TypeArgumentList node) {
token(node.leftBracket);
- visitNodes(node.arguments, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.arguments);
token(node.rightBracket);
}
@@ -1182,7 +1200,7 @@
visitTypeParameterList(TypeParameterList node) {
token(node.leftBracket);
- visitNodes(node.typeParameters, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.typeParameters);
token(node.rightBracket);
}
@@ -1199,7 +1217,7 @@
visitVariableDeclarationList(VariableDeclarationList node) {
modifier(node.keyword);
visitNode(node.type, followedBy: space);
- visitNodes(node.variables, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.variables);
}
visitVariableDeclarationStatement(VariableDeclarationStatement node) {
@@ -1213,14 +1231,16 @@
token(node.leftParenthesis);
visit(node.condition);
token(node.rightParenthesis);
- space();
+ if (node.body is! EmptyStatement) {
+ space();
+ }
visit(node.body);
}
visitWithClause(WithClause node) {
token(node.withKeyword);
space();
- visitNodes(node.mixinTypes, separatedBy: commaSeperator);
+ visitCommaSeparatedNodes(node.mixinTypes);
}
/// Safely visit the given [node].
@@ -1262,6 +1282,26 @@
}
}
+ /// Visit a comma-separated list of [nodes] if not null.
+ visitCommaSeparatedNodes(NodeList<ASTNode> nodes) {
+ if (nodes != null) {
+ var size = nodes.length;
+ if (size > 0) {
+ var node;
+ for (var i = 0; i < size; i++) {
+ node = nodes[i];
+ if (i > 0) {
+ var comma = node.beginToken.previous;
+ token(comma);
+ space();
+ }
+ node.accept(this);
+ }
+ }
+ }
+ }
+
+
/// Visit a [node], and if not null, optionally preceded or followed by the
/// specified functions.
visitNode(ASTNode node, {precededBy(): null, followedBy(): null}) {
@@ -1292,7 +1332,7 @@
/// Optionally emit a trailing comma.
optionalTrailingComma(Token rightBracket) {
if (rightBracket.previous.lexeme == ',') {
- comma();
+ token(rightBracket.previous);
}
}
@@ -1319,7 +1359,10 @@
emitSpaces() {
while (leadingSpaces > 0) {
- writer.print(' ');
+ if (!writer.currentLine.isWhitespace() || allowLineLeadingSpaces) {
+ writer.print(' ');
+ }
+ allowLineLeadingSpaces = false;
leadingSpaces--;
}
}
@@ -1338,20 +1381,13 @@
}
}
- commaSeperator() {
- comma();
- space();
- }
-
- comma() {
- writer.print(',');
- }
-
-
- /// Emit a non-breakable space.
- space([n = 1]) {
+ /// Emit a non-breakable space. If [allowLineLeading] is specified, spaces
+ /// will be preserved at the start of a line (in addition to the
+ /// indent-level), otherwise line-leading spaces will be ignored.
+ space({n: 1, allowLineLeading: false}) {
//TODO(pquitslund): replace with a proper space token
leadingSpaces+=n;
+ allowLineLeadingSpaces = allowLineLeading;
}
/// Emit a breakable space
@@ -1413,7 +1449,8 @@
var lines = max(min, countNewlinesBetween(previousToken, currentToken));
writer.newlines(lines);
- previousToken = currentToken.previous;
+ previousToken =
+ currentToken.previous != null ? currentToken.previous : token.previous;
while (comment != null) {
@@ -1424,8 +1461,11 @@
if (newlines > 0) {
writer.newlines(newlines);
lines += newlines;
- } else if (!isEOF(token)) {
- append(' ');
+ } else {
+ var spaces = countSpacesBetween(comment, nextToken);
+ if (spaces > 0) {
+ space();
+ }
}
previousToken = comment;
@@ -1436,7 +1476,6 @@
return lines;
}
-
ensureTrailingNewline() {
if (writer.lastToken is! NewlineToken) {
writer.newline();
@@ -1451,11 +1490,11 @@
/// Emit this [comment], inserting leading whitespace if appropriate.
emitComment(Token comment, Token previousToken) {
- if (!writer.currentLine.isWhitespace() && !isBlock(comment)) {
+ if (!writer.currentLine.isWhitespace() && previousToken != null) {
var ws = countSpacesBetween(previousToken, comment);
// Preserve one space but no more
- if (ws > 0) {
- append(' ');
+ if (ws > 0 && leadingSpaces == 0) {
+ space();
}
}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 51639e1..fc47861 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.10.2
+version: 0.10.3
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/generated/ast_test.dart
index 5dc1b2d..ab7d96c 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/generated/ast_test.dart
@@ -1011,7 +1011,7 @@
"}"]);
CompilationUnit unit = ParserTestCase.parseCompilationUnit(source, []);
List<ASTNode> nodes = new List<ASTNode>();
- BreadthFirstVisitor<Object> visitor = new BreadthFirstVisitor_19(nodes);
+ BreadthFirstVisitor<Object> visitor = new BreadthFirstVisitor_20(nodes);
visitor.visitAllNodes(unit);
EngineTestCase.assertSize(59, nodes);
EngineTestCase.assertInstanceOf(CompilationUnit, nodes[0]);
@@ -1031,10 +1031,10 @@
}
}
-class BreadthFirstVisitor_19 extends BreadthFirstVisitor<Object> {
+class BreadthFirstVisitor_20 extends BreadthFirstVisitor<Object> {
List<ASTNode> nodes;
- BreadthFirstVisitor_19(this.nodes) : super();
+ BreadthFirstVisitor_20(this.nodes) : super();
Object visitNode(ASTNode node) {
nodes.add(node);
diff --git a/pkg/analyzer/test/generated/element_test.dart b/pkg/analyzer/test/generated/element_test.dart
index 496ce5e..cfa5913 100644
--- a/pkg/analyzer/test/generated/element_test.dart
+++ b/pkg/analyzer/test/generated/element_test.dart
@@ -1021,6 +1021,20 @@
JUnitTestCase.assertFalse(0 == typeA.hashCode);
}
+ void test_isAssignableTo_typeVariables() {
+ ClassElement classA = ElementFactory.classElement2("A", ["E"]);
+ ClassElement classB = ElementFactory.classElement2("B", ["F", "G"]);
+ InterfaceTypeImpl typeAF = new InterfaceTypeImpl.con1(classA);
+ typeAF.typeArguments = <Type2> [classB.typeParameters[0].type];
+ InterfaceTypeImpl typeAG = new InterfaceTypeImpl.con1(classA);
+ typeAG.typeArguments = <Type2> [classB.typeParameters[1].type];
+ JUnitTestCase.assertFalse(typeAG.isAssignableTo(typeAF));
+ }
+
+ void test_isAssignableTo_void() {
+ JUnitTestCase.assertFalse(VoidTypeImpl.instance.isAssignableTo(_typeProvider.intType));
+ }
+
void test_isDirectSupertypeOf_extends() {
ClassElement classA = ElementFactory.classElement2("A", []);
ClassElement classB = ElementFactory.classElement("B", classA.type, []);
@@ -1737,6 +1751,14 @@
final __test = new InterfaceTypeImplTest();
runJUnitTest(__test, __test.test_hashCode);
});
+ _ut.test('test_isAssignableTo_typeVariables', () {
+ final __test = new InterfaceTypeImplTest();
+ runJUnitTest(__test, __test.test_isAssignableTo_typeVariables);
+ });
+ _ut.test('test_isAssignableTo_void', () {
+ final __test = new InterfaceTypeImplTest();
+ runJUnitTest(__test, __test.test_isAssignableTo_void);
+ });
_ut.test('test_isDirectSupertypeOf_extends', () {
final __test = new InterfaceTypeImplTest();
runJUnitTest(__test, __test.test_isDirectSupertypeOf_extends);
@@ -2791,7 +2813,7 @@
void test_isSubtypeOf_baseCase_classFunction() {
ClassElementImpl functionElement = ElementFactory.classElement2("Function", []);
- InterfaceTypeImpl functionType = new InterfaceTypeImpl_24(functionElement);
+ InterfaceTypeImpl functionType = new InterfaceTypeImpl_25(functionElement);
FunctionType f = ElementFactory.functionElement("f").type;
JUnitTestCase.assertTrue(f.isSubtypeOf(functionType));
}
@@ -3290,8 +3312,8 @@
}
}
-class InterfaceTypeImpl_24 extends InterfaceTypeImpl {
- InterfaceTypeImpl_24(ClassElement arg0) : super.con1(arg0);
+class InterfaceTypeImpl_25 extends InterfaceTypeImpl {
+ InterfaceTypeImpl_25(ClassElement arg0) : super.con1(arg0);
bool get isDartCoreFunction => true;
}
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 8ea3dae..38a08d5 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4379,7 +4379,7 @@
* @throws Exception if the method could not be invoked or throws an exception
*/
String computeStringValue(String lexeme, bool first, bool last) {
- AnalysisErrorListener listener = new AnalysisErrorListener_25();
+ AnalysisErrorListener listener = new AnalysisErrorListener_26();
Parser parser = new Parser(null, listener);
return invokeParserMethodImpl(parser, "computeStringValue", <Object> [lexeme, first, last], null) as String;
}
@@ -6633,12 +6633,27 @@
}
}
-class AnalysisErrorListener_25 implements AnalysisErrorListener {
+class AnalysisErrorListener_26 implements AnalysisErrorListener {
void onError(AnalysisError event) {
JUnitTestCase.fail("Unexpected compilation error: ${event.message} (${event.offset}, ${event.length})");
}
}
+class NonErrorParserTest extends ParserTestCase {
+ void test_constFactory_external() {
+ ParserTestCase.parse("parseClassMember", <Object> ["C"], "external const factory C();");
+ }
+
+ static dartSuite() {
+ _ut.group('NonErrorParserTest', () {
+ _ut.test('test_constFactory_external', () {
+ final __test = new NonErrorParserTest();
+ runJUnitTest(__test, __test.test_constFactory_external);
+ });
+ });
+ }
+}
+
/**
* The class `ComplexParserTest` defines parser tests that test the parsing of more complex
* code fragments or the interactions between multiple parsing methods. For example, tests to ensure
@@ -9076,26 +9091,14 @@
}
class IncrementalParserTest extends EngineTestCase {
- void fail_delete_identifier_beginning() {
+ void fail_delete_everything() {
+ assertParse("", "f() => a + b;", "", "");
+ }
+
+ void test_delete_identifier_beginning() {
assertParse("f() => ", "ab", "", "s + b;");
}
- void fail_delete_mergeTokens() {
- assertParse("f() => a", " + b + ", "", "c;");
- }
-
- void fail_insert_convertOneFunctionToTwo() {
- assertParse("f()", "", " => 0; g()", " {}");
- }
-
- void fail_insert_period_betweenIdentifiers1() {
- assertParse("f() => a", "", ".", " b;");
- }
-
- void fail_replace_multiple_partialFirstAndLast() {
- assertParse("f() => a", "a + b", "b * a", "b;");
- }
-
void test_delete_identifier_end() {
assertParse("f() => a", "bs", "", " + b;");
}
@@ -9104,6 +9107,10 @@
assertParse("f() => a", "b", "", "s + b;");
}
+ void test_delete_mergeTokens() {
+ assertParse("f() => a", " + b + ", "", "c;");
+ }
+
void test_insert_afterIdentifier1() {
assertParse("f() => a", "", "bs", " + b;");
}
@@ -9120,6 +9127,18 @@
assertParse("f() => a + ", "", "x", "b;");
}
+ void test_insert_convertOneFunctionToTwo() {
+ assertParse("f()", "", " => 0; g()", " {}");
+ }
+
+ void test_insert_end() {
+ assertParse("class A {}", "", " class B {}", "");
+ }
+
+ void test_insert_insideIdentifier() {
+ assertParse("f() => co", "", "w.", "b;");
+ }
+
void test_insert_newIdentifier1() {
assertParse("f() => a;", "", " b", " c;");
}
@@ -9132,6 +9151,10 @@
assertParse("f() => a + b", "", ".", ";");
}
+ void test_insert_period_betweenIdentifiers1() {
+ assertParse("f() => a", "", ".", " b;");
+ }
+
void test_insert_period_betweenIdentifiers2() {
assertParse("f() => a ", "", ".", "b;");
}
@@ -9172,6 +9195,10 @@
assertParse("f() => f", "ir", "ro", "st + b;");
}
+ void test_replace_multiple_partialFirstAndLast() {
+ assertParse("f() => a", "a + b", "b * a", "b;");
+ }
+
void test_replace_operator_oneForMany() {
assertParse("f() => a ", "+", "* c -", " b;");
}
@@ -9213,13 +9240,17 @@
Token incrementalTokens = incrementalScanner.rescan(originalTokens, replaceStart, removed.length, added.length);
JUnitTestCase.assertNotNull(incrementalTokens);
IncrementalParser incrementalParser = new IncrementalParser(source, incrementalScanner.tokenMap, incrementalListener);
- CompilationUnit incrementalUnit = incrementalParser.reparse(originalUnit, incrementalScanner.firstToken, incrementalScanner.lastToken, replaceStart, prefix.length + removed.length);
+ CompilationUnit incrementalUnit = incrementalParser.reparse(originalUnit, incrementalScanner.leftToken, incrementalScanner.rightToken, replaceStart, prefix.length + removed.length);
JUnitTestCase.assertNotNull(incrementalUnit);
- JUnitTestCase.assertTrue(ASTComparator.equals3(modifiedUnit, incrementalUnit));
+ JUnitTestCase.assertTrue(ASTComparator.equals4(modifiedUnit, incrementalUnit));
}
static dartSuite() {
_ut.group('IncrementalParserTest', () {
+ _ut.test('test_delete_identifier_beginning', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_delete_identifier_beginning);
+ });
_ut.test('test_delete_identifier_end', () {
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_delete_identifier_end);
@@ -9228,6 +9259,10 @@
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_delete_identifier_middle);
});
+ _ut.test('test_delete_mergeTokens', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_delete_mergeTokens);
+ });
_ut.test('test_insert_afterIdentifier1', () {
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_insert_afterIdentifier1);
@@ -9244,6 +9279,18 @@
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_insert_beforeIdentifier2);
});
+ _ut.test('test_insert_convertOneFunctionToTwo', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_insert_convertOneFunctionToTwo);
+ });
+ _ut.test('test_insert_end', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_insert_end);
+ });
+ _ut.test('test_insert_insideIdentifier', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_insert_insideIdentifier);
+ });
_ut.test('test_insert_newIdentifier1', () {
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_insert_newIdentifier1);
@@ -9260,6 +9307,10 @@
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_insert_periodAndIdentifier);
});
+ _ut.test('test_insert_period_betweenIdentifiers1', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_insert_period_betweenIdentifiers1);
+ });
_ut.test('test_insert_period_betweenIdentifiers2', () {
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_insert_period_betweenIdentifiers2);
@@ -9296,6 +9347,10 @@
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_replace_identifier_middle);
});
+ _ut.test('test_replace_multiple_partialFirstAndLast', () {
+ final __test = new IncrementalParserTest();
+ runJUnitTest(__test, __test.test_replace_multiple_partialFirstAndLast);
+ });
_ut.test('test_replace_operator_oneForMany', () {
final __test = new IncrementalParserTest();
runJUnitTest(__test, __test.test_replace_operator_oneForMany);
@@ -11314,6 +11369,7 @@
ComplexParserTest.dartSuite();
ErrorParserTest.dartSuite();
IncrementalParserTest.dartSuite();
+ NonErrorParserTest.dartSuite();
RecoveryParserTest.dartSuite();
ResolutionCopierTest.dartSuite();
SimpleParserTest.dartSuite();
@@ -11364,10 +11420,10 @@
'ensureAssignable_1': new MethodTrampoline(1, (Parser target, arg0) => target.ensureAssignable(arg0)),
'expect_1': new MethodTrampoline(1, (Parser target, arg0) => target.expect(arg0)),
'findRange_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.findRange(arg0, arg1)),
- 'gatherTodoComments_1': new MethodTrampoline(1, (Parser target, arg0) => target.gatherTodoComments(arg0)),
'getCodeBlockRanges_1': new MethodTrampoline(1, (Parser target, arg0) => target.getCodeBlockRanges(arg0)),
'getEndToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.getEndToken(arg0)),
'hasReturnTypeInTypeAlias_0': new MethodTrampoline(0, (Parser target) => target.hasReturnTypeInTypeAlias()),
+ 'injectToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.injectToken(arg0)),
'isFunctionDeclaration_0': new MethodTrampoline(0, (Parser target) => target.isFunctionDeclaration()),
'isFunctionExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target.isFunctionExpression(arg0)),
'isHexDigit_1': new MethodTrampoline(1, (Parser target, arg0) => target.isHexDigit(arg0)),
@@ -11469,7 +11525,6 @@
'peek_1': new MethodTrampoline(1, (Parser target, arg0) => target.peek2(arg0)),
'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError(arg0, arg1, arg2)),
'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError9(arg0, arg1)),
- 'scrapeTodoComment_1': new MethodTrampoline(1, (Parser target, arg0) => target.scrapeTodoComment(arg0)),
'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFinalConstVarOrType(arg0)),
'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFormalParameterList(arg0)),
'skipPastMatchingToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipPastMatchingToken(arg0)),
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index e85b6c5..3bc159c 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1490,6 +1490,21 @@
verify([source]);
}
+ void test_deprecatedMemberUse_hide() {
+ Source source = addSource(EngineTestCase.createSource([
+ "library lib;",
+ "import 'lib1.dart' hide B;",
+ "A a = new A();"]));
+ addSource2("/lib1.dart", EngineTestCase.createSource([
+ "library lib1;",
+ "class A {}",
+ "@deprecated",
+ "class B {}"]));
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_duplicateDefinition_emptyName() {
Source source = addSource(EngineTestCase.createSource([
"Map _globalMap = {",
@@ -4131,6 +4146,18 @@
verify([source]);
}
+ void test_undefinedIdentifier_synthetic_whenExpression() {
+ Source source = addSource(EngineTestCase.createSource(["print(x) {}", "main() {", " print(is String);", "}"]));
+ resolve(source);
+ assertErrors(source, [ParserErrorCode.MISSING_IDENTIFIER]);
+ }
+
+ void test_undefinedIdentifier_synthetic_whenMethodName() {
+ Source source = addSource(EngineTestCase.createSource(["print(x) {}", "main(int p) {", " p.();", "}"]));
+ resolve(source);
+ assertErrors(source, [ParserErrorCode.MISSING_IDENTIFIER]);
+ }
+
void test_undefinedMethod_functionExpression_callMethod() {
Source source = addSource(EngineTestCase.createSource(["main() {", " (() => null).call();", "}"]));
resolve(source);
@@ -4460,6 +4487,10 @@
final __test = new NonErrorResolverTest();
runJUnitTest(__test, __test.test_defaultValueInFunctionTypedParameter_optional);
});
+ _ut.test('test_deprecatedMemberUse_hide', () {
+ final __test = new NonErrorResolverTest();
+ runJUnitTest(__test, __test.test_deprecatedMemberUse_hide);
+ });
_ut.test('test_duplicateDefinition_emptyName', () {
final __test = new NonErrorResolverTest();
runJUnitTest(__test, __test.test_duplicateDefinition_emptyName);
@@ -5388,6 +5419,14 @@
final __test = new NonErrorResolverTest();
runJUnitTest(__test, __test.test_undefinedIdentifier_show);
});
+ _ut.test('test_undefinedIdentifier_synthetic_whenExpression', () {
+ final __test = new NonErrorResolverTest();
+ runJUnitTest(__test, __test.test_undefinedIdentifier_synthetic_whenExpression);
+ });
+ _ut.test('test_undefinedIdentifier_synthetic_whenMethodName', () {
+ final __test = new NonErrorResolverTest();
+ runJUnitTest(__test, __test.test_undefinedIdentifier_synthetic_whenMethodName);
+ });
_ut.test('test_undefinedMethod_functionExpression_callMethod', () {
final __test = new NonErrorResolverTest();
runJUnitTest(__test, __test.test_undefinedMethod_functionExpression_callMethod);
@@ -12454,6 +12493,21 @@
verify([source]);
}
+ void test_typeAliasCannotReferenceItself_11987() {
+ Source source = addSource(EngineTestCase.createSource([
+ "typedef void F(List<G> l);",
+ "typedef void G(List<F> l);",
+ "main() {",
+ " F foo(G g) => g;",
+ "}"]));
+ resolve(source);
+ assertErrors(source, [
+ CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
+ CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
+ StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]);
+ verify([source]);
+ }
+
void test_typeAliasCannotReferenceItself_parameterType_named() {
Source source = addSource(EngineTestCase.createSource(["typedef A({A a});"]));
resolve(source);
@@ -13962,6 +14016,10 @@
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_superInRedirectingConstructor_superRedirection);
});
+ _ut.test('test_typeAliasCannotReferenceItself_11987', () {
+ final __test = new CompileTimeErrorCodeTest();
+ runJUnitTest(__test, __test.test_typeAliasCannotReferenceItself_11987);
+ });
_ut.test('test_typeAliasCannotReferenceItself_parameterType_named', () {
final __test = new CompileTimeErrorCodeTest();
runJUnitTest(__test, __test.test_typeAliasCannotReferenceItself_parameterType_named);
@@ -14312,7 +14370,6 @@
void setUp() {
super.setUp();
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
- options.strictMode = true;
options.hint = false;
analysisContext.analysisOptions = options;
}
@@ -21272,7 +21329,7 @@
class EnclosedScopeTest extends ResolverTestCase {
void test_define_duplicate() {
GatheringErrorListener errorListener2 = new GatheringErrorListener();
- Scope rootScope = new Scope_22(errorListener2);
+ Scope rootScope = new Scope_23(errorListener2);
EnclosedScope scope = new EnclosedScope(rootScope);
VariableElement element1 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
VariableElement element2 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
@@ -21283,7 +21340,7 @@
void test_define_normal() {
GatheringErrorListener errorListener3 = new GatheringErrorListener();
- Scope rootScope = new Scope_23(errorListener3);
+ Scope rootScope = new Scope_24(errorListener3);
EnclosedScope outerScope = new EnclosedScope(rootScope);
EnclosedScope innerScope = new EnclosedScope(outerScope);
VariableElement element1 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
@@ -21307,20 +21364,20 @@
}
}
-class Scope_22 extends Scope {
+class Scope_23 extends Scope {
GatheringErrorListener errorListener2;
- Scope_22(this.errorListener2) : super();
+ Scope_23(this.errorListener2) : super();
AnalysisErrorListener get errorListener => errorListener2;
Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary) => null;
}
-class Scope_23 extends Scope {
+class Scope_24 extends Scope {
GatheringErrorListener errorListener3;
- Scope_23(this.errorListener3) : super();
+ Scope_24(this.errorListener3) : super();
AnalysisErrorListener get errorListener => errorListener3;
@@ -22043,6 +22100,22 @@
verify([source]);
}
+ void test_localVariable_types_invoked() {
+ Source source = addSource(EngineTestCase.createSource([
+ "const A = null;",
+ "main() {",
+ " var myVar = (int p) => 'foo';",
+ " myVar(42);",
+ "}"]));
+ LibraryElement library = resolve(source);
+ JUnitTestCase.assertNotNull(library);
+ CompilationUnit unit = analysisContext.getResolvedCompilationUnit(source, library);
+ JUnitTestCase.assertNotNull(unit);
+ List<bool> found = [false];
+ unit.accept(new RecursiveASTVisitor_27(this, found));
+ JUnitTestCase.assertTrue(found[0]);
+ }
+
void test_metadata_class() {
Source source = addSource(EngineTestCase.createSource(["const A = null;", "@A class C {}"]));
LibraryElement library = resolve(source);
@@ -22380,6 +22453,10 @@
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_labels_switch);
});
+ _ut.test('test_localVariable_types_invoked', () {
+ final __test = new SimpleResolverTest();
+ runJUnitTest(__test, __test.test_localVariable_types_invoked);
+ });
_ut.test('test_metadata_class', () {
final __test = new SimpleResolverTest();
runJUnitTest(__test, __test.test_metadata_class);
@@ -22428,6 +22505,25 @@
}
}
+class RecursiveASTVisitor_27 extends RecursiveASTVisitor<Object> {
+ final SimpleResolverTest SimpleResolverTest_this;
+
+ List<bool> found;
+
+ RecursiveASTVisitor_27(this.SimpleResolverTest_this, this.found) : super();
+
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.name == "myVar" && node.parent is MethodInvocation) {
+ found[0] = true;
+ Type2 staticType = node.staticType;
+ JUnitTestCase.assertSame(SimpleResolverTest_this.typeProvider.dynamicType, staticType);
+ FunctionType propagatedType = node.propagatedType as FunctionType;
+ JUnitTestCase.assertEquals(SimpleResolverTest_this.typeProvider.stringType, propagatedType.returnType);
+ }
+ return null;
+ }
+}
+
class SubtypeManagerTest extends EngineTestCase {
/**
* The inheritance manager being tested.
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index d70eec5..04350a5 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -1879,146 +1879,183 @@
*/
Token _incrementalTokens;
- void fail_delete_identifier_beginning() {
+ void test_delete_identifier_beginning() {
scan("", "ab", "", "s + b;");
- assertTokens(0, 0, ["s", "+", "b", ";"]);
- }
-
- void fail_delete_mergeTokens() {
- scan("a", " + b + ", "", "c;");
- assertTokens(0, 0, ["ac", ";"]);
- }
-
- void fail_replace_multiple_partialFirstAndLast() {
- scan("a", "a + b", "b * a", "b;");
- assertTokens(0, 2, ["ab", "*", "ab", ";"]);
+ assertTokens(-1, 1, ["s", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_delete_identifier_end() {
scan("a", "bs", "", " + b;");
- assertTokens(0, 0, ["a", "+", "b", ";"]);
+ assertTokens(-1, 1, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_delete_identifier_middle() {
scan("a", "b", "", "s + b;");
- assertTokens(0, 0, ["as", "+", "b", ";"]);
+ assertTokens(-1, 1, ["as", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+ }
+
+ void test_delete_mergeTokens() {
+ scan("a", " + b + ", "", "c;");
+ assertTokens(-1, 1, ["ac", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_afterIdentifier1() {
scan("a", "", "bs", " + b;");
- assertTokens(0, 0, ["abs", "+", "b", ";"]);
+ assertTokens(-1, 1, ["abs", "+", "b", ";"]);
assertReplaced(1, "+");
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_afterIdentifier2() {
scan("a + b", "", "y", ";");
- assertTokens(2, 2, ["a", "+", "by", ";"]);
+ assertTokens(1, 3, ["a", "+", "by", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_beforeIdentifier() {
scan("a + ", "", "x", "b;");
- assertTokens(2, 2, ["a", "+", "xb", ";"]);
+ assertTokens(1, 3, ["a", "+", "xb", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_beforeIdentifier_firstToken() {
scan("", "", "x", "a + b;");
- assertTokens(0, 0, ["xa", "+", "b", ";"]);
+ assertTokens(-1, 1, ["xa", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_convertOneFunctionToTwo() {
scan("f()", "", " => 0; g()", " {}");
- assertTokens(3, 8, ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]);
+ assertTokens(2, 9, ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+ }
+
+ void test_insert_end() {
+ scan("class A {}", "", " class B {}", "");
+ assertTokens(3, 8, ["class", "A", "{", "}", "class", "B", "{", "}"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+ }
+
+ void test_insert_insideIdentifier() {
+ scan("co", "", "w.", "b;");
+ assertTokens(-1, 3, ["cow", ".", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_newIdentifier1() {
scan("a; ", "", "b", " c;");
- assertTokens(2, 2, ["a", ";", "b", "c", ";"]);
+ assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_newIdentifier2() {
scan("a;", "", "b", " c;");
- assertTokens(2, 2, ["a", ";", "b", "c", ";"]);
+ assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
assertReplaced(1, ";");
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_period() {
scan("a + b", "", ".", ";");
- assertTokens(3, 3, ["a", "+", "b", ".", ";"]);
+ assertTokens(2, 4, ["a", "+", "b", ".", ";"]);
}
void test_insert_period_betweenIdentifiers1() {
scan("a", "", ".", " b;");
- assertTokens(1, 1, ["a", ".", "b", ";"]);
+ assertTokens(0, 2, ["a", ".", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_period_betweenIdentifiers2() {
scan("a ", "", ".", "b;");
- assertTokens(1, 1, ["a", ".", "b", ";"]);
+ assertTokens(0, 2, ["a", ".", "b", ";"]);
}
void test_insert_period_betweenIdentifiers3() {
scan("a ", "", ".", " b;");
- assertTokens(1, 1, ["a", ".", "b", ";"]);
+ assertTokens(0, 2, ["a", ".", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_period_insideExistingIdentifier() {
scan("a", "", ".", "b;");
- assertTokens(0, 2, ["a", ".", "b", ";"]);
+ assertTokens(-1, 3, ["a", ".", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_periodAndIdentifier() {
scan("a + b", "", ".x", ";");
- assertTokens(3, 4, ["a", "+", "b", ".", "x", ";"]);
+ assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]);
}
void test_insert_whitespace_beginning_beforeToken() {
scan("", "", " ", "a + b;");
- assertTokens(-1, -1, ["a", "+", "b", ";"]);
+ assertTokens(0, 1, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_whitespace_betweenTokens() {
scan("a ", "", " ", "+ b;");
- assertTokens(-1, -1, ["a", "+", "b", ";"]);
+ assertTokens(1, 2, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_whitespace_end_afterToken() {
scan("a + b;", "", " ", "");
- assertTokens(-1, -1, ["a", "+", "b", ";"]);
+ assertTokens(3, 4, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_whitespace_end_afterWhitespace() {
scan("a + b; ", "", " ", "");
- assertTokens(-1, -1, ["a", "+", "b", ";"]);
+ assertTokens(3, 4, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
void test_insert_whitespace_withMultipleComments() {
scan(EngineTestCase.createSource(["//comment", "//comment2", "a"]), "", " ", " + b;");
- assertTokens(-1, -1, ["a", "+", "b", ";"]);
+ assertTokens(1, 2, ["a", "+", "b", ";"]);
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
void test_replace_identifier_beginning() {
scan("", "b", "f", "ell + b;");
- assertTokens(0, 0, ["fell", "+", "b", ";"]);
+ assertTokens(-1, 1, ["fell", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_replace_identifier_end() {
scan("bel", "l", "t", " + b;");
- assertTokens(0, 0, ["belt", "+", "b", ";"]);
+ assertTokens(-1, 1, ["belt", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_replace_identifier_middle() {
scan("f", "ir", "ro", "st + b;");
- assertTokens(0, 0, ["frost", "+", "b", ";"]);
+ assertTokens(-1, 1, ["frost", "+", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+ }
+
+ void test_replace_multiple_partialFirstAndLast() {
+ scan("a", "a + b", "b * a", "b;");
+ assertTokens(-1, 3, ["ab", "*", "ab", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_replace_operator_oneForMany() {
scan("a ", "+", "* c -", " b;");
- assertTokens(1, 3, ["a", "*", "c", "-", "b", ";"]);
+ assertTokens(0, 4, ["a", "*", "c", "-", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_replace_operator_oneForOne() {
scan("a ", "+", "*", " b;");
- assertTokens(1, 1, ["a", "*", "b", ";"]);
+ assertTokens(0, 2, ["a", "*", "b", ";"]);
+ JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
}
void test_tokenMap() {
@@ -2032,8 +2069,16 @@
JUnitTestCase.assertEquals(oldToken.lexeme, newToken.lexeme);
oldToken = oldToken.next;
}
+ JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
}
+ /**
+ * Assert that the token at the given offset was replaced with a new token having the given
+ * lexeme.
+ *
+ * @param tokenOffset the offset of the token being tested
+ * @param lexeme the expected lexeme of the new token
+ */
void assertReplaced(int tokenOffset, String lexeme) {
Token oldToken = _originalTokens;
for (int i = 0; i < tokenOffset; i++) {
@@ -2046,35 +2091,52 @@
JUnitTestCase.assertNotSame(oldToken, newToken);
}
- void assertTokens(int firstIndex, int lastIndex, List<String> lexemes) {
- Token firstToken = null;
- Token lastToken = null;
+ /**
+ * Assert that the result of the incremental scan matches the given list of lexemes and that the
+ * left and right tokens correspond to the tokens at the given indices.
+ *
+ * @param leftIndex the expected index of the left token
+ * @param rightIndex the expected index of the right token
+ * @param lexemes the expected lexemes of the resulting tokens
+ */
+ void assertTokens(int leftIndex, int rightIndex, List<String> lexemes) {
int count = lexemes.length;
+ JUnitTestCase.assertTrueMsg("Invalid left index", leftIndex >= -1 && leftIndex < count);
+ JUnitTestCase.assertTrueMsg("Invalid right index", rightIndex >= 0 && rightIndex <= count);
+ Token leftToken = null;
+ Token rightToken = null;
Token token = _incrementalTokens;
+ if (leftIndex < 0) {
+ leftToken = token.previous;
+ }
for (int i = 0; i < count; i++) {
JUnitTestCase.assertEquals(lexemes[i], token.lexeme);
- if (i == firstIndex) {
- firstToken = token;
+ if (i == leftIndex) {
+ leftToken = token;
}
- if (i == lastIndex) {
- lastToken = token;
+ if (i == rightIndex) {
+ rightToken = token;
}
token = token.next;
}
+ if (rightIndex >= count) {
+ rightToken = token;
+ }
JUnitTestCase.assertSameMsg("Too many tokens", TokenType.EOF, token.type);
- if (firstIndex >= 0) {
- JUnitTestCase.assertNotNull(firstToken);
+ if (leftIndex >= 0) {
+ JUnitTestCase.assertNotNull(leftToken);
}
- JUnitTestCase.assertSame(firstToken, _incrementalScanner.firstToken);
- if (lastIndex >= 0) {
- JUnitTestCase.assertNotNull(lastToken);
+ JUnitTestCase.assertSameMsg("Invalid left token", leftToken, _incrementalScanner.leftToken);
+ if (rightIndex >= 0) {
+ JUnitTestCase.assertNotNull(rightToken);
}
- JUnitTestCase.assertSame(lastToken, _incrementalScanner.lastToken);
+ JUnitTestCase.assertSameMsg("Invalid right token", rightToken, _incrementalScanner.rightToken);
}
/**
* Given a description of the original and modified contents, perform an incremental scan of the
- * two pieces of text.
+ * two pieces of text. Verify that the incremental scan produced the same tokens as those that
+ * would be produced by a full scan of the new contents.
*
* @param prefix the unchanged text before the edit region
* @param removed the text that was removed from the original contents
@@ -2113,6 +2175,10 @@
static dartSuite() {
_ut.group('IncrementalScannerTest', () {
+ _ut.test('test_delete_identifier_beginning', () {
+ final __test = new IncrementalScannerTest();
+ runJUnitTest(__test, __test.test_delete_identifier_beginning);
+ });
_ut.test('test_delete_identifier_end', () {
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_delete_identifier_end);
@@ -2121,6 +2187,10 @@
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_delete_identifier_middle);
});
+ _ut.test('test_delete_mergeTokens', () {
+ final __test = new IncrementalScannerTest();
+ runJUnitTest(__test, __test.test_delete_mergeTokens);
+ });
_ut.test('test_insert_afterIdentifier1', () {
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_insert_afterIdentifier1);
@@ -2141,6 +2211,14 @@
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_insert_convertOneFunctionToTwo);
});
+ _ut.test('test_insert_end', () {
+ final __test = new IncrementalScannerTest();
+ runJUnitTest(__test, __test.test_insert_end);
+ });
+ _ut.test('test_insert_insideIdentifier', () {
+ final __test = new IncrementalScannerTest();
+ runJUnitTest(__test, __test.test_insert_insideIdentifier);
+ });
_ut.test('test_insert_newIdentifier1', () {
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_insert_newIdentifier1);
@@ -2205,6 +2283,10 @@
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_replace_identifier_middle);
});
+ _ut.test('test_replace_multiple_partialFirstAndLast', () {
+ final __test = new IncrementalScannerTest();
+ runJUnitTest(__test, __test.test_replace_multiple_partialFirstAndLast);
+ });
_ut.test('test_replace_operator_oneForMany', () {
final __test = new IncrementalScannerTest();
runJUnitTest(__test, __test.test_replace_operator_oneForMany);
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 06954e6..91f0ba6 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -286,7 +286,7 @@
* @param secondError the second error being compared
* @return `true` if the two errors are equivalent
*/
- bool equals4(AnalysisError firstError, AnalysisError secondError) => identical(firstError.errorCode, secondError.errorCode) && firstError.offset == secondError.offset && firstError.length == secondError.length && equals5(firstError.source, secondError.source);
+ bool equals5(AnalysisError firstError, AnalysisError secondError) => identical(firstError.errorCode, secondError.errorCode) && firstError.offset == secondError.offset && firstError.length == secondError.length && equals6(firstError.source, secondError.source);
/**
* Return `true` if the two sources are equivalent.
@@ -295,7 +295,7 @@
* @param secondSource the second source being compared
* @return `true` if the two sources are equivalent
*/
- bool equals5(Source firstSource, Source secondSource) {
+ bool equals6(Source firstSource, Source secondSource) {
if (firstSource == null) {
return secondSource == null;
} else if (secondSource == null) {
@@ -379,7 +379,7 @@
*/
bool foundAndRemoved(List<AnalysisError> errors, AnalysisError targetError) {
for (AnalysisError error in errors) {
- if (equals4(error, targetError)) {
+ if (equals5(error, targetError)) {
errors.remove(error);
return true;
}
diff --git a/pkg/analyzer/test/services/formatter_test.dart b/pkg/analyzer/test/services/formatter_test.dart
index 72f010b..61e4356 100644
--- a/pkg/analyzer/test/services/formatter_test.dart
+++ b/pkg/analyzer/test/services/formatter_test.dart
@@ -536,6 +536,40 @@
);
});
+ test('CU - comments (8)', () {
+ expectCUFormatsTo(
+ 'var x /* X */, y;\n',
+ 'var x /* X */, y;\n'
+ );
+ });
+
+ test('CU - comments (9)', () {
+ expectCUFormatsTo(
+ 'main() {\n'
+ ' foo(1 /* bang */, 2);\n'
+ '}\n'
+ 'foo(x, y) => null;\n',
+ 'main() {\n'
+ ' foo(1 /* bang */, 2);\n'
+ '}\n'
+ 'foo(x, y) => null;\n'
+ );
+ });
+
+ test('CU - comments (10)', () {
+ expectCUFormatsTo(
+ 'var l = [1 /* bang */, 2];\n',
+ 'var l = [1 /* bang */, 2];\n'
+ );
+ });
+
+ test('CU - comments (11)', () {
+ expectCUFormatsTo(
+ 'var m = {1: 2 /* bang */, 3: 4};\n',
+ 'var m = {1: 2 /* bang */, 3: 4};\n'
+ );
+ });
+
test('CU - EOF nl', () {
expectCUFormatsTo(
'var x = 1;',
@@ -711,6 +745,20 @@
);
});
+ test('stmt (empty while body)', () {
+ expectStmtFormatsTo(
+ 'while (true);',
+ 'while (true);'
+ );
+ });
+
+ test('stmt (empty for body)', () {
+ expectStmtFormatsTo(
+ 'for ( ; ; );',
+ 'for ( ; ; );'
+ );
+ });
+
test('stmt (cascades)', () {
expectStmtFormatsTo(
'"foo"\n'
@@ -734,6 +782,16 @@
'var l = [1,2,3,4];',
'var l = [1, 2, 3, 4];'
);
+ expectStmtFormatsTo(
+ 'var l = [\n'
+ '1,\n'
+ '2,\n'
+ '];',
+ 'var l = [\n'
+ ' 1,\n'
+ ' 2,\n'
+ '];'
+ );
//Dangling ','
expectStmtFormatsTo(
'var l = [1,];',
@@ -747,6 +805,17 @@
'var map = const {"foo": "bar", "fuz": null};'
);
+ expectStmtFormatsTo(
+ 'var map = {\n'
+ '"foo": "bar",\n'
+ '"bar": "baz"'
+ '};',
+ 'var map = {\n'
+ ' "foo": "bar",\n'
+ ' "bar": "baz"'
+ '};'
+ );
+
//Dangling ','
expectStmtFormatsTo(
'var map = {"foo": "bar",};',
@@ -767,6 +836,18 @@
' print(e);\n'
'}'
);
+ expectStmtFormatsTo(
+ 'try{\n'
+ 'doSomething();\n'
+ '}on Exception catch (e){\n'
+ 'print(e);\n'
+ '}',
+ 'try {\n'
+ ' doSomething();\n'
+ '} on Exception catch (e) {\n'
+ ' print(e);\n'
+ '}'
+ );
});
test('stmt (binary/ternary ops)', () {
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index df98f1d..3454899 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -122,7 +122,7 @@
// Keep track of logged errors so we can know that the build failed.
onLog.listen((entry) {
if (entry.level == LogLevel.ERROR) {
- // TODO(nweiz): keep track of stack trace.
+ // TODO(nweiz): keep track of stack chain.
_accumulatedErrors.add(
new TransformerException(entry.transform, entry.message, null));
}
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index 2372ba9..a1af547 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -10,6 +10,7 @@
import 'asset_id.dart';
import 'errors.dart';
import 'transform_node.dart';
+import 'utils.dart';
/// Describes the current state of an asset as part of a transformation graph.
///
@@ -125,7 +126,7 @@
/// The return value of [callback] is piped to the returned Future.
Future _waitForState(bool test(AssetState state),
callback(AssetState state)) {
- if (test(state)) return new Future.sync(() => callback(state));
+ if (test(state)) return syncFuture(() => callback(state));
return onStateChange.firstWhere(test).then((_) => callback(state));
}
diff --git a/pkg/barback/lib/src/build_result.dart b/pkg/barback/lib/src/build_result.dart
index 52b341e..faeb256 100644
--- a/pkg/barback/lib/src/build_result.dart
+++ b/pkg/barback/lib/src/build_result.dart
@@ -4,10 +4,6 @@
library barback.build_result;
-import 'dart:async';
-
-import 'package:stack_trace/stack_trace.dart';
-
import 'errors.dart';
import 'utils.dart';
@@ -49,14 +45,14 @@
return "errors:\n" + errors.map((error) {
var stackTrace = null;
if (error is TransformerException || error is AssetLoadException) {
- stackTrace = new Trace.from(error.stackTrace);
+ stackTrace = error.stackTrace.terse;
}
var msg = new StringBuffer();
msg.write(prefixLines(error.toString()));
if (stackTrace != null) {
msg.write("\n\n");
- msg.write("Stack trace:\n");
+ msg.write("Stack chain:\n");
msg.write(prefixLines(stackTrace.toString()));
}
return msg.toString();
diff --git a/pkg/barback/lib/src/cancelable_future.dart b/pkg/barback/lib/src/cancelable_future.dart
index 4454f5c..84c19f1 100644
--- a/pkg/barback/lib/src/cancelable_future.dart
+++ b/pkg/barback/lib/src/cancelable_future.dart
@@ -32,8 +32,8 @@
Future then(onValue(T value), {Function onError}) =>
_completer.future.then(onValue, onError: onError);
Future<T> whenComplete(action()) => _completer.future.whenComplete(action);
- Future timeout(Duration timeLimit, [void onTimeout()]) =>
- _completer.future.timeout(timeLimit, onTimeout);
+ Future timeout(Duration timeLimit, {void onTimeout()}) =>
+ _completer.future.timeout(timeLimit, onTimeout: onTimeout);
/// Cancels this future.
void cancel() {
_canceled = true;
diff --git a/pkg/barback/lib/src/errors.dart b/pkg/barback/lib/src/errors.dart
index bb9af79..d62efeb 100644
--- a/pkg/barback/lib/src/errors.dart
+++ b/pkg/barback/lib/src/errors.dart
@@ -4,8 +4,6 @@
library barback.errors;
-import 'dart:async';
-
import 'package:stack_trace/stack_trace.dart';
import 'asset_id.dart';
@@ -115,9 +113,11 @@
abstract class _WrappedException implements BarbackException {
/// The wrapped exception.
final error;
- final StackTrace stackTrace;
+ final Chain stackTrace;
- _WrappedException(this.error, this.stackTrace);
+ _WrappedException(this.error, StackTrace stackTrace)
+ : this.stackTrace = stackTrace == null ? null :
+ new Chain.forTrace(stackTrace);
String get _message;
@@ -127,7 +127,7 @@
var stack = stackTrace;
if (stack == null && error is Error) stack = error.stackTrace;
if (stack != null) {
- result = "$result\n${new Trace.from(stack).terse}";
+ result = "$result\n${stackTrace.terse}";
}
return result;
diff --git a/pkg/barback/lib/src/file_pool.dart b/pkg/barback/lib/src/file_pool.dart
index 31d32ed..dab9409 100644
--- a/pkg/barback/lib/src/file_pool.dart
+++ b/pkg/barback/lib/src/file_pool.dart
@@ -8,6 +8,8 @@
import 'dart:convert';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
import 'pool.dart';
import 'utils.dart';
@@ -33,7 +35,7 @@
/// try again.
Stream<List<int>> openRead(String path) {
return futureStream(_pool.request().then((resource) {
- return new File(path).openRead().transform(
+ return Chain.track(new File(path).openRead()).transform(
new StreamTransformer.fromHandlers(handleDone: (sink) {
sink.close();
resource.release();
diff --git a/pkg/barback/lib/src/internal_asset.dart b/pkg/barback/lib/src/internal_asset.dart
index 6b3c9fb..75b4969 100644
--- a/pkg/barback/lib/src/internal_asset.dart
+++ b/pkg/barback/lib/src/internal_asset.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:io';
import 'dart:typed_data';
import 'asset.dart';
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
index 95ecbb1..2ecf6b4 100644
--- a/pkg/barback/lib/src/package_graph.dart
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -66,6 +66,9 @@
/// [Future] returned by [getAllAssets].
var _lastUnexpectedError;
+ /// The stack trace for [_lastUnexpectedError].
+ StackTrace _lastUnexpectedErrorTrace;
+
// TODO(nweiz): Allow transformers to declare themselves as "lightweight" or
// "heavyweight" and adjust their restrictions appropriately. Simple
// transformers may be very efficient to run in parallel, whereas dart2js uses
@@ -114,8 +117,9 @@
// errors, the result will automatically be considered a success.
_resultsController.add(
new BuildResult.aggregate(_cascadeResults.values));
- }, onError: (error, [stackTrace]) {
+ }, onError: (error, stackTrace) {
_lastUnexpectedError = error;
+ _lastUnexpectedErrorTrace = stackTrace;
_resultsController.addError(error, stackTrace);
});
}
@@ -152,7 +156,7 @@
if (_lastUnexpectedError != null) {
var error = _lastUnexpectedError;
_lastUnexpectedError = null;
- return new Future.error(error);
+ return new Future.error(error, _lastUnexpectedErrorTrace);
}
// If the build completed with an error, complete the future with it.
diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart
index ff8ad5c..13bc700 100644
--- a/pkg/barback/lib/src/phase_input.dart
+++ b/pkg/barback/lib/src/phase_input.dart
@@ -291,7 +291,7 @@
/// synchronously to ensure that [_adjustTransformers] isn't called before the
/// callback.
Future _waitForTransformers(callback()) {
- if (_adjustTransformersFuture == null) return new Future.sync(callback);
+ if (_adjustTransformersFuture == null) return syncFuture(callback);
return _adjustTransformersFuture.then(
(_) => _waitForTransformers(callback));
}
diff --git a/pkg/barback/lib/src/pool.dart b/pkg/barback/lib/src/pool.dart
index 7f89c12..24100ca 100644
--- a/pkg/barback/lib/src/pool.dart
+++ b/pkg/barback/lib/src/pool.dart
@@ -9,6 +9,9 @@
import 'package:stack_trace/stack_trace.dart';
+import 'utils.dart';
+
+// TODO(nweiz): put this somewhere that it can be shared between packages.
/// Manages an abstract pool of resources with a limit on how many may be in use
/// at once.
///
@@ -73,7 +76,7 @@
/// The return value of [callback] is piped to the returned Future.
Future withResource(callback()) {
return request().then((resource) =>
- new Future.sync(callback).whenComplete(resource.release));
+ syncFuture(callback).whenComplete(resource.release));
}
/// If there are any pending requests, this will fire the oldest one.
@@ -107,7 +110,7 @@
void _onTimeout() {
for (var completer in _requestedResources) {
completer.completeError("Pool deadlock: all resources have been "
- "allocated for too long.", new Trace.current().vmTrace);
+ "allocated for too long.", new Chain.current());
}
_requestedResources.clear();
_timer = null;
diff --git a/pkg/barback/lib/src/serialize.dart b/pkg/barback/lib/src/serialize.dart
index fa5adea..f0b356e 100644
--- a/pkg/barback/lib/src/serialize.dart
+++ b/pkg/barback/lib/src/serialize.dart
@@ -88,24 +88,17 @@
/// property.
final String message;
- /// The exception's stack trace, or `null` if no stack trace was available.
- final Trace stackTrace;
+ /// The exception's stack chain, or `null` if no stack chain was available.
+ final Chain stackTrace;
/// Loads a [CrossIsolateException] from a serialized representation.
///
/// [error] should be the result of [CrossIsolateException.serialize].
- factory CrossIsolateException.deserialize(Map error) {
- var type = error['type'];
- var message = error['message'];
- var stackTrace = error['stack'] == null ? null :
- new Trace.parse(error['stack']);
- return new CrossIsolateException._(type, message, stackTrace);
- }
-
- /// Loads a [CrossIsolateException] from a serialized representation.
- ///
- /// [error] should be the result of [CrossIsolateException.serialize].
- CrossIsolateException._(this.type, this.message, this.stackTrace);
+ CrossIsolateException.deserialize(Map error)
+ : type = error['type'],
+ message = error['message'],
+ stackTrace = error['stack'] == null ? null :
+ new Chain.parse(error['stack']);
/// Serializes [error] to an object that can safely be passed across isolate
/// boundaries.
@@ -114,7 +107,7 @@
return {
'type': error.runtimeType.toString(),
'message': _getErrorMessage(error),
- 'stack': stack == null ? null : stack.toString()
+ 'stack': stack == null ? null : new Chain.forTrace(stack).toString()
};
}
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index 71576ff..a4a5950 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -7,6 +7,8 @@
import 'dart:async';
import 'dart:typed_data';
+import 'package:stack_trace/stack_trace.dart';
+
/// A pair of values.
class Pair<E, F> {
E first;
@@ -151,12 +153,12 @@
for (var stream in streams) {
stream.listen(
- controller.add,
- onError: controller.addError,
- onDone: () {
- doneCount++;
- if (doneCount == streams.length) controller.close();
- });
+ controller.add,
+ onError: controller.addError,
+ onDone: () {
+ doneCount++;
+ if (doneCount == streams.length) controller.close();
+ });
}
return controller.stream;
@@ -193,6 +195,9 @@
// TODO(jmesserly): doc comment changed to due 14601.
Future newFuture(callback()) => new Future.value().then((_) => callback());
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
/// Returns a buffered stream that will emit the same values as the stream
/// returned by [future] once [future] completes.
///
diff --git a/pkg/barback/pubspec.yaml b/pkg/barback/pubspec.yaml
index 54e3a1a..3032f3d 100644
--- a/pkg/barback/pubspec.yaml
+++ b/pkg/barback/pubspec.yaml
@@ -1,5 +1,15 @@
name: barback
-version: 0.9.0 # Replaced by publish_barback.py. Do not edit.
+
+# Note! This version is referenced directly in the pub source code in
+# lib/src/barback.dart. Pub implicitly places a version constraint on barback
+# to ensure users only select a version of barback that works with their current
+# version of pub.
+#
+# When the minor version of this is upgraded, you *must* update that version
+# number in pub to stay in sync with this. New patch versions are considered
+# backwards compatible, and pub will allow later patch versions automatically.
+version: 0.10.2+1
+
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
description: >
@@ -19,14 +29,5 @@
dev_dependencies:
scheduled_test: ">=0.9.0 <0.10.0"
unittest: ">=0.9.0 <0.10.0"
-
environment:
- # Barback is tightly coupled to the SDK because pub contains code that is run
- # against the user's version of barback. We need to ensure that that version
- # of barback is compatible with the user's version of pub.
- #
- # Since the SDK itself can't place constraints on barback, we do a reverse
- # constraint and have barback itself only allow specific SDK versions.
- # This ensures that for each SDK version, there is a single known good version
- # of barback that will be used with it.
- sdk: "$SDK_CONSTRAINT$"
+ sdk: ">=1.0.1 <2.0.0"
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index d21d235..fb0094f 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -324,8 +324,10 @@
}
});
// After everything is created, do a pass through all classes to make sure no
- // intermediate classes created by mixins are included.
- entityMap.values.where((e) => e is Class).forEach((c) => c.makeValid());
+ // intermediate classes created by mixins are included, all the links to
+ // exported members point to the new library.
+ entityMap.values.where((e) => e is Class).forEach(
+ (c) => c.updateLinksAndRemoveIntermediaryClasses());
// Everything is a subclass of Object, therefore empty the list to avoid a
// giant list of subclasses to be printed out.
if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear();
@@ -342,7 +344,8 @@
throw new StateError('No library_list.json');
}
libraryMap =
- JSON.decode(new File('$_outputDirectory/library_list.json').readAsStringSync());
+ JSON.decode(new File(
+ '$_outputDirectory/library_list.json').readAsStringSync());
libraryMap['libraries'].addAll(filteredEntities
.where((e) => e is Library)
.map((e) => e.previewMap));
@@ -618,7 +621,8 @@
if (elementName != null) {
return new markdown.Element.text('a', elementName);
}
- return _fixComplexReference(name, currentLibrary, currentClass, currentMember);
+ return _fixComplexReference(name, currentLibrary, currentClass,
+ currentMember);
}
markdown.Node fixReferenceWithScope(String name, DeclarationMirror scope) {
@@ -643,11 +647,17 @@
if (!dir.existsSync()) {
dir.createSync();
}
- // We assume there's a single extra level of directory structure for packages.
if (path.split(filename).length > 1) {
- var subdir = new Directory(path.join(_outputDirectory, path.dirname(filename)));
- if (!subdir.existsSync()) {
- subdir.createSync();
+ var splitList = path.split(filename);
+ for (int i = 0; i < splitList.length; i++) {
+ var level = splitList[i];
+ }
+ for (var level in path.split(filename)) {
+ var subdir = new Directory(path.join(_outputDirectory,
+ path.dirname(filename)));
+ if (!subdir.existsSync()) {
+ subdir.createSync();
+ }
}
}
File file = new File(path.join(_outputDirectory, filename));
@@ -753,14 +763,23 @@
}
/// Returns a map of [Variable] objects constructed from [mirrorMap].
+ /// The optional parameter [containingLibrary] is contains data for variables
+ /// defined at the top level of a library (potentially for exporting
+ /// purposes).
Map<String, Variable> _createVariables(Map<String,
- VariableMirror> mirrorMap) {
+ VariableMirror> mirrorMap, [Library containingLibrary]) {
var data = {};
// TODO(janicejl): When map to map feature is created, replace the below
// with a filter. Issue(#9590).
mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
if (_includePrivate || !_isHidden(mirror)) {
- entityMap[docName(mirror)] = new Variable(mirrorName, mirror);
+ if (containingLibrary != null && mirror.owner.qualifiedName !=
+ containingLibrary.mirror.qualifiedName) {
+ entityMap[docName(mirror)] = new ExportedVariable(mirrorName, mirror,
+ containingLibrary);
+ } else {
+ entityMap[docName(mirror)] = new Variable(mirrorName, mirror);
+ }
data[mirrorName] = entityMap[docName(mirror)];
}
});
@@ -768,11 +787,15 @@
}
/// Returns a map of [Method] objects constructed from [mirrorMap].
- MethodGroup _createMethods(Map<String, MethodMirror> mirrorMap) {
+ /// The optional parameter [containingLibrary] is contains data for variables
+ /// defined at the top level of a library (potentially for exporting
+ /// purposes).
+ MethodGroup _createMethods(Map<String, MethodMirror> mirrorMap,
+ [Library containingLibrary]) {
var group = new MethodGroup();
mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
if (_includePrivate || !mirror.isPrivate) {
- group.addMethod(mirror);
+ group.addMethod(mirror, containingLibrary);
}
});
return group;
@@ -857,14 +880,25 @@
bool hasBeenCheckedForPackage = false;
String packageIntro;
+ Map<String, Exported> _exportedMembers;
+
Library(LibraryMirror libraryMirror) : super(libraryMirror) {
var exported = _calcExportedItems(libraryMirror);
- this.classes = _createClasses(
- exported['classes']..addAll(libraryMirror.classes));
+ _createClasses(exported['classes']..addAll(libraryMirror.classes));
this.functions = _createMethods(
- exported['methods']..addAll(libraryMirror.functions));
+ exported['methods']..addAll(libraryMirror.functions), this);
this.variables = _createVariables(
- exported['variables']..addAll(libraryMirror.variables));
+ exported['variables']..addAll(libraryMirror.variables), this);
+
+ var exportedVariables = {};
+ variables.forEach((key, value) {
+ if (value is ExportedVariable) {
+ exportedVariables[key] = value;
+ }
+ });
+ _exportedMembers = new Map.from(this.classes.exported)
+ ..addAll(this.functions.exported)
+ ..addAll(exportedVariables);
}
String get packagePrefix => packageName == null || packageName.isEmpty ?
@@ -883,13 +917,12 @@
String get name => docName(mirror);
- /// Returns a [ClassGroup] containing error, typedef and regular classes.
- ClassGroup _createClasses(Map<String, ClassMirror> mirrorMap) {
- var group = new ClassGroup();
+ /// Set our classes field with error, typedef and regular classes.
+ void _createClasses(Map<String, ClassMirror> mirrorMap) {
+ this.classes = new ClassGroup();
mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
- group.addClass(mirror);
+ this.classes.addClass(mirror, this);
});
- return group;
}
/// For the given library determine what items (if any) are exported.
@@ -1087,16 +1120,26 @@
///
/// If it does not exist in the owner library, it is a mixin applciation and
/// should be removed.
- void makeValid() {
+ void updateLinksAndRemoveIntermediaryClasses() {
var library = entityMap[owner];
- if (library != null && !library.classes.containsKey(name)) {
- this.isPrivate = true;
- // Since we are now making the mixin a private class, make all elements
- // with the mixin as an owner private too.
- entityMap.values.where((e) => e.owner == qualifiedName)
- .forEach((element) => element.isPrivate = true);
- // Move the subclass up to the next public superclass
- subclasses.forEach((subclass) => addSubclass(subclass));
+ if (library != null) {
+ if (!library.classes.containsKey(name) && mirror.isNameSynthetic) {
+ // In the mixin case, remove the intermediary classes.
+ this.isPrivate = true;
+ // Since we are now making the mixin a private class, make all elements
+ // with the mixin as an owner private too.
+ entityMap.values.where((e) => e.owner == qualifiedName).forEach(
+ (element) => element.isPrivate = true);
+ // Move the subclass up to the next public superclass
+ subclasses.forEach((subclass) => addSubclass(subclass));
+ } else {
+ // It is an exported item. Loop through each of the exported types,
+ // and tell them to update their links, given these other exported
+ // names within the library.
+ for (Exported member in library._exportedMembers.values) {
+ member.updateExports(library._exportedMembers.keys);
+ }
+ }
}
}
@@ -1110,8 +1153,8 @@
});
}
- /// If a class extends a private superclass, find the closest public superclass
- /// of the private superclass.
+ /// If a class extends a private superclass, find the closest public
+ /// superclass of the private superclass.
String validSuperclass() {
if (superclass == null) return 'dart.core.Object';
if (_isVisible(superclass)) return superclass.qualifiedName;
@@ -1140,6 +1183,52 @@
int compareTo(aClass) => name.compareTo(aClass.name);
}
+abstract class Exported {
+ void updateExports(Map<String, Indexable> libraryExports);
+}
+
+Map _filterMap(exported, map, test) {
+ map.forEach((key, value) {
+ if (test(value)) exported[key] = value;
+ });
+ return exported;
+}
+
+class ExportedClass extends Class implements Exported {
+ Class _originalClass;
+ Library _exportingLibrary;
+
+ ExportedClass(ClassMirror originalClass, Library this._exportingLibrary) :
+ super._(originalClass) {
+ _originalClass = new Class(originalClass);
+ }
+
+ // The qualified name (for URL purposes) and the file name are the same,
+ // of the form packageName/ClassName or packageName/ClassName.methodName.
+ // This defines both the URL and the directory structure.
+ String get fileName => path.join(_exportingLibrary.packageName,
+ _exportingLibrary.mirror.qualifiedName + '.' + _originalClass.name);
+
+ void updateExports(Map<String, Indexable> libraryExports) {
+ // TODO(efortuna): If this class points to another exported class or type
+ // of some sort, then that reference needs to be updated here.
+ /* these need to be updated:
+ 'comment': comment,
+ 'superclass': validSuperclass(),
+ 'implements': interfaces.where(_isVisible)
+ .map((e) => e.qualifiedName).toList(),
+ 'subclass': (subclasses.toList()..sort())
+ .map((x) => x.qualifiedName).toList(),
+ 'variables': recurseMap(variables),
+ 'inheritedVariables': recurseMap(inheritedVariables),
+ 'methods': methods.toMap(),
+ 'inheritedMethods': inheritedMethods.toMap(),
+ 'annotations': annotations.map((a) => a.toMap()).toList(),
+ 'generics': recurseMap(generics)
+ */
+ }
+}
+
/// A container to categorize classes into the following groups: abstract
/// classes, regular classes, typedefs, and errors.
class ClassGroup {
@@ -1147,7 +1236,17 @@
Map<String, Typedef> typedefs = {};
Map<String, Class> errors = {};
- void addClass(ClassMirror classMirror) {
+ Map<String, Exported> get exported {
+ var exported = _filterMap({}, classes, (value) => value is ExportedClass);
+ // TODO(efortuna): The line below needs updating.
+ exported = _filterMap(exported, typedefs,
+ (value) => value is ExportedClass);
+ exported = _filterMap(exported, errors,
+ (value) => value is ExportedClass);
+ return exported;
+ }
+
+ void addClass(ClassMirror classMirror, Library containingLibrary) {
if (classMirror.isTypedef) {
// This is actually a Dart2jsTypedefMirror, and it does define value,
// but we don't have visibility to that type.
@@ -1159,6 +1258,13 @@
} else {
var clazz = new Class(classMirror);
+ if (classMirror.library.qualifiedName !=
+ containingLibrary.mirror.qualifiedName) {
+ var exportedClass = new ExportedClass(classMirror, containingLibrary);
+ entityMap[clazz.fileName] = exportedClass;
+ clazz = exportedClass;
+ }
+
if (clazz.isError()) {
errors[classMirror.simpleName] = clazz;
} else if (classMirror.isClass) {
@@ -1261,6 +1367,26 @@
}
}
+class ExportedVariable extends Variable implements Exported {
+ Library _exportingLibrary;
+
+ ExportedVariable(String variableName, VariableMirror originalVariable,
+ Library this._exportingLibrary) : super(variableName, originalVariable);
+
+ String get fileName => path.join(_exportingLibrary.packageName,
+ _exportingLibrary.mirror.qualifiedName + '.' + super.name);
+
+ void updateExports(Map<String, Indexable> libraryExports) {
+ // TODO(efortuna): if this class points to another exported class or type
+ // of some sort, then that reference needs to be updated here.
+ /* these need to be updated:
+ 'comment': comment,
+ 'type': new List.filled(1, type.toMap()),
+ 'annotations': annotations.map((a) => a.toMap()).toList()
+ */
+ }
+}
+
/// A class containing properties of a Dart method.
class Method extends Indexable {
@@ -1331,6 +1457,33 @@
}
}
+class ExportedMethod extends Method implements Exported {
+ Library _exportingLibrary;
+
+ ExportedMethod(MethodMirror originalMethod, Library this._exportingLibrary) :
+ super(originalMethod);
+
+ // TODO(efortuna): Refactor this code so the exported items can share this
+ // behavior.
+ String get fileName => path.join(_exportingLibrary.packageName,
+ _exportingLibrary.mirror.qualifiedName + '.' + super.name);
+
+ void updateExports(Map<String, Indexable> libraryExports) {
+ // TODO(efortuna): if this class points to another exported class or type
+ // of some sort, then that reference needs to be updated here.
+ /* these need to be updated:
+ 'qualifiedName': qualifiedName,
+ 'comment': comment,
+ 'commentFrom': commentInheritedFrom,
+ 'return': new List.filled(1, returnType.toMap()),
+ 'parameters': recurseMap(parameters),
+ 'annotations': annotations.map((a) => a.toMap()).toList()
+ */
+ }
+}
+
+
+
/// A container to categorize methods into the following groups: setters,
/// getters, constructors, operators, regular methods.
class MethodGroup {
@@ -1340,8 +1493,27 @@
Map<String, Method> operators = {};
Map<String, Method> regularMethods = {};
- void addMethod(MethodMirror mirror) {
- var method = new Method(mirror);
+ Map<String, Exported> get exported {
+ var exported = {};
+ for (Map<String, Method> group in [setters, getters, constructors,
+ operators, regularMethods]) {
+ exported = _filterMap(exported, group,
+ (value) => value is ExportedMethod);
+ }
+ return exported;
+ }
+
+ /// The optional parameter [containingLibrary] is contains data for variables
+ /// defined at the top level of a library (potentially for exporting
+ /// purposes).
+ void addMethod(MethodMirror mirror, [Library containingLibrary]) {
+ var method;
+ if (containingLibrary != null && mirror.owner.qualifiedName !=
+ containingLibrary.mirror.qualifiedName) {
+ method = new ExportedMethod(mirror, containingLibrary);
+ } else {
+ method = new Method(mirror);
+ }
entityMap[docName(mirror)] = method;
if (mirror.isSetter) {
setters[mirror.simpleName] = method;
@@ -1498,9 +1670,13 @@
}
var owner = m.owner;
if (owner == null) return m.qualifiedName;
- // For the unnamed constructor we just return the class name.
- if (m.simpleName == '') return docName(owner);
- return docName(owner) + '.' + m.simpleName;
+ var simpleName = m.simpleName;
+ if (m is MethodMirror && m.isConstructor) {
+ // We name constructors specially -- including the class name again and a
+ // "-" to separate the constructor from its name (if any).
+ simpleName = '${owner.simpleName}-$simpleName';
+ }
+ return docName(owner) + '.' + simpleName;
}
/// Remove statics from the map of inherited items before adding them.
diff --git a/pkg/http/README.md b/pkg/http/README.md
new file mode 100644
index 0000000..93d4266
--- /dev/null
+++ b/pkg/http/README.md
@@ -0,0 +1,21 @@
+# http
+
+A composable, Future-based library for making HTTP requests.
+
+This package contains a set of high-level functions and classes that make it
+easy to consume HTTP resources.
+
+**NOTE:** This package currently only works for
+server-side or command-line Dart applications. In other words, if the app
+imports `dart:io`, it can use this package.
+
+## Using
+
+Please see the [API docs][docs] for explanations and examples.
+
+## Filing issues
+
+Please file issues for the http package at [http://dartbug.com/new][bugs].
+
+[bugs]: http://dartbug.com/new
+[docs]: https://api.dartlang.org/docs/channels/dev/latest/http.html
\ No newline at end of file
diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart
index 86925c3..87a4224 100644
--- a/pkg/http/lib/src/base_client.dart
+++ b/pkg/http/lib/src/base_client.dart
@@ -128,7 +128,7 @@
/// Sends a non-streaming [Request] and returns a non-streaming [Response].
Future<Response> _sendUnstreamed(String method, url,
Map<String, String> headers, [body, Encoding encoding]) {
- return new Future.sync(() {
+ return syncFuture(() {
if (url is String) url = Uri.parse(url);
var request = new Request(method, url);
diff --git a/pkg/http/lib/src/io_client.dart b/pkg/http/lib/src/io_client.dart
index 6695fb8..b4fa893 100644
--- a/pkg/http/lib/src/io_client.dart
+++ b/pkg/http/lib/src/io_client.dart
@@ -7,6 +7,8 @@
import 'dart:async';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
import 'base_client.dart';
import 'base_request.dart';
import 'streamed_response.dart';
@@ -23,7 +25,8 @@
Future<StreamedResponse> send(BaseRequest request) {
var stream = request.finalize();
- return _inner.openUrl(request.method, request.url).then((ioRequest) {
+ return Chain.track(_inner.openUrl(request.method, request.url))
+ .then((ioRequest) {
ioRequest.followRedirects = request.followRedirects;
ioRequest.maxRedirects = request.maxRedirects;
ioRequest.contentLength = request.contentLength;
@@ -31,7 +34,7 @@
request.headers.forEach((name, value) {
ioRequest.headers.set(name, value);
});
- return stream.pipe(ioRequest);
+ return Chain.track(stream.pipe(ioRequest));
}).then((response) {
var headers = {};
response.headers.forEach((key, values) {
diff --git a/pkg/http/lib/src/multipart_file.dart b/pkg/http/lib/src/multipart_file.dart
index 19c03bf..d316e2a 100644
--- a/pkg/http/lib/src/multipart_file.dart
+++ b/pkg/http/lib/src/multipart_file.dart
@@ -9,6 +9,7 @@
import 'dart:io';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import 'byte_stream.dart';
import 'utils.dart';
@@ -93,8 +94,8 @@
{String filename, ContentType contentType}) {
if (filename == null) filename = path.basename(filePath);
var file = new File(filePath);
- return file.length().then((length) {
- var stream = new ByteStream(file.openRead());
+ return Chain.track(file.length()).then((length) {
+ var stream = new ByteStream(Chain.track(file.openRead()));
return new MultipartFile(field, stream, length,
filename: filename,
contentType: contentType);
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index 8383959..d3a4307 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -9,6 +9,8 @@
import 'dart:io';
import 'dart:typed_data';
+import 'package:stack_trace/stack_trace.dart';
+
import 'byte_stream.dart';
/// Converts a URL query string (or `application/x-www-form-urlencoded` body)
@@ -36,32 +38,11 @@
String mapToQuery(Map<String, String> map, {Encoding encoding}) {
var pairs = <List<String>>[];
map.forEach((key, value) =>
- pairs.add([urlEncode(key, encoding: encoding),
- urlEncode(value, encoding: encoding)]));
+ pairs.add([Uri.encodeQueryComponent(key, encoding: encoding),
+ Uri.encodeQueryComponent(value, encoding: encoding)]));
return pairs.map((pair) => "${pair[0]}=${pair[1]}").join("&");
}
-// TODO(nweiz): get rid of this when issue 12780 is fixed.
-/// URL-encodes [source] using [encoding].
-String urlEncode(String source, {Encoding encoding}) {
- if (encoding == null) encoding = UTF8;
- return encoding.encode(source).map((byte) {
- // Convert spaces to +, like encodeQueryComponent.
- if (byte == 0x20) return '+';
- // Pass through digits.
- if ((byte >= 0x30 && byte < 0x3A) ||
- // Pass through uppercase letters.
- (byte >= 0x41 && byte < 0x5B) ||
- // Pass through lowercase letters.
- (byte >= 0x61 && byte < 0x7B) ||
- // Pass through `-._~`.
- (byte == 0x2D || byte == 0x2E || byte == 0x5F || byte == 0x7E)) {
- return new String.fromCharCode(byte);
- }
- return '%' + byte.toRadixString(16).toUpperCase();
- }).join();
-}
-
/// Like [String.split], but only splits on the first occurrence of the pattern.
/// This will always return an array of two elements or fewer.
///
@@ -234,3 +215,6 @@
}
return nextElement(null);
}
+
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
diff --git a/pkg/http/pubspec.yaml b/pkg/http/pubspec.yaml
index 2e2aafa..80018b1 100644
--- a/pkg/http/pubspec.yaml
+++ b/pkg/http/pubspec.yaml
@@ -1,10 +1,11 @@
name: http
version: 0.9.0
author: "Dart Team <misc@dartlang.org>"
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/http
description: A composable, Future-based API for making HTTP requests.
dependencies:
path: ">=0.9.0 <0.10.0"
+ stack_trace: ">=0.9.0 <0.10.0"
dev_dependencies:
unittest: ">=0.9.0 <0.10.0"
environment:
diff --git a/pkg/observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
index 10378fa..dcb8853 100644
--- a/pkg/observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -315,7 +315,9 @@
var _foo = 42;
List log = [];
- noSuchMethod(Invocation invocation) {
+ // TODO(ahe): Remove @reflectable from here (once either of
+ // http://dartbug.com/15408 or http://dartbug.com/15409 are fixed).
+ @reflectable noSuchMethod(Invocation invocation) {
final name = invocation.memberName;
log.add(name);
if (name == #foo && invocation.isGetter) return _foo;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d9c7d08..e6b3e7b 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -167,6 +167,7 @@
# printed. Minified versions of these tests exist that test the behavior when
# minified.
unittest/test/*_unminified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
+unittest/test/mirror_matchers_test: Fail # Issue 15405
[ $compiler == dart2js && $browser ]
stack_trace/test/vm_test: Fail, OK # VM-specific traces
@@ -347,9 +348,3 @@
[ $runtime == vm && ($system == windows || $system == linux) ]
watcher/test/*/mac_os_test: Skip
-
-[ $runtime == vm && $system == linux ]
-watcher/test/*/linux_test: Pass, Slow # Issue 14606
-
-[ $runtime == vm && $system == macos ]
-watcher/test/directory_watcher/mac_os_test: Pass, Fail # Issue 15024
diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart
index f3ad9ea..b9b81bf 100644
--- a/pkg/polymer/lib/src/instance.dart
+++ b/pkg/polymer/lib/src/instance.dart
@@ -24,6 +24,9 @@
/**
* The mixin class for Polymer elements. It provides convenience features on top
* of the custom elements web standard.
+ *
+ * If this class is used as a mixin,
+ * you must call `polymerCreated()` from the body of your constructor.
*/
abstract class Polymer implements Element, Observable, NodeBindExtension {
// Fully ported from revision:
@@ -124,6 +127,12 @@
// TODO(jmesserly): Polymer does not have this feature. Reconcile.
ShadowRoot getShadowRoot(String customTagName) => _shadowRoots[customTagName];
+ /**
+ * If this class is used as a mixin, this method must be called from inside
+ * of the `created()` constructor.
+ *
+ * If this class is a superclass, calling `super.created()` is sufficient.
+ */
void polymerCreated() {
if (this.ownerDocument.window != null || alwaysPrepare ||
_preparingElements > 0) {
diff --git a/pkg/polymer/lib/src/reflected_type.dart b/pkg/polymer/lib/src/reflected_type.dart
index ad11ffb..6486abc 100644
--- a/pkg/polymer/lib/src/reflected_type.dart
+++ b/pkg/polymer/lib/src/reflected_type.dart
@@ -25,7 +25,7 @@
final Symbol _mangledNameField = () {
var jsClassMirrorMirror = reflect(reflectClass(ClassMirror)).type;
- for (var name in jsClassMirrorMirror.variables.keys) {
+ for (var name in jsClassMirrorMirror.declarations.keys) {
if (MirrorSystem.getName(name) == '_mangledName') return name;
}
}();
diff --git a/pkg/scheduled_test/lib/scheduled_process.dart b/pkg/scheduled_test/lib/scheduled_process.dart
index 8f91459a..1d46d46 100644
--- a/pkg/scheduled_test/lib/scheduled_process.dart
+++ b/pkg/scheduled_test/lib/scheduled_process.dart
@@ -8,6 +8,8 @@
import 'dart:convert';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
import 'scheduled_test.dart';
import 'src/utils.dart';
import 'src/value_future.dart';
@@ -97,12 +99,12 @@
_scheduleExceptionCleanup();
var stdoutWithCanceller = _lineStreamWithCanceller(
- _process.then((p) => p.stdout));
+ _process.then((p) => Chain.track(p.stdout)));
_stdoutCanceller = stdoutWithCanceller.last;
_stdoutLog = stdoutWithCanceller.first;
var stderrWithCanceller = _lineStreamWithCanceller(
- _process.then((p) => p.stderr));
+ _process.then((p) => Chain.track(p.stderr)));
_stderrCanceller = stderrWithCanceller.last;
_stderrLog = stderrWithCanceller.first;
@@ -150,10 +152,11 @@
workingDirectory = results[2];
environment = results[3];
_updateDescription(executable, arguments);
- return Process.start(executable,
- arguments,
- workingDirectory: workingDirectory,
- environment: environment).then((process) {
+ return Chain.track(
+ Process.start(executable,
+ arguments,
+ workingDirectory: workingDirectory,
+ environment: environment)).then((process) {
process.stdin.encoding = UTF8;
return process;
});
@@ -169,7 +172,7 @@
// process is running, we want the schedule to move to the onException
// queue where the process will be killed, rather than blocking the tasks
// queue waiting for the process to exit.
- _process.then((p) => p.exitCode).then((exitCode) {
+ _process.then((p) => Chain.track(p.exitCode)).then((exitCode) {
if (_endExpected) {
exitCodeCompleter.complete(exitCode);
return;
diff --git a/pkg/scheduled_test/lib/scheduled_server.dart b/pkg/scheduled_test/lib/scheduled_server.dart
index 3f2addd..202fdb8 100644
--- a/pkg/scheduled_test/lib/scheduled_server.dart
+++ b/pkg/scheduled_test/lib/scheduled_server.dart
@@ -8,9 +8,12 @@
import 'dart:collection';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
import 'scheduled_test.dart';
import 'src/scheduled_server/handler.dart';
import 'src/scheduled_server/safe_http_server.dart';
+import 'src/utils.dart';
typedef Future ScheduledHandler(HttpRequest request);
@@ -46,8 +49,8 @@
var scheduledServer;
scheduledServer = new ScheduledServer._(schedule(() {
- return SafeHttpServer.bind("127.0.0.1", 0).then((server) {
- server.listen(scheduledServer._handleRequest,
+ return Chain.track(SafeHttpServer.bind("127.0.0.1", 0)).then((server) {
+ Chain.track(server).listen(scheduledServer._handleRequest,
onError: currentSchedule.signalError);
currentSchedule.onComplete.schedule(server.close);
return server;
@@ -89,7 +92,7 @@
/// responsibility to check that the method/path are correct and that it's
/// being run at the correct time.
void _handleRequest(HttpRequest request) {
- wrapFuture(new Future.sync(() {
+ wrapFuture(syncFuture(() {
if (_handlers.isEmpty) {
fail("'$description' received ${request.method} ${request.uri.path} "
"when no more requests were expected.");
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index 1be401c..807424f2 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -191,6 +191,7 @@
import 'dart:async';
+import 'package:stack_trace/stack_trace.dart';
import 'package:unittest/unittest.dart' as unittest;
import 'src/schedule.dart';
@@ -230,22 +231,26 @@
_ensureInitialized();
_ensureSetUpForTopLevel();
testFn(description, () {
- var asyncDone = unittest.expectAsync0(() {});
- return currentSchedule.run(() {
- if (_setUpFn != null) _setUpFn();
- body();
- }).then((_) {
- // If we got here, the test completed successfully so tell unittest so.
- asyncDone();
- }).catchError((e) {
+ var completer = new Completer();
+
+ Chain.capture(() {
+ _currentSchedule = new Schedule();
+ return currentSchedule.run(() {
+ if (_setUpFn != null) _setUpFn();
+ body();
+ }).then(completer.complete);
+ }, onError: (e, chain) {
if (e is ScheduleError) {
assert(e.schedule.errors.contains(e));
assert(e.schedule == currentSchedule);
unittest.registerException(e.schedule.errorString());
} else {
- unittest.registerException(e);
+ unittest.registerException(e, chain);
}
+ completer.complete();
});
+
+ return completer.future;
});
}
@@ -317,7 +322,6 @@
throw new StateError('There seems to be another scheduled test '
'still running.');
}
- _currentSchedule = new Schedule();
if (_setUpFn != null) {
var parentFn = _setUpFn;
_setUpFn = () { parentFn(); setUpFn(); };
@@ -332,9 +336,7 @@
});
} else {
unittest.setUp(() {
- if (currentSchedule == null) {
- throw new StateError('No schedule allocated.');
- } else if (_setUpFn != null) {
+ if (_setUpFn != null) {
var parentFn = _setUpFn;
_setUpFn = () { parentFn(); setUpFn(); };
} else {
diff --git a/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
index 1b377ae..6d8705b 100644
--- a/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
@@ -8,6 +8,7 @@
import 'dart:io';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import '../../descriptor.dart';
import '../../scheduled_test.dart';
@@ -26,7 +27,8 @@
Future create([String parent]) => schedule(() {
if (parent == null) parent = defaultRoot;
var fullPath = path.join(parent, name);
- return new Directory(fullPath).create(recursive: true).then((_) {
+ return Chain.track(new Directory(fullPath).create(recursive: true))
+ .then((_) {
return Future.wait(
contents.map((entry) => entry.create(fullPath)).toList());
});
@@ -43,7 +45,7 @@
}
return Future.wait(contents.map((entry) {
- return new Future.sync(() => entry.validateNow(fullPath))
+ return syncFuture(() => entry.validateNow(fullPath))
.then((_) => null)
.catchError((e) => e);
})).then((results) {
@@ -54,7 +56,7 @@
}
Stream<List<int>> load(String pathToLoad) {
- return futureStream(new Future.value().then((_) {
+ return futureStream(syncFuture(() {
if (path.posix.isAbsolute(pathToLoad)) {
throw new ArgumentError("Can't load absolute path '$pathToLoad'.");
}
diff --git a/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
index 9111b3d..515f6e4 100644
--- a/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
@@ -10,6 +10,7 @@
import 'dart:math' as math;
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import '../../descriptor.dart';
import '../../scheduled_test.dart';
@@ -49,7 +50,8 @@
Future create([String parent]) => schedule(() {
if (parent == null) parent = defaultRoot;
- return new File(path.join(parent, name)).writeAsBytes(contents);
+ return Chain.track(new File(path.join(parent, name))
+ .writeAsBytes(contents));
}, "creating file '$name'");
Future validate([String parent]) =>
@@ -62,7 +64,7 @@
fail("File not found: '$fullPath'.");
}
- return new File(fullPath).readAsBytes().then(_validateNow);
+ return Chain.track(new File(fullPath).readAsBytes()).then(_validateNow);
}
// TODO(nweiz): rather than setting up an inheritance chain, just store a
diff --git a/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
index 590a1ce..8303117 100644
--- a/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
@@ -11,6 +11,7 @@
import '../../descriptor.dart';
import '../../scheduled_test.dart';
+import '../utils.dart';
/// A descriptor that validates that no file exists with the given name.
/// Creating this descriptor is a no-op and loading from it is invalid.
@@ -23,7 +24,7 @@
Future validate([String parent]) => schedule(() => validateNow(parent),
"validating '$name' doesn't exist");
- Future validateNow([String parent]) => new Future.sync(() {
+ Future validateNow([String parent]) => syncFuture(() {
if (parent == null) parent = defaultRoot;
var fullPath = path.join(parent, name);
if (new File(fullPath).existsSync()) {
diff --git a/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
index 130cfdd..4ce8602 100644
--- a/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
@@ -8,6 +8,7 @@
import 'dart:io';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import '../../descriptor.dart';
import '../../scheduled_test.dart';
@@ -112,5 +113,6 @@
}
Future create([String parent]) => new Future.error(
- new UnsupportedError("Pattern descriptors don't support create()."));
+ new UnsupportedError("Pattern descriptors don't support create()."),
+ new Chain.current());
}
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index 7cc30fb..5bf5947 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -426,7 +426,7 @@
}
var task = new Task(() {
- return new Future.sync(fn).catchError((e, stackTrace) {
+ return syncFuture(fn).catchError((e, stackTrace) {
throw new ScheduleError.from(_schedule, e, stackTrace: stackTrace);
});
}, description, this);
@@ -495,15 +495,15 @@
_schedule.currentQueue != this || pendingCallbacks.isEmpty;
_totalCallbacks++;
- var trace = new Trace.current();
+ var chain = new Chain.current();
var pendingCallback = new PendingCallback._(() {
var fullDescription = description;
if (fullDescription == null) {
fullDescription = "Out-of-band operation #${_totalCallbacks}";
}
- var stackString = prefixLines(terseTraceString(trace));
- fullDescription += "\n\nStack trace:\n$stackString";
+ var stackString = prefixLines(terseTraceString(chain));
+ fullDescription += "\n\nStack chain:\n$stackString";
return fullDescription;
});
_pendingCallbacks.add(pendingCallback);
diff --git a/pkg/scheduled_test/lib/src/schedule_error.dart b/pkg/scheduled_test/lib/src/schedule_error.dart
index 264a0aa..5b273fd 100644
--- a/pkg/scheduled_test/lib/src/schedule_error.dart
+++ b/pkg/scheduled_test/lib/src/schedule_error.dart
@@ -4,8 +4,6 @@
library schedule_error;
-import 'dart:async';
-
import 'package:stack_trace/stack_trace.dart';
import 'schedule.dart';
@@ -18,7 +16,7 @@
final error;
/// The stack trace that was attached to the error. Can be `null`.
- final stackTrace;
+ final StackTrace stackTrace;
/// The schedule during which this error occurred.
final Schedule schedule;
@@ -53,16 +51,12 @@
stackTrace = error.stackTrace;
}
- if (stackTrace == null) stackTrace = new Trace.current();
+ if (stackTrace == null) stackTrace = new Chain.current();
return new ScheduleError(schedule, error, stackTrace);
}
- // TODO(floitsch): restore StackTrace type when it has been integrated into
- // the core libraries.
- ScheduleError(Schedule schedule, error, var stackTrace)
- : error = error,
- stackTrace = stackTrace,
- schedule = schedule,
+ ScheduleError(Schedule schedule, this.error, this.stackTrace)
+ : schedule = schedule,
task = schedule.currentTask,
queue = schedule.currentQueue,
pendingCallbacks = schedule.currentQueue == null ? <PendingCallback>[]
@@ -86,7 +80,7 @@
}
if (stackTrace != null) {
- result.write('Stack trace:\n');
+ result.write('Stack chain:\n');
result.write(prefixLines(terseTraceString(stackTrace)));
result.write("\n\n");
}
diff --git a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
index 7241171..fdfcd44 100644
--- a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
@@ -6,8 +6,6 @@
import 'dart:async';
-import 'package:stack_trace/stack_trace.dart';
-
import '../scheduled_test.dart';
/// Matches a [Future] that completes successfully with a value. Note that this
@@ -62,11 +60,9 @@
}
}
- var outerTrace = new Trace.current();
currentSchedule.wrapFuture(item.then((value) {
if (_matcher == null) return;
- // TODO(floitsch): we cannot switch traces anymore.
// If expect throws we might want to be able to switch to the outer trace
// instead.
expect(value, _matcher);
diff --git a/pkg/scheduled_test/lib/src/scheduled_server/handler.dart b/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
index 316d536..ecac381 100644
--- a/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
@@ -53,7 +53,7 @@
// between a test failing while waiting for a handler and a test failing
// while executing a handler.
chainToCompleter(schedule(() {
- return new Future.sync(() {
+ return syncFuture(() {
if (request.method != method || request.uri.path != path) {
fail("'${server.description}' expected $method $path, "
"but got ${request.method} ${request.uri.path}.");
@@ -71,7 +71,7 @@
/// completing. Otherwise, completes immediately.
Future _waitForTask() {
return pumpEventQueue().then((_) {
- if (currentSchedule.currentTask != _taskBefore) return;
+ if (currentSchedule.currentTask != _taskBefore) return null;
// If we're one task before the handler was scheduled, wait for that
// task to complete and pump the event queue so that [ready] will be
// set.
diff --git a/pkg/scheduled_test/lib/src/substitute_future.dart b/pkg/scheduled_test/lib/src/substitute_future.dart
index d30c936..5c91689 100644
--- a/pkg/scheduled_test/lib/src/substitute_future.dart
+++ b/pkg/scheduled_test/lib/src/substitute_future.dart
@@ -29,8 +29,8 @@
Future then(onValue(T value), {Function onError}) =>
_completer.future.then(onValue, onError: onError);
Future<T> whenComplete(action()) => _completer.future.whenComplete(action);
- Future timeout(Duration timeLimit, [void onTimeout()]) =>
- _completer.future.timeout(timeLimit, onTimeout);
+ Future timeout(Duration timeLimit, {void onTimeout()}) =>
+ _completer.future.timeout(timeLimit, onTimeout: onTimeout);
/// Substitutes [newFuture] for the currently wrapped [Future], which is
/// returned.
diff --git a/pkg/scheduled_test/lib/src/task.dart b/pkg/scheduled_test/lib/src/task.dart
index 997e806..5bd52430 100644
--- a/pkg/scheduled_test/lib/src/task.dart
+++ b/pkg/scheduled_test/lib/src/task.dart
@@ -61,7 +61,7 @@
Future get result => _resultCompleter.future;
final _resultCompleter = new Completer();
- final Trace stackTrace;
+ final Chain stackChain;
Task(fn(), String description, TaskQueue queue)
: this._(fn, description, queue, null, queue.contents.length);
@@ -71,7 +71,7 @@
Task._(fn(), this.description, TaskQueue queue, this.parent, this._id)
: queue = queue,
- stackTrace = new Trace.current() {
+ stackChain = new Chain.current() {
this.fn = () {
if (state != TaskState.WAITING) {
throw new StateError("Can't run $state task '$this'.");
@@ -123,12 +123,8 @@
String toString() => description == null ? "#$_id" : description;
String toStringWithStackTrace() {
- var result = toString();
- if (stackTrace != null) {
- var stackString = prefixLines(terseTraceString(stackTrace));
- result += "\n\nStack trace:\n$stackString";
- }
- return result;
+ var stackString = prefixLines(terseTraceString(stackChain));
+ return "$this\n\nStack chain:\n$stackString";
}
/// Returns a detailed representation of [queue] with this task highlighted.
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index 7daac77..9cba044 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -31,6 +31,9 @@
future.then(completer.complete, onError: completer.completeError);
}
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
/// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
/// first line is prefixed with that instead.
String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
@@ -72,10 +75,6 @@
}
}
-// TODO(nweiz): remove this when issue 8731 is fixed.
-/// Returns a [Stream] that will immediately emit [error] and then close.
-Stream errorStream(error) => new Future.error(error).asStream();
-
/// Returns a buffered stream that will emit the same values as the stream
/// returned by [future] once [future] completes.
///
@@ -127,12 +126,11 @@
///
/// If the [StreamIterator] has no elements, the result is a state error.
Future<String> streamIteratorFirst(StreamIterator<String> streamIterator) {
- StackTrace stackTrace = new Trace.current();
return streamIterator.moveNext().then((hasNext) {
if (hasNext) {
return streamIterator.current;
} else {
- return new Future.error(new StateError("No elements"), stackTrace);
+ throw new StateError("No elements");
}
});
}
@@ -233,8 +231,12 @@
/// Returns a string representation of [trace] that has the core and test frames
/// folded together.
String terseTraceString(StackTrace trace) {
- return new Trace.from(trace).terse.foldFrames((frame) {
- return frame.package == 'scheduled_test' || frame.package == 'unittest' ||
- frame.isCore;
- }).toString().trim();
+ return new Chain(new Chain.forTrace(trace).traces.map((trace) {
+ return trace.foldFrames((frame) {
+ return frame.package == 'scheduled_test' ||
+ frame.package == 'unittest' ||
+ frame.package == 'stack_trace' ||
+ frame.isCore;
+ });
+ })).terse.toString().trim();
}
diff --git a/pkg/scheduled_test/lib/src/value_future.dart b/pkg/scheduled_test/lib/src/value_future.dart
index 3821feb..b0d458b 100644
--- a/pkg/scheduled_test/lib/src/value_future.dart
+++ b/pkg/scheduled_test/lib/src/value_future.dart
@@ -35,6 +35,6 @@
Future then(onValue(T value), {Function onError}) =>
_future.then(onValue, onError: onError);
Future<T> whenComplete(action()) => _future.whenComplete(action);
- Future timeout(Duration timeLimit, [void onTimeout()]) =>
- _future.timeout(timeLimit, onTimeout);
+ Future timeout(Duration timeLimit, {void onTimeout()}) =>
+ _future.timeout(timeLimit, onTimeout: onTimeout);
}
diff --git a/pkg/scheduled_test/test/metatest.dart b/pkg/scheduled_test/test/metatest.dart
index 18309bd..c8bc601 100644
--- a/pkg/scheduled_test/test/metatest.dart
+++ b/pkg/scheduled_test/test/metatest.dart
@@ -204,7 +204,7 @@
"description": testCase.description,
"message": testCase.message,
"result": testCase.result,
- "stackTrace": testCase.stackTrace
+ "stackTrace": testCase.stackTrace.toString()
}).toList()
});
}
diff --git a/pkg/scheduled_test/test/scheduled_process_test.dart b/pkg/scheduled_test/test/scheduled_process_test.dart
index 151e917..8ff1533 100644
--- a/pkg/scheduled_test/test/scheduled_process_test.dart
+++ b/pkg/scheduled_test/test/scheduled_process_test.dart
@@ -5,7 +5,6 @@
library scheduled_process_test;
import 'dart:async';
-import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
diff --git a/pkg/scheduled_test/test/utils.dart b/pkg/scheduled_test/test/utils.dart
index 9bfc913..6fc24f3 100644
--- a/pkg/scheduled_test/test/utils.dart
+++ b/pkg/scheduled_test/test/utils.dart
@@ -25,7 +25,7 @@
Future timeout(Future input, int milliseconds, onTimeout()) {
var completer = new Completer();
var timer = new Timer(new Duration(milliseconds: milliseconds), () {
- chainToCompleter(new Future.sync(onTimeout), completer);
+ chainToCompleter(syncFuture(onTimeout), completer);
});
input.then((value) {
if (completer.isCompleted) return;
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index aa32bd7..2920d87 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -20,12 +20,11 @@
* address.street = 'N 34th';
* address.city = 'Seattle';
* var serialization = new Serialization()
- * ..addRuleFor(address);
+ * ..addRuleFor(Address);
* Map output = serialization.write(address);
*
- * This creates a new serialization and adds a rule for address objects. Right
- * now it has to be passed an address instance because of limitations using
- * Address as a literal. Then we ask the [Serialization] to write the address
+ * This creates a new serialization and adds a rule for address objects.
+ * Then we ask the [Serialization] to write the address
* and we get back a Map which is a [json]able representation of the state of
* the address and related objects. Note that while the output in this case
* is a [Map], the type will vary depending on which output format we've told
@@ -35,7 +34,7 @@
* fields of the address object. We can also specify those fields explicitly.
*
* var serialization = new Serialization()
- * ..addRuleFor(address,
+ * ..addRuleFor(Address,
* constructor: "create",
* constructorFields: ["number", "street"],
* fields: ["city"]);
@@ -47,7 +46,7 @@
* serialized.
*
* var serialization = new Serialization()
- * ..addRuleFor(address,
+ * ..addRuleFor(Address,
* constructor: "",
* excludeFields: ["other", "stuff"]);
*
@@ -189,7 +188,7 @@
* [Reader] or [Writer] respectively.
*
* new Serialization()
- * ..addRuleFor(new Person(), constructorFields: ["name"])
+ * ..addRuleFor(Person, constructorFields: ["name"])
* ..namedObjects['Person'] = reflect(new Person()).type;
*/
library serialization;
diff --git a/pkg/unittest/lib/mirror_matchers.dart b/pkg/unittest/lib/mirror_matchers.dart
index 7d1597f..25f2b6d 100644
--- a/pkg/unittest/lib/mirror_matchers.dart
+++ b/pkg/unittest/lib/mirror_matchers.dart
@@ -49,10 +49,19 @@
var mirror = reflect(item);
var classMirror = mirror.type;
var symbol = new Symbol(_name);
- if (!classMirror.getters.containsKey(symbol)) {
+ var candidate = classMirror.declarations[symbol];
+ if (candidate == null) {
addStateInfo(matchState, {'reason': 'has no property named "$_name"'});
return false;
}
+ bool isInstanceField = candidate is VariableMirror && !candidate.isStatic;
+ bool isInstanceGetter =
+ candidate is MethodMirror && candidate.isGetter && !candidate.isStatic;
+ if (!(isInstanceField || isInstanceGetter)) {
+ addStateInfo(matchState, {'reason':
+ 'has a member named "$_name", but it is not an instance property'});
+ return false;
+ }
if (_matcher == null) return true;
var result = mirror.getField(symbol);
var resultMatches = _matcher.matches(result.reflectee, matchState);
diff --git a/pkg/unittest/test/mirror_matchers_test.dart b/pkg/unittest/test/mirror_matchers_test.dart
index 4a445ed..2fe0319 100644
--- a/pkg/unittest/test/mirror_matchers_test.dart
+++ b/pkg/unittest/test/mirror_matchers_test.dart
@@ -7,6 +7,13 @@
import 'test_utils.dart';
+class C {
+ var instanceField = 1;
+ get instanceGetter => 2;
+ static var staticField = 3;
+ static get staticGetter => 4;
+}
+
void main() {
initUtils();
@@ -21,5 +28,18 @@
'Expected: has property "length" which matches <2> '
'Actual: [3] '
'Which: has property "length" with value <1>');
+ var c = new C();
+ shouldPass(c, hasProperty('instanceField', 1));
+ shouldPass(c, hasProperty('instanceGetter', 2));
+ shouldFail(c, hasProperty('staticField'),
+ 'Expected: has property "staticField" '
+ 'Actual: <Instance of \'C\'> '
+ 'Which: has a member named "staticField",'
+ ' but it is not an instance property');
+ shouldFail(c, hasProperty('staticGetter'),
+ 'Expected: has property "staticGetter" '
+ 'Actual: <Instance of \'C\'> '
+ 'Which: has a member named "staticGetter",'
+ ' but it is not an instance property');
});
}
\ No newline at end of file
diff --git a/pkg/watcher/lib/src/directory_watcher/linux.dart b/pkg/watcher/lib/src/directory_watcher/linux.dart
index d62c6ef..76558dd 100644
--- a/pkg/watcher/lib/src/directory_watcher/linux.dart
+++ b/pkg/watcher/lib/src/directory_watcher/linux.dart
@@ -7,6 +7,8 @@
import 'dart:async';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
import '../utils.dart';
import '../watch_event.dart';
import 'resubscribable.dart';
@@ -56,13 +58,13 @@
_LinuxDirectoryWatcher(String directory)
: directory = directory {
// Batch the inotify changes together so that we can dedup events.
- var innerStream = new Directory(directory).watch().transform(
- new BatchedStreamTransformer<FileSystemEvent>());
+ var innerStream = Chain.track(new Directory(directory).watch())
+ .transform(new BatchedStreamTransformer<FileSystemEvent>());
_listen(innerStream, _onBatch,
onError: _eventsController.addError,
onDone: _onDone);
- _listen(new Directory(directory).list(), (entity) {
+ _listen(Chain.track(new Directory(directory).list()), (entity) {
_entries[entity.path] = new _EntryState(entity is Directory);
if (entity is! Directory) return;
_watchSubdir(entity.path);
@@ -157,7 +159,7 @@
// event for every new file.
watcher.ready.then((_) {
if (!isReady || _eventsController.isClosed) return;
- _listen(new Directory(path).list(recursive: true), (entry) {
+ _listen(Chain.track(new Directory(path).list(recursive: true)), (entry) {
if (entry is Directory) return;
_eventsController.add(new WatchEvent(ChangeType.ADD, entry.path));
}, onError: (error, stackTrace) {
@@ -213,7 +215,7 @@
if (oldState == _EntryState.DIRECTORY) {
var watcher = _subWatchers.remove(path);
- if (watcher == null) return;
+ if (watcher == null) continue;
for (var path in watcher._allFiles) {
_eventsController.add(new WatchEvent(ChangeType.REMOVE, path));
}
@@ -247,6 +249,17 @@
/// Handles the underlying event stream closing, indicating that the directory
/// being watched was removed.
void _onDone() {
+ // Most of the time when a directory is removed, its contents will get
+ // individual REMOVE events before the watch stream is closed -- in that
+ // case, [_entries] will be empty here. However, if the directory's removal
+ // is caused by a MOVE, we need to manually emit events.
+ if (isReady) {
+ _entries.forEach((path, state) {
+ if (state == _EntryState.DIRECTORY) return;
+ _eventsController.add(new WatchEvent(ChangeType.REMOVE, path));
+ });
+ }
+
// The parent directory often gets a close event before the subdirectories
// are done emitting events. We wait for them to finish before we close
// [events] so that we can be sure to emit a remove event for every file
diff --git a/pkg/watcher/lib/src/directory_watcher/mac_os.dart b/pkg/watcher/lib/src/directory_watcher/mac_os.dart
index 5b1feb3..90036cc 100644
--- a/pkg/watcher/lib/src/directory_watcher/mac_os.dart
+++ b/pkg/watcher/lib/src/directory_watcher/mac_os.dart
@@ -7,6 +7,9 @@
import 'dart:async';
import 'dart:io';
+import 'package:path/path.dart' as p;
+import 'package:stack_trace/stack_trace.dart';
+
import '../constructable_file_system_event.dart';
import '../path_set.dart';
import '../utils.dart';
@@ -21,14 +24,22 @@
/// succession, it won't report them in the order they occurred. See issue
/// 14373.
///
-/// This also works around issues 14793, 14806, and 14849 in the implementation
-/// of [Directory.watch].
+/// This also works around issues 15458 and 14849 in the implementation of
+/// [Directory.watch].
class MacOSDirectoryWatcher extends ResubscribableDirectoryWatcher {
+ // TODO(nweiz): remove these when issue 15042 is fixed.
+ static var logDebugInfo = false;
+ static var _count = 0;
+
MacOSDirectoryWatcher(String directory)
- : super(directory, () => new _MacOSDirectoryWatcher(directory));
+ : super(directory, () => new _MacOSDirectoryWatcher(directory, _count++));
}
class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher {
+ // TODO(nweiz): remove these when issue 15042 is fixed.
+ static var _count = 0;
+ final String _id;
+
final String directory;
Stream<WatchEvent> get events => _eventsController.stream;
@@ -68,21 +79,33 @@
/// watcher is closed. This does not include [_watchSubscription].
final _subscriptions = new Set<StreamSubscription>();
- _MacOSDirectoryWatcher(String directory)
+ _MacOSDirectoryWatcher(String directory, int parentId)
: directory = directory,
- _files = new PathSet(directory) {
+ _files = new PathSet(directory),
+ _id = "$parentId/${_count++}" {
_startWatch();
- _listen(new Directory(directory).list(recursive: true),
+ _listen(Chain.track(new Directory(directory).list(recursive: true)),
(entity) {
if (entity is! Directory) _files.add(entity.path);
},
onError: _emitError,
- onDone: _readyCompleter.complete,
+ onDone: () {
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] watcher is ready, known files:");
+ for (var file in _files.toSet()) {
+ print("[$_id] ${p.relative(file, from: directory)}");
+ }
+ }
+ _readyCompleter.complete();
+ },
cancelOnError: true);
}
void close() {
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] watcher is closed");
+ }
for (var subscription in _subscriptions) {
subscription.cancel();
}
@@ -94,26 +117,65 @@
/// The callback that's run when [Directory.watch] emits a batch of events.
void _onBatch(List<FileSystemEvent> batch) {
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] ======== batch:");
+ for (var event in batch) {
+ print("[$_id] ${_formatEvent(event)}");
+ }
+
+ print("[$_id] known files:");
+ for (var file in _files.toSet()) {
+ print("[$_id] ${p.relative(file, from: directory)}");
+ }
+ }
+
batches++;
_sortEvents(batch).forEach((path, events) {
+ var relativePath = p.relative(path, from: directory);
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] events for $relativePath:\n");
+ for (var event in events) {
+ print("[$_id] ${_formatEvent(event)}");
+ }
+ }
+
var canonicalEvent = _canonicalEvent(events);
events = canonicalEvent == null ?
_eventsBasedOnFileSystem(path) : [canonicalEvent];
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] canonical event for $relativePath: "
+ "${_formatEvent(canonicalEvent)}");
+ print("[$_id] actionable events for $relativePath: "
+ "${events.map(_formatEvent)}");
+ }
for (var event in events) {
if (event is FileSystemCreateEvent) {
if (!event.isDirectory) {
+ // Don't emit ADD events for files or directories that we already
+ // know about. Such an event comes from FSEvents reporting an add
+ // that happened prior to the watch beginning.
+ if (_files.contains(path)) continue;
+
_emitEvent(ChangeType.ADD, path);
_files.add(path);
continue;
}
- _listen(new Directory(path).list(recursive: true), (entity) {
+ if (_files.containsDir(path)) continue;
+
+ _listen(Chain.track(new Directory(path).list(recursive: true)),
+ (entity) {
if (entity is Directory) return;
_emitEvent(ChangeType.ADD, entity.path);
_files.add(entity.path);
- }, onError: _emitError, cancelOnError: true);
+ }, onError: (e, stackTrace) {
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] got error listing $relativePath: $e");
+ }
+ _emitError(e, stackTrace);
+ }, cancelOnError: true);
} else if (event is FileSystemModifyEvent) {
assert(!event.isDirectory);
_emitEvent(ChangeType.MODIFY, path);
@@ -125,6 +187,10 @@
}
}
});
+
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] ======== batch complete");
+ }
}
/// Sort all the events in a batch into sets based on their path.
@@ -161,34 +227,12 @@
set.add(event);
}
- for (var event in batch.where((event) => event is! FileSystemMoveEvent)) {
+ for (var event in batch) {
+ // The Mac OS watcher doesn't emit move events. See issue 14806.
+ assert(event is! FileSystemMoveEvent);
addEvent(event.path, event);
}
- // Issue 14806 means that move events can be misleading if they're in the
- // same batch as another modification of a related file. If they are, we
- // make the event set empty to ensure we check the state of the filesystem.
- // Otherwise, treat them as a DELETE followed by an ADD.
- for (var event in batch.where((event) => event is FileSystemMoveEvent)) {
- if (eventsForPaths.containsKey(event.path) ||
- eventsForPaths.containsKey(event.destination)) {
-
- if (!isInModifiedDirectory(event.path)) {
- eventsForPaths[event.path] = new Set();
- }
- if (!isInModifiedDirectory(event.destination)) {
- eventsForPaths[event.destination] = new Set();
- }
-
- continue;
- }
-
- addEvent(event.path, new ConstructableFileSystemDeleteEvent(
- event.path, event.isDirectory));
- addEvent(event.destination, new ConstructableFileSystemCreateEvent(
- event.path, event.isDirectory));
- }
-
return eventsForPaths;
}
@@ -209,6 +253,7 @@
var type = batch.first.type;
var isDir = batch.first.isDirectory;
+ var hadModifyEvent = false;
for (var event in batch.skip(1)) {
// If one event reports that the file is a directory and another event
@@ -219,7 +264,10 @@
// safely assume the file was modified after a CREATE or before the
// REMOVE; otherwise there will also be a REMOVE or CREATE event
// (respectively) that will be contradictory.
- if (event is FileSystemModifyEvent) continue;
+ if (event is FileSystemModifyEvent) {
+ hadModifyEvent = true;
+ continue;
+ }
assert(event is FileSystemCreateEvent || event is FileSystemDeleteEvent);
// If we previously thought this was a MODIFY, we now consider it to be a
@@ -234,13 +282,23 @@
if (type != event.type) return null;
}
+ // If we got a CREATE event for a file we already knew about, that comes
+ // from FSEvents reporting an add that happened prior to the watch
+ // beginning. If we also received a MODIFY event, we want to report that,
+ // but not the CREATE.
+ if (type == FileSystemEvent.CREATE && hadModifyEvent &&
+ _files.contains(batch.first.path)) {
+ type = FileSystemEvent.MODIFY;
+ }
+
switch (type) {
case FileSystemEvent.CREATE:
- // Issue 14793 means that CREATE events can actually mean DELETE, so we
- // should always check the filesystem for them.
- return null;
+ return new ConstructableFileSystemCreateEvent(batch.first.path, isDir);
case FileSystemEvent.DELETE:
- return new ConstructableFileSystemDeleteEvent(batch.first.path, isDir);
+ // Issue 15458 means that DELETE events for directories can actually
+ // mean CREATE, so we always check the filesystem for them.
+ if (isDir) return null;
+ return new ConstructableFileSystemCreateEvent(batch.first.path, false);
case FileSystemEvent.MODIFY:
return new ConstructableFileSystemModifyEvent(
batch.first.path, isDir, false);
@@ -261,6 +319,13 @@
var fileExists = new File(path).existsSync();
var dirExists = new Directory(path).existsSync();
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] file existed: $fileExisted");
+ print("[$_id] dir existed: $dirExisted");
+ print("[$_id] file exists: $fileExists");
+ print("[$_id] dir exists: $dirExists");
+ }
+
var events = [];
if (fileExisted) {
if (fileExists) {
@@ -314,8 +379,9 @@
/// Start or restart the underlying [Directory.watch] stream.
void _startWatch() {
// Batch the FSEvent changes together so that we can dedup events.
- var innerStream = new Directory(directory).watch(recursive: true).transform(
- new BatchedStreamTransformer<FileSystemEvent>());
+ var innerStream =
+ Chain.track(new Directory(directory).watch(recursive: true))
+ .transform(new BatchedStreamTransformer<FileSystemEvent>());
_watchSubscription = innerStream.listen(_onBatch,
onError: _eventsController.addError,
onDone: _onDone);
@@ -325,10 +391,9 @@
void _emitEvent(ChangeType type, String path) {
if (!isReady) return;
- // Don't emit ADD events for files that we already know about. Such an event
- // probably comes from FSEvents reporting an add that happened prior to the
- // watch beginning.
- if (type == ChangeType.ADD && _files.contains(path)) return;
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("[$_id] emitting $type ${p.relative(path, from: directory)}");
+ }
_eventsController.add(new WatchEvent(type, path));
}
@@ -350,4 +415,23 @@
}, cancelOnError: cancelOnError);
_subscriptions.add(subscription);
}
+
+ // TODO(nweiz): remove this when issue 15042 is fixed.
+ /// Return a human-friendly string representation of [event].
+ String _formatEvent(FileSystemEvent event) {
+ if (event == null) return 'null';
+
+ var path = p.relative(event.path, from: directory);
+ var type = event.isDirectory ? 'directory' : 'file';
+ if (event is FileSystemCreateEvent) {
+ return "create $type $path";
+ } else if (event is FileSystemDeleteEvent) {
+ return "delete $type $path";
+ } else if (event is FileSystemModifyEvent) {
+ return "modify $type $path";
+ } else if (event is FileSystemMoveEvent) {
+ return "move $type $path to "
+ "${p.relative(event.destination, from: directory)}";
+ }
+ }
}
diff --git a/pkg/watcher/lib/src/directory_watcher/polling.dart b/pkg/watcher/lib/src/directory_watcher/polling.dart
index e50a0c0..684f7aa 100644
--- a/pkg/watcher/lib/src/directory_watcher/polling.dart
+++ b/pkg/watcher/lib/src/directory_watcher/polling.dart
@@ -8,6 +8,7 @@
import 'dart:io';
import 'package:crypto/crypto.dart';
+import 'package:stack_trace/stack_trace.dart';
import '../async_queue.dart';
import '../stat.dart';
@@ -105,7 +106,7 @@
_filesToProcess.add(null);
}
- var stream = new Directory(directory).list(recursive: true);
+ var stream = Chain.track(new Directory(directory).list(recursive: true));
_listSubscription = stream.listen((entity) {
assert(!_events.isClosed);
@@ -185,7 +186,7 @@
/// Calculates the SHA-1 hash of the file at [path].
Future<List<int>> _hashFile(String path) {
- return new File(path).readAsBytes().then((bytes) {
+ return Chain.track(new File(path).readAsBytes()).then((bytes) {
var sha1 = new SHA1();
sha1.add(bytes);
return sha1.close();
diff --git a/pkg/watcher/lib/src/stat.dart b/pkg/watcher/lib/src/stat.dart
index d36eff3..166d789 100644
--- a/pkg/watcher/lib/src/stat.dart
+++ b/pkg/watcher/lib/src/stat.dart
@@ -7,6 +7,8 @@
import 'dart:async';
import 'dart:io';
+import 'package:stack_trace/stack_trace.dart';
+
/// A function that takes a file path and returns the last modified time for
/// the file at that path.
typedef DateTime MockTimeCallback(String path);
@@ -29,5 +31,5 @@
return new Future.value(_mockTimeCallback(path));
}
- return FileStat.stat(path).then((stat) => stat.modified);
+ return Chain.track(FileStat.stat(path)).then((stat) => stat.modified);
}
diff --git a/pkg/watcher/pubspec.yaml b/pkg/watcher/pubspec.yaml
index b95c7ef..93d8eb4 100644
--- a/pkg/watcher/pubspec.yaml
+++ b/pkg/watcher/pubspec.yaml
@@ -9,6 +9,7 @@
dependencies:
crypto: ">=0.9.0 <0.10.0"
path: ">=0.9.0 <0.10.0"
+ stack_trace: ">=0.9.0 <0.10.0"
dev_dependencies:
scheduled_test: ">=0.9.0 <0.10.0"
unittest: ">=0.9.0 <0.10.0"
diff --git a/pkg/watcher/test/directory_watcher/linux_test.dart b/pkg/watcher/test/directory_watcher/linux_test.dart
index ba69569..f53b272 100644
--- a/pkg/watcher/test/directory_watcher/linux_test.dart
+++ b/pkg/watcher/test/directory_watcher/linux_test.dart
@@ -14,14 +14,7 @@
watcherFactory = (dir) => new LinuxDirectoryWatcher(dir);
- setUp(() {
- // Increase the timeout because closing a [Directory.watch] stream blocks
- // the main isolate for a very long time on Goobuntu, as of kernel
- // 3.2.5-gg1336 (see issue 14606).
- currentSchedule.timeout *= 3;
-
- createSandbox();
- });
+ setUp(createSandbox);
sharedTests();
diff --git a/pkg/watcher/test/directory_watcher/mac_os_test.dart b/pkg/watcher/test/directory_watcher/mac_os_test.dart
index 7d31221..8fc2d3e 100644
--- a/pkg/watcher/test/directory_watcher/mac_os_test.dart
+++ b/pkg/watcher/test/directory_watcher/mac_os_test.dart
@@ -2,8 +2,6 @@
// 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:async';
-
import 'package:scheduled_test/scheduled_test.dart';
import 'package:watcher/src/directory_watcher/mac_os.dart';
import 'package:watcher/watcher.dart';
@@ -13,6 +11,7 @@
main() {
initConfig();
+ MacOSDirectoryWatcher.logDebugInfo = true;
watcherFactory = (dir) => new MacOSDirectoryWatcher(dir);
@@ -52,28 +51,6 @@
withPermutations((i, j, k) =>
writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
- // We sleep here because a narrow edge case caused by two interacting bugs
- // can produce events that aren't expected if we start the watcher too
- // soon after creating the files above. Here's what happens:
- //
- // * We create "dir/sub" and its contents above.
- //
- // * We initialize the watcher watching "dir".
- //
- // * Due to issue 14373, the watcher can receive native events describing
- // the creation of "dir/sub" and its contents despite the fact that they
- // occurred before the watcher was started.
- //
- // * Usually the above events will occur while the watcher is doing its
- // initial scan of "dir/sub" and be ignored, but occasionally they will
- // occur afterwards.
- //
- // * When processing the bogus CREATE events, the watcher has to assume that
- // they could mean something other than CREATE (issue 14793). Thus it
- // assumes that the files or directories in question could have changed
- // and emits CHANGE events or additional REMOVE/CREATE pairs for them.
- schedule(() => new Future.delayed(new Duration(seconds: 2)));
-
startWatcher(dir: "dir");
renameDir("dir/sub", "sub");
diff --git a/pkg/watcher/test/no_subscription/mac_os_test.dart b/pkg/watcher/test/no_subscription/mac_os_test.dart
index 3862134..e0275c4 100644
--- a/pkg/watcher/test/no_subscription/mac_os_test.dart
+++ b/pkg/watcher/test/no_subscription/mac_os_test.dart
@@ -9,32 +9,6 @@
import 'shared.dart';
import '../utils.dart';
-// This is currently failing due to issue 14793. The reason is fairly complex:
-//
-// 1. As part of the test, an "unwatched.txt" file is created while there are no
-// active watchers on the containing directory.
-//
-// 2. A watcher is then added.
-//
-// 3. The watcher lists the contents of the directory and notices that
-// "unwatched.txt" already exists.
-//
-// 4. Since FSEvents reports past changes (issue 14373), the IO event stream
-// emits a CREATED event for "unwatched.txt".
-//
-// 5. Due to issue 14793, the watcher cannot trust that this is really a CREATED
-// event and checks the status of "unwatched.txt" on the filesystem against
-// its internal state.
-//
-// 6. "unwatched.txt" exists on the filesystem and the watcher knows about it
-// internally as well. It assumes this means that the file was modified.
-//
-// 7. The watcher emits an unexpected MODIFIED event for "unwatched.txt",
-// causing the test to fail.
-//
-// Once issue 14793 is fixed, this will no longer be the case and the test will
-// work again.
-
main() {
initConfig();
diff --git a/pkg/watcher/test/no_subscription/shared.dart b/pkg/watcher/test/no_subscription/shared.dart
index de625d5..99172a2 100644
--- a/pkg/watcher/test/no_subscription/shared.dart
+++ b/pkg/watcher/test/no_subscription/shared.dart
@@ -41,16 +41,6 @@
schedule(() {
completer = new Completer();
subscription = watcher.events.listen(wrapAsync((event) {
- // TODO(nweiz): Remove this when either issue 14373 or 14793 is fixed.
- // Issue 14373 means that the new [Directory.watch] will emit an event
- // for "unwatched.txt" being created, and issue 14793 means we have to
- // check the filesystem, which leads us to assume that the file has been
- // modified.
- if (Platform.isMacOS && event.path.endsWith("unwatched.txt")) {
- expect(event, isWatchEvent(ChangeType.MODIFY, "unwatched.txt"));
- return;
- }
-
// We should get an event for the third file, not the one added while
// we weren't subscribed.
expect(event, isWatchEvent(ChangeType.ADD, "added.txt"));
diff --git a/pkg/watcher/test/utils.dart b/pkg/watcher/test/utils.dart
index 567bdb2..a7bd9b6 100644
--- a/pkg/watcher/test/utils.dart
+++ b/pkg/watcher/test/utils.dart
@@ -15,6 +15,9 @@
import 'package:watcher/src/stat.dart';
import 'package:watcher/src/utils.dart';
+// TODO(nweiz): remove this when issue 15042 is fixed.
+import 'package:watcher/src/directory_watcher/mac_os.dart';
+
/// The path to the temporary sandbox created for each test. All file
/// operations are implicitly relative to this directory.
String _sandboxDir;
@@ -115,6 +118,11 @@
///
/// If [dir] is provided, watches a subdirectory in the sandbox with that name.
void startWatcher({String dir}) {
+ var testCase = currentTestCase.description;
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("starting watcher for $testCase");
+ }
+
// We want to wait until we're ready *after* we subscribe to the watcher's
// events.
_watcher = createWatcher(dir: dir, waitForReady: false);
@@ -128,6 +136,10 @@
onError: currentSchedule.signalError);
currentSchedule.onComplete.schedule(() {
+ if (MacOSDirectoryWatcher.logDebugInfo) {
+ print("stopping watcher for $testCase");
+ }
+
var numEvents = _nextEvent;
subscription.cancel();
_nextEvent = 0;
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 9f241b1..2a0e678 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -4,6 +4,7 @@
library builtin;
import 'dart:io';
+import 'dart:async';
// import 'root_library'; happens here from C Code
// The root library (aka the script) is imported into this library. The
@@ -91,6 +92,10 @@
} catch (error) {
_requestFailed(error);
}
+ // TODO(floitsch): remove this line. It's just here to push an event on the
+ // event loop so that we invoke the scheduled microtasks. Also remove the
+ // import of dart:async when this line is not needed anymore.
+ Timer.run(() {});
}
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index eee4430..ca3d8a3 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -60,9 +60,12 @@
V(File_GetStdioHandleType, 1) \
V(File_GetType, 2) \
V(File_AreIdentical, 2) \
+ V(FileSystemWatcher_CloseWatcher, 1) \
+ V(FileSystemWatcher_GetSocketId, 2) \
+ V(FileSystemWatcher_InitWatcher, 0) \
V(FileSystemWatcher_IsSupported, 0) \
- V(FileSystemWatcher_ReadEvents, 1) \
- V(FileSystemWatcher_UnwatchPath, 1) \
+ V(FileSystemWatcher_ReadEvents, 2) \
+ V(FileSystemWatcher_UnwatchPath, 2) \
V(FileSystemWatcher_WatchPath, 4) \
V(Logger_PrintString, 1)
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index ed010db..d284b2e 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -26,7 +26,9 @@
const char* DartUtils::kDartExtensionScheme = "dart-ext:";
const char* DartUtils::kAsyncLibURL = "dart:async";
const char* DartUtils::kBuiltinLibURL = "dart:builtin";
+const char* DartUtils::kCollectionDevLibURL = "dart:_collection-dev";
const char* DartUtils::kCoreLibURL = "dart:core";
+const char* DartUtils::kIsolateLibURL = "dart:isolate";
const char* DartUtils::kIOLibURL = "dart:io";
const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
const char* DartUtils::kUriLibURL = "dart:uri";
@@ -678,18 +680,19 @@
Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
Dart_Handle builtin_lib) {
// Setup the internal library's 'internalPrint' function.
- Dart_Handle internal_lib =
- Dart_LookupLibrary(NewString("dart:_collection-dev"));
- DART_CHECK_VALID(internal_lib);
Dart_Handle print = Dart_Invoke(
builtin_lib, NewString("_getPrintClosure"), 0, NULL);
- Dart_Handle result = Dart_SetField(internal_lib,
+ Dart_Handle url = NewString(kCollectionDevLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle collection_dev_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(collection_dev_lib);
+ Dart_Handle result = Dart_SetField(collection_dev_lib,
NewString("_printClosure"),
print);
DART_CHECK_VALID(result);
// Setup the 'timer' factory.
- Dart_Handle url = NewString(kAsyncLibURL);
+ url = NewString(kAsyncLibURL);
DART_CHECK_VALID(url);
Dart_Handle async_lib = Dart_LookupLibrary(url);
DART_CHECK_VALID(async_lib);
@@ -701,8 +704,22 @@
DART_CHECK_VALID(Dart_Invoke(
async_lib, NewString("_setTimerFactoryClosure"), 1, args));
+ // Setup the 'scheduleImmediate' closure.
+ url = NewString(kIsolateLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle isolate_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(isolate_lib);
+ Dart_Handle schedule_immediate_closure =
+ Dart_Invoke(isolate_lib, NewString("_getIsolateScheduleImmediateClosure"),
+ 0, NULL);
+ args[0] = schedule_immediate_closure;
+ DART_CHECK_VALID(Dart_Invoke(
+ async_lib, NewString("_setScheduleImmediateClosure"), 1, args));
+
// Setup the corelib 'Uri.base' getter.
- Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
+ url = NewString(kCoreLibURL);
+ DART_CHECK_VALID(url);
+ Dart_Handle corelib = Dart_LookupLibrary(url);
DART_CHECK_VALID(corelib);
Dart_Handle uri_base = Dart_Invoke(
builtin_lib, NewString("_getUriBaseClosure"), 0, NULL);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index f6ae3ab..3e1dbe9 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -209,7 +209,9 @@
static const char* kDartExtensionScheme;
static const char* kAsyncLibURL;
static const char* kBuiltinLibURL;
+ static const char* kCollectionDevLibURL;
static const char* kCoreLibURL;
+ static const char* kIsolateLibURL;
static const char* kIOLibURL;
static const char* kIOLibPatchURL;
static const char* kUriLibURL;
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index c7e1969..335238c 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -13,6 +13,7 @@
#include <string.h> // NOLINT
#include <sys/epoll.h> // NOLINT
#include <sys/stat.h> // NOLINT
+#include <sys/timerfd.h> // NOLINT
#include <unistd.h> // NOLINT
#include <fcntl.h> // NOLINT
@@ -29,7 +30,6 @@
namespace bin {
static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
static const int kShutdownId = -2;
@@ -134,11 +134,27 @@
if (status == -1) {
FATAL("Failed adding interrupt fd to epoll instance");
}
+ timer_fd_ = TEMP_FAILURE_RETRY(timerfd_create(CLOCK_REALTIME,
+ TFD_NONBLOCK | TFD_CLOEXEC));
+ if (epoll_fd_ == -1) {
+ FATAL("Failed creating timerfd file descriptor");
+ }
+ // Register the timer_fd_ with the epoll instance.
+ event.events = EPOLLIN;
+ event.data.fd = timer_fd_;
+ status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
+ EPOLL_CTL_ADD,
+ timer_fd_,
+ &event));
+ if (status == -1) {
+ FATAL("Failed adding timerfd fd to epoll instance");
+ }
}
EventHandlerImplementation::~EventHandlerImplementation() {
TEMP_FAILURE_RETRY(close(epoll_fd_));
+ TEMP_FAILURE_RETRY(close(timer_fd_));
TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
}
@@ -191,6 +207,14 @@
for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) {
if (msg[i].id == kTimerId) {
timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data);
+ struct itimerspec it;
+ memset(&it, 0, sizeof(it));
+ if (timeout_queue_.HasTimeout()) {
+ int64_t millis = timeout_queue_.CurrentTimeout();
+ it.it_value.tv_sec = millis / 1000;
+ it.it_value.tv_nsec = (millis % 1000) * 1000000;
+ }
+ timerfd_settime(timer_fd_, TFD_TIMER_ABSTIME, &it, NULL);
} else if (msg[i].id == kShutdownId) {
shutdown_ = true;
} else {
@@ -338,6 +362,13 @@
for (int i = 0; i < size; i++) {
if (events[i].data.ptr == NULL) {
interrupt_seen = true;
+ } else if (events[i].data.fd == timer_fd_) {
+ int64_t val;
+ VOID_TEMP_FAILURE_RETRY(read(timer_fd_, &val, sizeof(val)));
+ if (timeout_queue_.HasTimeout()) {
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ timeout_queue_.RemoveCurrent();
+ }
} else {
SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr);
intptr_t event_mask = GetPollEvents(events[i].events, sd);
@@ -359,29 +390,6 @@
}
-int64_t EventHandlerImplementation::GetTimeout() {
- if (!timeout_queue_.HasTimeout()) {
- return kInfinityTimeout;
- }
- int64_t millis = timeout_queue_.CurrentTimeout() -
- TimerUtils::GetCurrentTimeMilliseconds();
- return (millis < 0) ? 0 : millis;
-}
-
-
-void EventHandlerImplementation::HandleTimeout() {
- if (timeout_queue_.HasTimeout()) {
- int64_t millis = timeout_queue_.CurrentTimeout() -
- TimerUtils::GetCurrentTimeMilliseconds();
- if (millis <= 0) {
- DartUtils::PostNull(timeout_queue_.CurrentPort());
- // Remove current from queue.
- timeout_queue_.RemoveCurrent();
- }
- }
-}
-
-
void EventHandlerImplementation::Poll(uword args) {
static const intptr_t kMaxEvents = 16;
struct epoll_event events[kMaxEvents];
@@ -389,20 +397,15 @@
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(epoll_wait(handler_impl->epoll_fd_,
events,
kMaxEvents,
- millis));
+ -1));
ASSERT(EAGAIN == EWOULDBLOCK);
- if (result == -1) {
+ if (result <= 0) {
if (errno != EWOULDBLOCK) {
perror("Poll failed");
}
- } else if (result == 0) {
- handler_impl->HandleTimeout();
} else {
handler_impl->HandleEvents(events, result);
}
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index 6a96aa2..2e811e8 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -102,9 +102,7 @@
void Shutdown();
private:
- int64_t GetTimeout();
void HandleEvents(struct epoll_event* events, int size);
- void HandleTimeout();
static void Poll(uword args);
void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
void HandleInterruptFd();
@@ -118,6 +116,7 @@
bool shutdown_;
int interrupt_fds_[2];
int epoll_fd_;
+ int timer_fd_;
};
} // namespace bin
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 9f1f6d0..68612a5 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -20,6 +20,7 @@
/* patch */ static int _openStdio(int fd) native "File_OpenStdio";
}
+
patch class _RandomAccessFile {
/* patch */ static int _close(int id) native "File_Close";
/* patch */ static _readByte(int id) native "File_ReadByte";
@@ -37,52 +38,125 @@
/* patch */ static _flush(int id) native "File_Flush";
}
-patch class _FileSystemWatcher {
- /* patch */ factory _FileSystemWatcher(
- String path, int events, bool recursive)
- => new _FileSystemWatcherImpl(path, events, recursive);
- /* patch */ static bool get isSupported => _FileSystemWatcherImpl.isSupported;
+class _WatcherPath {
+ final int pathId;
+ final String path;
+ final int events;
+ int count = 0;
+ _WatcherPath(this.pathId, this.path, this.events);
}
-class _FileSystemWatcherImpl
- extends NativeFieldWrapperClass1
- implements _FileSystemWatcher {
+
+patch class _FileSystemWatcher {
+ static int _id;
+ static final Map<int, _WatcherPath> _idMap = {};
+
final String _path;
final int _events;
final bool _recursive;
- StreamController _controller;
- StreamSubscription _subscription;
+ _WatcherPath _watcherPath;
- _FileSystemWatcherImpl(this._path, this._events, this._recursive) {
- if (!isSupported) {
- throw new FileSystemException(
- "File system watching is not supported on this system",
- _path);
+ StreamController _broadcastController;
+
+ /* patch */ static Stream<FileSystemEvent> watch(
+ String path, int events, bool recursive) {
+ if (Platform.isLinux) {
+ return new _InotifyFileSystemWatcher(path, events, recursive).stream;
}
- _controller = new StreamController.broadcast(onListen: _listen,
- onCancel: _cancel);
+ if (Platform.isWindows) {
+ return new _Win32FileSystemWatcher(path, events, recursive).stream;
+ }
+ if (Platform.isMacOS) {
+ return new _FSEventStreamFileSystemWatcher(
+ path, events, recursive).stream;
+ }
+ throw new FileSystemException(
+ "File system watching is not supported on this platform");
}
+ _FileSystemWatcher._(this._path, this._events, this._recursive) {
+ if (!isSupported) {
+ throw new FileSystemException(
+ "File system watching is not supported on this platform",
+ _path);
+ }
+ _broadcastController = new StreamController.broadcast(onListen: _listen,
+ onCancel: _cancel);
+ }
+
+ Stream get stream => _broadcastController.stream;
+
void _listen() {
- int socketId;
+ if (_id == null) {
+ try {
+ _id = _initWatcher();
+ _newWatcher();
+ } catch (e) {
+ _broadcastController.addError(new FileSystemException(
+ "Failed to initialize file system entity watcher"));
+ _broadcastController.close();
+ return;
+ }
+ }
+ var pathId;
try {
- socketId = _watchPath(_path, _events, identical(true, _recursive));
+ pathId = _watchPath(_id, _path, _events, _recursive);
} catch (e) {
- _controller.addError(new FileSystemException(
+ _broadcastController.addError(new FileSystemException(
"Failed to watch path", _path, e));
- _controller.close();
+ _broadcastController.close();
return;
}
+ if (!_idMap.containsKey(pathId)) {
+ _idMap[pathId] = new _WatcherPath(pathId, _path, _events);
+ }
+ _watcherPath = _idMap[pathId];
+ _watcherPath.count++;
+ _pathWatched().pipe(_broadcastController);
+ }
+
+ void _cancel() {
+ if (_watcherPath != null) {
+ assert(_watcherPath.count > 0);
+ _watcherPath.count--;
+ if (_watcherPath.count == 0) {
+ _pathWatchedEnd();
+ _unwatchPath(_id, _watcherPath.pathId);
+ _idMap.remove(_watcherPath.pathId);
+ }
+ _watcherPath = null;
+ }
+ if (_idMap.isEmpty && _id != null) {
+ _closeWatcher(_id);
+ _doneWatcher();
+ _id = null;
+ }
+ }
+
+ // Called when (and after) a new watcher instance is created and available.
+ void _newWatcher() {}
+ // Called when a watcher is no longer needed.
+ void _doneWatcher() {}
+ // Called when a new path is being watched.
+ Stream _pathWatched() {}
+ // Called when a path is no longer being watched.
+ void _donePathWatched() {}
+
+ static _WatcherPath _pathFromPathId(int pathId) {
+ return _idMap[pathId];
+ }
+
+ static Stream _listenOnSocket(int socketId, int id, int pathId) {
var socket = new _RawSocket(new _NativeSocket.watch(socketId));
- _subscription = socket.expand((event) {
- bool stop = false;
+ return socket.expand((event) {
+ var stops = [];
var events = [];
var pair = {};
if (event == RawSocketEvent.READ) {
String getPath(event) {
- var path = _path;
+ var path = _pathFromPathId(event[4]).path;
if (event[2] != null && event[2].isNotEmpty) {
path += Platform.pathSeparator;
path += event[2];
@@ -96,87 +170,190 @@
}
return (event[0] & FileSystemEvent._IS_DIR) != 0;
}
- void add(event) {
- if ((event.type & _events) == 0) return;
- events.add(event);
+ void add(id, event) {
+ if ((event.type & _pathFromPathId(id).events) == 0) return;
+ events.add([id, event]);
}
void rewriteMove(event, isDir) {
if (event[3]) {
- add(new FileSystemCreateEvent._(getPath(event), isDir));
+ add(event[4], new FileSystemCreateEvent._(getPath(event), isDir));
} else {
- add(new FileSystemDeleteEvent._(getPath(event), isDir));
+ add(event[4], new FileSystemDeleteEvent._(getPath(event), isDir));
}
}
while (socket.available() > 0) {
- for (var event in _readEvents()) {
+ for (var event in _readEvents(id, pathId)) {
if (event == null) continue;
+ int pathId = event[4];
bool isDir = getIsDir(event);
var path = getPath(event);
if ((event[0] & FileSystemEvent.CREATE) != 0) {
- add(new FileSystemCreateEvent._(path, isDir));
+ add(event[4], new FileSystemCreateEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent.MODIFY) != 0) {
- add(new FileSystemModifyEvent._(path, isDir, true));
+ add(event[4], new FileSystemModifyEvent._(path, isDir, true));
}
if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
- add(new FileSystemModifyEvent._(path, isDir, false));
+ add(event[4], new FileSystemModifyEvent._(path, isDir, false));
}
if ((event[0] & FileSystemEvent.MOVE) != 0) {
int link = event[1];
if (link > 0) {
- if (pair.containsKey(link)) {
- events.add(new FileSystemMoveEvent._(
- getPath(pair[link]), isDir, path));
- pair.remove(link);
+ pair.putIfAbsent(pathId, () => {});
+ if (pair[pathId].containsKey(link)) {
+ add(event[4],
+ new FileSystemMoveEvent._(
+ getPath(pair[pathId][link]), isDir, path));
+ pair[pathId].remove(link);
} else {
- pair[link] = event;
+ pair[pathId][link] = event;
}
} else {
rewriteMove(event, isDir);
}
}
if ((event[0] & FileSystemEvent.DELETE) != 0) {
- add(new FileSystemDeleteEvent._(path, isDir));
+ add(event[4], new FileSystemDeleteEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
- add(new FileSystemDeleteEvent._(path, isDir));
- stop = true;
+ add(event[4], new FileSystemDeleteEvent._(path, isDir));
+ // Signal done event.
+ stops.add([event[4], null]);
}
}
}
- for (var event in pair.values) {
- rewriteMove(event, getIsDir(event));
+ for (var map in pair.values) {
+ for (var event in map.values) {
+ rewriteMove(event, getIsDir(event));
+ }
}
} else if (event == RawSocketEvent.CLOSED) {
} else if (event == RawSocketEvent.READ_CLOSED) {
} else {
assert(false);
}
- if (stop) socket.close();
+ events.addAll(stops);
return events;
- })
- .listen(_controller.add, onDone: _cancel);
+ });
}
- void _cancel() {
- if (_subscription != null) {
- _unwatchPath();
- _subscription.cancel();
- _subscription = null;
+ /* patch */ static bool get isSupported
+ native "FileSystemWatcher_IsSupported";
+
+ static int _initWatcher() native "FileSystemWatcher_InitWatcher";
+ static void _closeWatcher(int id) native "FileSystemWatcher_CloseWatcher";
+
+ static int _watchPath(int id, String path, int events, bool recursive)
+ native "FileSystemWatcher_WatchPath";
+ static void _unwatchPath(int id, int path_id)
+ native "FileSystemWatcher_UnwatchPath";
+ static List _readEvents(int id, int path_id)
+ native "FileSystemWatcher_ReadEvents";
+ static int _getSocketId(int id, int path_id)
+ native "FileSystemWatcher_GetSocketId";
+}
+
+
+class _InotifyFileSystemWatcher extends _FileSystemWatcher {
+ static final Map<int, StreamController> _idMap = {};
+ static StreamSubscription _subscription;
+
+ _InotifyFileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ void _newWatcher() {
+ int id = _FileSystemWatcher._id;
+ _subscription = _FileSystemWatcher._listenOnSocket(id, id, 0)
+ .listen((event) {
+ if (_idMap.containsKey(event[0])) {
+ if (event[1] != null) {
+ _idMap[event[0]].add(event[1]);
+ } else {
+ _idMap[event[0]].close();
+ }
+ }
+ });
+ }
+
+ void _doneWatcher() {
+ _subscription.cancel();
+ }
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ if (!_idMap.containsKey(pathId)) {
+ _idMap[pathId] = new StreamController.broadcast();
}
+ return _idMap[pathId].stream;
+ }
+
+ void _pathWatchedEnd() {
+ var pathId = _watcherPath.pathId;
+ if (!_idMap.containsKey(pathId)) return;
+ _idMap[pathId].close();
+ _idMap.remove(pathId);
+ }
+}
+
+
+class _Win32FileSystemWatcher extends _FileSystemWatcher {
+ StreamSubscription _subscription;
+ StreamController _controller;
+
+ _Win32FileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ _controller = new StreamController();
+ _subscription = _FileSystemWatcher._listenOnSocket(pathId, 0, pathId)
+ .listen((event) {
+ assert(event[0] == pathId);
+ if (event[1] != null) {
+ _controller.add(event[1]);
+ } else {
+ _controller.close();
+ }
+ });
+ return _controller.stream;
+ }
+
+ void _pathWatchedEnd() {
+ _subscription.cancel();
_controller.close();
}
-
- Stream<FileSystemEvent> get stream => _controller.stream;
-
- static bool get isSupported native "FileSystemWatcher_IsSupported";
-
- int _watchPath(String path, int events, bool recursive)
- native "FileSystemWatcher_WatchPath";
- void _unwatchPath() native "FileSystemWatcher_UnwatchPath";
- List _readEvents() native "FileSystemWatcher_ReadEvents";
}
+
+class _FSEventStreamFileSystemWatcher extends _FileSystemWatcher {
+ StreamSubscription _subscription;
+ StreamController _controller;
+
+ _FSEventStreamFileSystemWatcher(path, events, recursive)
+ : super._(path, events, recursive);
+
+ Stream _pathWatched() {
+ var pathId = _watcherPath.pathId;
+ var socketId = _FileSystemWatcher._getSocketId(0, pathId);
+ _controller = new StreamController();
+ _subscription = _FileSystemWatcher._listenOnSocket(socketId, 0, pathId)
+ .listen((event) {
+ if (event[1] != null) {
+ _controller.add(event[1]);
+ } else {
+ _controller.close();
+ }
+ });
+ return _controller.stream;
+ }
+
+ void _pathWatchedEnd() {
+ _subscription.cancel();
+ _controller.close();
+ }
+}
+
+
Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) {
return new Uint8List.view(source.buffer, offsetInBytes, length);
}
diff --git a/runtime/bin/file_system_watcher.cc b/runtime/bin/file_system_watcher.cc
index 7893ffb..0260be7 100644
--- a/runtime/bin/file_system_watcher.cc
+++ b/runtime/bin/file_system_watcher.cc
@@ -12,54 +12,57 @@
namespace dart {
namespace bin {
-static const int kWatcherNativeField = 0;
-
-
-void SetWatcherIdNativeField(Dart_Handle watcher, intptr_t id) {
- ThrowIfError(Dart_SetNativeInstanceField(watcher, kWatcherNativeField, id));
-}
-
-
-void GetWatcherIdNativeField(Dart_Handle watcher, intptr_t* id) {
- ThrowIfError(Dart_GetNativeInstanceField(watcher, kWatcherNativeField, id));
-}
-
void FUNCTION_NAME(FileSystemWatcher_IsSupported)(Dart_NativeArguments args) {
Dart_SetReturnValue(args, Dart_NewBoolean(FileSystemWatcher::IsSupported()));
}
+
+void FUNCTION_NAME(FileSystemWatcher_InitWatcher)(Dart_NativeArguments args) {
+ Dart_SetReturnValue(args, Dart_NewInteger(FileSystemWatcher::Init()));
+}
+
+
+void FUNCTION_NAME(FileSystemWatcher_CloseWatcher)(Dart_NativeArguments args) {
+ intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ FileSystemWatcher::Close(id);
+}
+
+
void FUNCTION_NAME(FileSystemWatcher_WatchPath)(Dart_NativeArguments args) {
- Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
+ intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
const char* path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
int events = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
bool recursive = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
- intptr_t id = FileSystemWatcher::WatchPath(path, events, recursive);
- if (id == -1) {
+ intptr_t path_id = FileSystemWatcher::WatchPath(id, path, events, recursive);
+ if (path_id == -1) {
Dart_ThrowException(DartUtils::NewDartOSError());
- } else {
- SetWatcherIdNativeField(watcher, id);
}
- intptr_t socket_id = FileSystemWatcher::GetSocketId(id);
- Dart_SetReturnValue(args, Dart_NewInteger(socket_id));
+ Dart_SetReturnValue(args, Dart_NewInteger(path_id));
}
void FUNCTION_NAME(FileSystemWatcher_UnwatchPath)(Dart_NativeArguments args) {
- Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
- intptr_t id;
- GetWatcherIdNativeField(watcher, &id);
- FileSystemWatcher::UnwatchPath(id);
+ intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+ FileSystemWatcher::UnwatchPath(id, path_id);
}
void FUNCTION_NAME(FileSystemWatcher_ReadEvents)(Dart_NativeArguments args) {
- Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
- intptr_t id;
- GetWatcherIdNativeField(watcher, &id);
- Dart_Handle handle = FileSystemWatcher::ReadEvents(id);
+ intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+ Dart_Handle handle = FileSystemWatcher::ReadEvents(id, path_id);
ThrowIfError(handle);
Dart_SetReturnValue(args, handle);
}
+
+void FUNCTION_NAME(FileSystemWatcher_GetSocketId)(Dart_NativeArguments args) {
+ intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+ int socket_id = FileSystemWatcher::GetSocketId(id, path_id);
+ Dart_SetReturnValue(args, Dart_NewInteger(socket_id));
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/file_system_watcher.h b/runtime/bin/file_system_watcher.h
index 21c334f..6a6164a 100644
--- a/runtime/bin/file_system_watcher.h
+++ b/runtime/bin/file_system_watcher.h
@@ -37,10 +37,15 @@
};
static bool IsSupported();
- static intptr_t WatchPath(const char* path, int events, bool recursive);
- static void UnwatchPath(intptr_t id);
- static intptr_t GetSocketId(intptr_t id);
- static Dart_Handle ReadEvents(intptr_t id);
+ static intptr_t Init();
+ static void Close(intptr_t id);
+ static intptr_t WatchPath(intptr_t id,
+ const char* path,
+ int events,
+ bool recursive);
+ static void UnwatchPath(intptr_t id, intptr_t path_id);
+ static intptr_t GetSocketId(intptr_t id, intptr_t path_id);
+ static Dart_Handle ReadEvents(intptr_t id, intptr_t path_id);
private:
DISALLOW_COPY_AND_ASSIGN(FileSystemWatcher);
diff --git a/runtime/bin/file_system_watcher_android.cc b/runtime/bin/file_system_watcher_android.cc
index 5971ed0..96fd325 100644
--- a/runtime/bin/file_system_watcher_android.cc
+++ b/runtime/bin/file_system_watcher_android.cc
@@ -21,42 +21,54 @@
}
-intptr_t FileSystemWatcher::WatchPath(const char* path,
- int events,
- bool recursive) {
- int fd = TEMP_FAILURE_RETRY(inotify_init());
- if (fd < 0 || !FDUtils::SetCloseOnExec(fd)) {
+intptr_t FileSystemWatcher::Init() {
+ int id = TEMP_FAILURE_RETRY(inotify_init());
+ if (id < 0 || !FDUtils::SetCloseOnExec(id)) {
return -1;
}
// Some systems dosn't support setting this as non-blocking. Since watching
// internals are kept away from the user, we know it's possible to continue,
// even if setting non-blocking fails.
- FDUtils::SetNonBlocking(fd);
- int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
- if (events & kCreate) list_events |= IN_CREATE;
- if (events & kModifyContent) list_events |= IN_MODIFY | IN_ATTRIB;
- if (events & kDelete) list_events |= IN_DELETE;
- if (events & kMove) list_events |= IN_MOVE;
- int path_fd = TEMP_FAILURE_RETRY(inotify_add_watch(fd, path, list_events));
- if (path_fd < 0) {
- close(fd);
- return -1;
- }
- return fd;
-}
-
-
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
- // Nothing to do.
-}
-
-
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
+ FDUtils::SetNonBlocking(id);
return id;
}
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+void FileSystemWatcher::Close(intptr_t id) {
+ USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+ const char* path,
+ int events,
+ bool recursive) {
+ int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
+ if (events & kCreate) list_events |= IN_CREATE;
+ if (events & kModifyContent) list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
+ if (events & kDelete) list_events |= IN_DELETE;
+ if (events & kMove) list_events |= IN_MOVE;
+ int path_id = TEMP_FAILURE_RETRY(inotify_add_watch(id, path, list_events));
+ if (path_id < 0) {
+ return -1;
+ }
+ return path_id;
+}
+
+
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+ VOID_TEMP_FAILURE_RETRY(inotify_rm_watch(id, path_id));
+}
+
+
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+ USE(path_id);
+ return id;
+}
+
+
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+ USE(path_id);
const intptr_t kEventSize = sizeof(struct inotify_event);
const intptr_t kBufferSize = kEventSize + NAME_MAX + 1;
uint8_t buffer[kBufferSize];
@@ -64,33 +76,36 @@
if (bytes < 0) {
return DartUtils::NewDartOSError();
}
- const intptr_t kMaxCount = kBufferSize / kEventSize + 1;
+ const intptr_t kMaxCount = bytes / kEventSize;
Dart_Handle events = Dart_NewList(kMaxCount);
intptr_t offset = 0;
intptr_t i = 0;
while (offset < bytes) {
struct inotify_event* e =
reinterpret_cast<struct inotify_event*>(buffer + offset);
- Dart_Handle event = Dart_NewList(4);
- int mask = 0;
- if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
- if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
- if (e->mask & IN_CREATE) mask |= kCreate;
- if (e->mask & IN_MOVE) mask |= kMove;
- if (e->mask & IN_DELETE) mask |= kDelete;
- if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
- if (e->mask & IN_ISDIR) mask |= kIsDir;
- Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
- Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
- if (e->len > 0) {
- Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
- reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
- } else {
- Dart_ListSetAt(event, 2, Dart_Null());
+ if ((e->mask & IN_IGNORED) == 0) {;
+ Dart_Handle event = Dart_NewList(5);
+ int mask = 0;
+ if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
+ if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
+ if (e->mask & IN_CREATE) mask |= kCreate;
+ if (e->mask & IN_MOVE) mask |= kMove;
+ if (e->mask & IN_DELETE) mask |= kDelete;
+ if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
+ if (e->mask & IN_ISDIR) mask |= kIsDir;
+ Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
+ Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
+ if (e->len > 0) {
+ Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
+ reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
+ } else {
+ Dart_ListSetAt(event, 2, Dart_Null());
+ }
+ Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+ Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
+ Dart_ListSetAt(events, i, event);
+ i++;
}
- Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
- Dart_ListSetAt(events, i, event);
- i++;
offset += kEventSize + e->len;
}
ASSERT(offset == bytes);
diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc
index 4e57446..8706702 100644
--- a/runtime/bin/file_system_watcher_linux.cc
+++ b/runtime/bin/file_system_watcher_linux.cc
@@ -21,40 +21,52 @@
}
-intptr_t FileSystemWatcher::WatchPath(const char* path,
- int events,
- bool recursive) {
- int fd = TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
- if (fd < 0) return -1;
+intptr_t FileSystemWatcher::Init() {
+ int id = TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
+ if (id < 0) return -1;
// Some systems dosn't support setting this as non-blocking. Since watching
// internals are kept away from the user, we know it's possible to continue,
// even if setting non-blocking fails.
- FDUtils::SetNonBlocking(fd);
+ FDUtils::SetNonBlocking(id);
+ return id;
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+ USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+ const char* path,
+ int events,
+ bool recursive) {
int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
if (events & kCreate) list_events |= IN_CREATE;
if (events & kModifyContent) list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
if (events & kDelete) list_events |= IN_DELETE;
if (events & kMove) list_events |= IN_MOVE;
- int path_fd = TEMP_FAILURE_RETRY(inotify_add_watch(fd, path, list_events));
- if (path_fd < 0) {
- close(fd);
+ int path_id = TEMP_FAILURE_RETRY(inotify_add_watch(id, path, list_events));
+ if (path_id < 0) {
return -1;
}
- return fd;
+ return path_id;
}
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
- // Nothing to do.
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+ VOID_TEMP_FAILURE_RETRY(inotify_rm_watch(id, path_id));
}
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+ USE(path_id);
return id;
}
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+ USE(path_id);
const intptr_t kEventSize = sizeof(struct inotify_event);
const intptr_t kBufferSize = kEventSize + NAME_MAX + 1;
uint8_t buffer[kBufferSize];
@@ -69,26 +81,29 @@
while (offset < bytes) {
struct inotify_event* e =
reinterpret_cast<struct inotify_event*>(buffer + offset);
- Dart_Handle event = Dart_NewList(4);
- int mask = 0;
- if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
- if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
- if (e->mask & IN_CREATE) mask |= kCreate;
- if (e->mask & IN_MOVE) mask |= kMove;
- if (e->mask & IN_DELETE) mask |= kDelete;
- if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
- if (e->mask & IN_ISDIR) mask |= kIsDir;
- Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
- Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
- if (e->len > 0) {
- Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
- reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
- } else {
- Dart_ListSetAt(event, 2, Dart_Null());
+ if ((e->mask & IN_IGNORED) == 0) {;
+ Dart_Handle event = Dart_NewList(5);
+ int mask = 0;
+ if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
+ if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
+ if (e->mask & IN_CREATE) mask |= kCreate;
+ if (e->mask & IN_MOVE) mask |= kMove;
+ if (e->mask & IN_DELETE) mask |= kDelete;
+ if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
+ if (e->mask & IN_ISDIR) mask |= kIsDir;
+ Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
+ Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
+ if (e->len > 0) {
+ Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
+ reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
+ } else {
+ Dart_ListSetAt(event, 2, Dart_Null());
+ }
+ Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+ Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
+ Dart_ListSetAt(events, i, event);
+ i++;
}
- Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
- Dart_ListSetAt(events, i, event);
- i++;
offset += kEventSize + e->len;
}
ASSERT(offset == bytes);
diff --git a/runtime/bin/file_system_watcher_macos.cc b/runtime/bin/file_system_watcher_macos.cc
index 2200b78..c524e36 100644
--- a/runtime/bin/file_system_watcher_macos.cc
+++ b/runtime/bin/file_system_watcher_macos.cc
@@ -42,12 +42,6 @@
namespace dart {
namespace bin {
-static Mutex* watcher_mutex = new Mutex();
-static Monitor* watcher_monitor = new Monitor();
-
-class FSEventsWatcher;
-static FSEventsWatcher* watcher = NULL;
-
union FSEvent {
struct {
uint32_t exists;
@@ -99,7 +93,7 @@
FSEventStreamRef ref_;
};
- FSEventsWatcher() : run_loop_(0), users_(0) {
+ FSEventsWatcher() : run_loop_(0) {
Thread::Start(Run, reinterpret_cast<uword>(this));
}
@@ -107,6 +101,10 @@
CFRunLoopStop(run_loop_);
}
+ Monitor& monitor() { return monitor_; }
+
+ bool has_run_loop() const { return run_loop_ != NULL; }
+
static void TimerCallback(CFRunLoopTimerRef timer, void* context) {
// Dummy callback to keep RunLoop alive.
}
@@ -116,9 +114,9 @@
watcher->run_loop_ = CFRunLoopGetCurrent();
// Notify, as the run-loop is set.
- watcher_monitor->Enter();
- watcher_monitor->Notify();
- watcher_monitor->Exit();
+ watcher->monitor().Enter();
+ watcher->monitor().Notify();
+ watcher->monitor().Exit();
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
NULL,
@@ -134,27 +132,6 @@
CFRunLoopRun();
}
- static void Increment() {
- if (watcher == NULL) {
- watcher_monitor->Enter();
- watcher = new FSEventsWatcher();
- while (watcher->run_loop_ == NULL) {
- watcher_monitor->Wait(Monitor::kNoTimeout);
- }
- watcher_monitor->Exit();
- }
- watcher->users_++;
- }
-
- static void Decrement() {
- ASSERT(watcher->users_ > 0);
- watcher->users_--;
- if (watcher->users_ == 0) {
- delete watcher;
- watcher = NULL;
- }
- }
-
Node* AddPath(const char* path, int events, bool recursive) {
int fds[2];
VOID_TEMP_FAILURE_RETRY(pipe(fds));
@@ -215,8 +192,8 @@
}
}
+ Monitor monitor_;
CFRunLoopRef run_loop_;
- int users_;
};
@@ -226,36 +203,50 @@
}
-intptr_t FileSystemWatcher::WatchPath(const char* path,
+intptr_t FileSystemWatcher::Init() {
+ FSEventsWatcher* watcher = new FSEventsWatcher();
+ watcher->monitor().Enter();
+ while (!watcher->has_run_loop()) {
+ watcher->monitor().Wait(1);
+ }
+ watcher->monitor().Exit();
+ return reinterpret_cast<intptr_t>(watcher);
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+ FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id);
+ delete watcher;
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+ const char* path,
int events,
bool recursive) {
- MutexLocker lock(watcher_mutex);
- FSEventsWatcher::Increment();
-
+ FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id);
FSEventsWatcher::Node* node = watcher->AddPath(path, events, recursive);
node->Start();
return reinterpret_cast<intptr_t>(node);
}
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
- MutexLocker lock(watcher_mutex);
-
- FSEventsWatcher::Node* node = reinterpret_cast<FSEventsWatcher::Node*>(id);
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+ USE(id);
+ FSEventsWatcher::Node* node =
+ reinterpret_cast<FSEventsWatcher::Node*>(path_id);
node->Stop();
delete node;
-
- FSEventsWatcher::Decrement();
}
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
- return reinterpret_cast<FSEventsWatcher::Node*>(id)->read_fd();
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+ return reinterpret_cast<FSEventsWatcher::Node*>(path_id)->read_fd();
}
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
- intptr_t fd = GetSocketId(id);
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+ intptr_t fd = GetSocketId(id, path_id);
intptr_t avail = FDUtils::AvailableBytes(fd);
int count = avail / sizeof(FSEvent);
if (count <= 0) return Dart_NewList(0);
@@ -267,7 +258,7 @@
return DartUtils::NewDartOSError();
}
size_t path_len = strlen(e.data.path);
- Dart_Handle event = Dart_NewList(4);
+ Dart_Handle event = Dart_NewList(5);
int flags = e.data.flags;
int mask = 0;
if (flags & kFSEventStreamEventFlagItemRenamed) {
@@ -295,6 +286,7 @@
Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
reinterpret_cast<uint8_t*>(e.data.path), path_len));
Dart_ListSetAt(event, 3, Dart_NewBoolean(true));
+ Dart_ListSetAt(event, 4, Dart_NewInteger(path_id));
Dart_ListSetAt(events, i, event);
}
return events;
diff --git a/runtime/bin/file_system_watcher_win.cc b/runtime/bin/file_system_watcher_win.cc
index 9731009..adb2426 100644
--- a/runtime/bin/file_system_watcher_win.cc
+++ b/runtime/bin/file_system_watcher_win.cc
@@ -23,9 +23,21 @@
}
-intptr_t FileSystemWatcher::WatchPath(const char* path,
+intptr_t FileSystemWatcher::Init() {
+ return 0;
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+ USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+ const char* path,
int events,
bool recursive) {
+ USE(id);
const wchar_t* name = StringUtils::Utf8ToWide(path);
HANDLE dir = CreateFileW(name,
FILE_LIST_DIRECTORY,
@@ -59,19 +71,22 @@
}
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
- // Nothing to do.
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+ USE(id);
+ USE(path_id);
}
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
- return id;
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+ USE(id);
+ return path_id;
}
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+ USE(id);
const intptr_t kEventSize = sizeof(FILE_NOTIFY_INFORMATION);
- DirectoryWatchHandle* dir = reinterpret_cast<DirectoryWatchHandle*>(id);
+ DirectoryWatchHandle* dir = reinterpret_cast<DirectoryWatchHandle*>(path_id);
intptr_t available = dir->Available();
intptr_t max_count = available / kEventSize + 1;
Dart_Handle events = Dart_NewList(max_count);
@@ -83,7 +98,7 @@
FILE_NOTIFY_INFORMATION* e =
reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer + offset);
- Dart_Handle event = Dart_NewList(4);
+ Dart_Handle event = Dart_NewList(5);
int mask = 0;
if (e->Action == FILE_ACTION_ADDED) mask |= kCreate;
if (e->Action == FILE_ACTION_REMOVED) mask |= kDelete;
@@ -96,6 +111,7 @@
Dart_ListSetAt(event, 2, Dart_NewStringFromUTF16(
reinterpret_cast<uint16_t*>(e->FileName), e->FileNameLength / 2));
Dart_ListSetAt(event, 3, Dart_NewBoolean(true));
+ Dart_ListSetAt(event, 4, Dart_NewInteger(path_id));
Dart_ListSetAt(events, i, event);
i++;
if (e->NextEntryOffset == 0) break;
diff --git a/runtime/bin/resources.h b/runtime/bin/resources.h
index 6ee066a..02cc967 100644
--- a/runtime/bin/resources.h
+++ b/runtime/bin/resources.h
@@ -8,6 +8,11 @@
#include <stddef.h>
#include <string.h>
+// Map from Blink to Dart VM.
+#if defined(_DEBUG)
+#define DEBUG
+#endif
+
#include "platform/assert.h"
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 0a2547c..6fa0a99 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -585,13 +585,38 @@
ThrowPRException("TlsException",
"Failed NSS_SetDomesticPolicy call.");
}
- // Enable TLS, as well as SSL3 and SSL2.
- status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
- if (status != SECSuccess) {
- mutex_->Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("TlsException",
- "Failed SSL_OptionSetDefault enable TLS call.");
+
+ // Enable the same additional ciphers that Chromium does.
+ // See NSSSSLInitSingleton() in Chromium's net/socket/nss_ssl_util.cc.
+ // Explicitly enable exactly those ciphers with keys of at least 80 bits.
+ const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers();
+ const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers();
+ for (int i = 0; i < num_ciphers; i++) {
+ SSLCipherSuiteInfo info;
+ if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) ==
+ SECSuccess) {
+ bool enabled = (info.effectiveKeyBits >= 80);
+ // Trim the list of cipher suites in order to keep the size of the
+ // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and
+ // HMAC-SHA256 cipher suites are disabled.
+ if (info.symCipher == ssl_calg_camellia ||
+ info.symCipher == ssl_calg_seed ||
+ (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) ||
+ info.authAlgorithm == ssl_auth_dsa ||
+ info.macAlgorithm == ssl_hmac_sha256 ||
+ info.nonStandard ||
+ strcmp(info.keaTypeName, "ECDH") == 0) {
+ enabled = false;
+ }
+
+ if (ssl_ciphers[i] == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) {
+ // Enabled to allow servers with only a DSA certificate to function.
+ enabled = true;
+ }
+ SSL_CipherPrefSetDefault(ssl_ciphers[i], enabled);
+ }
}
+
status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
if (status != SECSuccess) {
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
@@ -658,7 +683,7 @@
SSLVersionRange vrange;
vrange.min = SSL_LIBRARY_VERSION_3_0;
- vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+ vrange.max = SSL_LIBRARY_VERSION_TLS_1_2;
SSL_VersionRangeSet(filter_, &vrange);
SECStatus status;
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 175d07e..046bd18 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -427,7 +427,7 @@
for (intptr_t i = 0; i < addresses->count(); i++) {
InterfaceSocketAddress* interface = addresses->GetAt(i);
SocketAddress* addr = interface->socket_address();
- CObjectArray* entry = new CObjectArray(CObject::NewArray(4));
+ CObjectArray* entry = new CObjectArray(CObject::NewArray(5));
CObjectInt32* type = new CObjectInt32(
CObject::NewInt32(addr->GetType()));
@@ -449,6 +449,10 @@
interface->interface_name()));
entry->SetAt(3, interface_name);
+ CObjectInt64* interface_index = new CObjectInt64(CObject::NewInt64(
+ interface->interface_index()));
+ entry->SetAt(4, interface_index);
+
array->SetAt(i + 1, entry);
}
result = array;
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 1bec3e6..d4ae826 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -110,9 +110,11 @@
class InterfaceSocketAddress {
public:
explicit InterfaceSocketAddress(struct sockaddr* sa,
- const char* interface_name)
+ const char* interface_name,
+ intptr_t interface_index)
: socket_address_(new SocketAddress(sa)),
- interface_name_(interface_name) {}
+ interface_name_(interface_name),
+ interface_index_(interface_index) {}
~InterfaceSocketAddress() {
delete socket_address_;
@@ -121,10 +123,12 @@
SocketAddress* socket_address() const { return socket_address_; }
const char* interface_name() const { return interface_name_; }
+ int interface_index() const { return interface_index_; }
private:
SocketAddress* socket_address_;
const char* interface_name_;
+ intptr_t interface_index_;
DISALLOW_COPY_AND_ASSIGN(InterfaceSocketAddress);
};
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index c36a66e..e50884b 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -11,6 +11,7 @@
#include <string.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
+#include <net/if.h> // NOLINT
#include <netinet/tcp.h> // NOLINT
#include <ifaddrs.h> // NOLINT
@@ -298,7 +299,7 @@
for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
addresses->SetAt(i, new InterfaceSocketAddress(
- ifa->ifa_addr, strdup(ifa->ifa_name)));
+ ifa->ifa_addr, strdup(ifa->ifa_name), if_nametoindex(ifa->ifa_name)));
i++;
}
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 6568379..b8eef1d 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -11,6 +11,7 @@
#include <string.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
+#include <net/if.h> // NOLINT
#include <netinet/tcp.h> // NOLINT
#include <ifaddrs.h> // NOLINT
@@ -298,7 +299,7 @@
for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
addresses->SetAt(i, new InterfaceSocketAddress(
- ifa->ifa_addr, strdup(ifa->ifa_name)));
+ ifa->ifa_addr, strdup(ifa->ifa_name), if_nametoindex(ifa->ifa_name)));
i++;
}
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 1480f1f..d313a0d 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -197,9 +197,10 @@
class _NetworkInterface implements NetworkInterface {
final String name;
- final List<InternetAddress> addresses;
+ final int index;
+ final List<InternetAddress> addresses = [];
- _NetworkInterface(String this.name, List<InternetAddress> this.addresses);
+ _NetworkInterface(this.name, this.index);
String toString() {
return "NetworkInterface('$name', $addresses)";
@@ -305,23 +306,21 @@
if (isErrorResponse(response)) {
throw createError(response, "Failed listing interfaces");
} else {
- var list = new List<NetworkInterface>();
var map = response.skip(1)
- .fold(new Map<String, List<InternetAddress>>(), (map, result) {
+ .fold(new Map<String, NetworkInterface>(), (map, result) {
var type = new InternetAddressType._from(result[0]);
var name = result[3];
+ var index = result[4];
var address = new _InternetAddress(
type, result[1], "", result[2]);
if (!includeLinkLocal && address.isLinkLocal) return map;
if (!includeLoopback && address.isLoopback) return map;
- map.putIfAbsent(name, () => new List<InternetAddress>());
- map[name].add(address);
+ map.putIfAbsent(
+ name, () => new _NetworkInterface(name, index));
+ map[name].addresses.add(address);
return map;
- })
- .forEach((name, addresses) {
- list.add(new _NetworkInterface(name, addresses));
});
- return list;
+ return map.values.toList();
}
});
}
@@ -465,7 +464,7 @@
var result =
nativeWrite(bufferAndStart.buffer, bufferAndStart.start, bytes);
if (result is OSError) {
- reportError(result, "Write failed");
+ scheduleMicrotask(() => reportError(result, "Write failed"));
result = 0;
}
return result;
@@ -501,6 +500,7 @@
canActivateEvents = false;
for (int i = FIRST_EVENT; i <= LAST_EVENT; i++) {
if (((events & (1 << i)) != 0)) {
+ if ((i == CLOSED_EVENT || i == READ_EVENT) && isClosedRead) continue;
if (i == CLOSED_EVENT &&
typeFlags != TYPE_LISTENING_SOCKET &&
!isClosing &&
@@ -737,6 +737,7 @@
}
_RawServerSocket(this._socket) {
+ var zone = Zone.current;
_controller = new StreamController(sync: true,
onListen: _onSubscriptionStateChange,
onCancel: _onSubscriptionStateChange,
@@ -744,14 +745,14 @@
onResume: _onPauseStateChange);
_socket.closeFuture.then((_) => _controller.close());
_socket.setHandlers(
- read: () {
+ read: zone.bindCallback(() {
var socket = _socket.accept();
if (socket != null) _controller.add(new _RawSocket(socket));
- },
- error: (e) {
+ }),
+ error: zone.bindUnaryCallback((e) {
_controller.addError(e);
_controller.close();
- }
+ })
);
}
@@ -814,6 +815,7 @@
}
_RawSocket(this._socket) {
+ var zone = Zone.current;
_controller = new StreamController(sync: true,
onListen: _onSubscriptionStateChange,
onCancel: _onSubscriptionStateChange,
@@ -830,10 +832,10 @@
},
closed: () => _controller.add(RawSocketEvent.READ_CLOSED),
destroyed: () => _controller.add(RawSocketEvent.CLOSED),
- error: (e) {
+ error: zone.bindUnaryCallback((e) {
_controller.addError(e);
close();
- }
+ })
);
}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index d8cd9f9..7610a73 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -329,7 +329,8 @@
u != NULL; u = u->Next) {
addresses->SetAt(i, new InterfaceSocketAddress(
u->Address.lpSockaddr,
- StringUtils::WideToUtf8(a->FriendlyName)));
+ StringUtils::WideToUtf8(a->FriendlyName),
+ a->Ipv6IfIndex));
i++;
}
}
diff --git a/runtime/bin/vmservice/vmservice_dartium.dart b/runtime/bin/vmservice/vmservice_dartium.dart
new file mode 100644
index 0000000..c1520ec
--- /dev/null
+++ b/runtime/bin/vmservice/vmservice_dartium.dart
@@ -0,0 +1,60 @@
+// 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 vmservice_dartium;
+
+import 'dart:isolate';
+import 'vmservice.dart';
+
+// The receive port that isolate startup / shutdown messages are delivered on.
+RawReceivePort _receivePort;
+// The receive port that service request messages are delivered on.
+RawReceivePort _requestPort;
+
+// The native method that is called to post the response back to DevTools.
+void postResponse(String response, int cookie) native "PostResponse";
+
+void handleRequest(service, String uri, cookie) {
+ var serviceRequest = new ServiceRequest();
+ var r = serviceRequest.parse(Uri.parse(uri));
+ if (!r) {
+ // Did not understand the request uri.
+ serviceRequest.setErrorResponse('Invalid request uri: ${uri}');
+ } else {
+ var f = service.runningIsolates.route(serviceRequest);
+ if (f != null) {
+ f.then((_) {
+ postResponse(serviceRequest.response, cookie);
+ }).catchError((e) { });
+ return;
+ } else {
+ // Nothing responds to this type of request.
+ serviceRequest.setErrorResponse('No route for: $uri');
+ }
+ }
+ postResponse(serviceRequest.response, cookie);
+}
+
+main() {
+ // Create VmService.
+ var service = new VMService();
+ _receivePort = service.receivePort;
+ _requestPort = new RawReceivePort((message) {
+ if (message == null) {
+ return;
+ }
+ if (message is! List) {
+ return;
+ }
+ if (message.length != 2) {
+ return;
+ }
+ var uri = message[0];
+ if (uri is! String) {
+ return;
+ }
+ var cookie = message[1];
+ handleRequest(service, uri, cookie);
+ });
+}
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 46e4f40..3792a5b 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -57,6 +57,24 @@
StreamController _controller;
}
+typedef void ImmediateCallback();
+
+/// The callback that has been registered through `scheduleImmediate`.
+ImmediateCallback _pendingImmediateCallback;
+
+/// The closure that should be used as scheduleImmediateClosure, when the VM
+/// is responsible for the event loop.
+void _isolateScheduleImmediate(void callback()) {
+ assert(_pendingImmediateCallback == null);
+ _pendingImmediateCallback = callback;
+}
+
+/// The embedder can execute this function to get hold of
+/// [_isolateScheduleImmediate] above.
+Function _getIsolateScheduleImmediateClosure() {
+ return _isolateScheduleImmediate;
+}
+
class _RawReceivePortImpl implements RawReceivePort {
factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
@@ -92,7 +110,15 @@
static void _handleMessage(
_RawReceivePortImpl port, int replyId, var message) {
assert(port != null);
+ // TODO(floitsch): this relies on the fact that any exception aborts the
+ // VM. Once we have non-fatal global exceptions we need to catch errors
+ // so that we can run the immediate callbacks.
port._handler(message);
+ if (_pendingImmediateCallback != null) {
+ var callback = _pendingImmediateCallback;
+ _pendingImmediateCallback = null;
+ callback();
+ }
}
// Call into the VM to close the VM maintained mappings.
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 8476c15..ec24d3e 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -248,7 +248,7 @@
Function operator [](Symbol selector) {
bool found = false;
for (ClassMirror c = type; c != null; c = c.superclass) {
- var target = c.methods[selector];
+ var target = c._methods[selector];
if (target != null && !target.isStatic && target.isRegularMethod) {
found = true;
break;
@@ -337,14 +337,6 @@
return reflect(_apply(arguments, names));
}
- Future<InstanceMirror> applyAsync(List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
- return new Future(() {
- return this.apply(_unwrapAsyncPositionals(positionalArguments),
- _unwrapAsyncNamed(namedArguments));
- });
- }
-
InstanceMirror findInContext(Symbol name, {ifAbsent: null}) {
List<String> parts = _n(name).split(".").toList(growable: false);
if (parts.length > 3) {
@@ -504,71 +496,41 @@
Map<Symbol, DeclarationMirror> get declarations {
if (_declarations != null) return _declarations;
var decls = new Map<Symbol, DeclarationMirror>();
- decls.addAll(members);
- decls.addAll(constructors);
+ decls.addAll(_members);
+ decls.addAll(_constructors);
typeVariables.forEach((tv) => decls[tv.simpleName] = tv);
return _declarations =
new _UnmodifiableMapView<Symbol, DeclarationMirror>(decls);
}
- Map<Symbol, Mirror> _members;
- Map<Symbol, Mirror> get members {
- if (_members == null) {
+ Map<Symbol, Mirror> _cachedMembers;
+ Map<Symbol, Mirror> get _members {
+ if (_cachedMembers == null) {
var whoseMembers = _isMixinAlias ? _trueSuperclass : this;
- _members = _makeMemberMap(mixin._computeMembers(whoseMembers._reflectee));
+ _cachedMembers = _makeMemberMap(mixin._computeMembers(whoseMembers._reflectee));
}
- return _members;
+ return _cachedMembers;
}
- Map<Symbol, MethodMirror> _methods;
- Map<Symbol, MethodMirror> get methods {
- if (_methods == null) {
- _methods = _filterMap(
- members,
+ Map<Symbol, MethodMirror> _cachedMethods;
+ Map<Symbol, MethodMirror> get _methods {
+ if (_cachedMethods == null) {
+ _cachedMethods = _filterMap(
+ _members,
(key, value) => (value is MethodMirror && value.isRegularMethod));
}
- return _methods;
+ return _cachedMethods;
}
- Map<Symbol, MethodMirror> _getters;
- Map<Symbol, MethodMirror> get getters {
- if (_getters == null) {
- _getters = _filterMap(
- members,
- (key, value) => (value is MethodMirror && value.isGetter));
- }
- return _getters;
- }
-
- Map<Symbol, MethodMirror> _setters;
- Map<Symbol, MethodMirror> get setters {
- if (_setters == null) {
- _setters = _filterMap(
- members,
- (key, value) => (value is MethodMirror && value.isSetter));
- }
- return _setters;
- }
-
- Map<Symbol, VariableMirror> _variables;
- Map<Symbol, VariableMirror> get variables {
- if (_variables == null) {
- _variables = _filterMap(
- members,
- (key, value) => (value is VariableMirror));
- }
- return _variables;
- }
-
- Map<Symbol, MethodMirror> _constructors;
- Map<Symbol, MethodMirror> get constructors {
- if (_constructors == null) {
+ Map<Symbol, MethodMirror> _cachedConstructors;
+ Map<Symbol, MethodMirror> get _constructors {
+ if (_cachedConstructors == null) {
var constructorsList = _computeConstructors(_reflectee);
var stringName = _n(simpleName);
constructorsList.forEach((c) => c._patchConstructorName(stringName));
- _constructors = _makeMemberMap(constructorsList);
+ _cachedConstructors = _makeMemberMap(constructorsList);
}
- return _constructors;
+ return _cachedConstructors;
}
bool get _isAnonymousMixinApplication {
@@ -622,7 +584,7 @@
String toString() => "ClassMirror on '${MirrorSystem.getName(simpleName)}'";
Function operator [](Symbol selector) {
- var target = methods[selector];
+ var target = _methods[selector];
if (target == null || !target.isStatic || !target.isRegularMethod) {
throw new ArgumentError(
"${MirrorSystem.getName(simpleName)} has no static method "
@@ -658,16 +620,6 @@
names));
}
- Future<InstanceMirror> newInstanceAsync(Symbol constructorName,
- List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
- return new Future(() {
- return this.newInstance(constructorName,
- _unwrapAsyncPositionals(positionalArguments),
- _unwrapAsyncNamed(namedArguments));
- });
- }
-
List<InstanceMirror> get metadata {
// Get the metadata objects, convert them into InstanceMirrors using
// reflect() and then make them into a Dart list.
@@ -996,64 +948,23 @@
Map<Symbol, DeclarationMirror> get declarations {
if (_declarations != null) return _declarations;
return _declarations =
- new _UnmodifiableMapView<Symbol, DeclarationMirror>(members);
+ new _UnmodifiableMapView<Symbol, DeclarationMirror>(_members);
}
- Map<Symbol, Mirror> _members;
- Map<Symbol, Mirror> get members {
- if (_members == null) {
- _members = _makeMemberMap(_computeMembers(_reflectee));
+ Map<Symbol, Mirror> _cachedMembers;
+ Map<Symbol, Mirror> get _members {
+ if (_cachedMembers == null) {
+ _cachedMembers = _makeMemberMap(_computeMembers(_reflectee));
}
- return _members;
+ return _cachedMembers;
}
- Map<Symbol, ClassMirror> _types;
- Map<Symbol, TypeMirror> get types {
- if (_types == null) {
- _types = _filterMap(members, (key, value) => (value is TypeMirror));
+ Map<Symbol, MethodMirror> _cachedFunctions;
+ Map<Symbol, MethodMirror> get _functions {
+ if (_cachedFunctions == null) {
+ _cachedFunctions = _filterMap(_members, (key, value) => (value is MethodMirror));
}
- return _types;
- }
-
- Map<Symbol, ClassMirror> _classes;
- Map<Symbol, ClassMirror> get classes {
- if (_classes == null) {
- _classes = _filterMap(members, (key, value) => (value is ClassMirror));
- }
- return _classes;
- }
-
- Map<Symbol, MethodMirror> _functions;
- Map<Symbol, MethodMirror> get functions {
- if (_functions == null) {
- _functions = _filterMap(members, (key, value) => (value is MethodMirror));
- }
- return _functions;
- }
-
- Map<Symbol, MethodMirror> _getters;
- Map<Symbol, MethodMirror> get getters {
- if (_getters == null) {
- _getters = _filterMap(functions, (key, value) => (value.isGetter));
- }
- return _getters;
- }
-
- Map<Symbol, MethodMirror> _setters;
- Map<Symbol, MethodMirror> get setters {
- if (_setters == null) {
- _setters = _filterMap(functions, (key, value) => (value.isSetter));
- }
- return _setters;
- }
-
- Map<Symbol, VariableMirror> _variables;
- Map<Symbol, VariableMirror> get variables {
- if (_variables == null) {
- _variables = _filterMap(members,
- (key, value) => (value is VariableMirror));
- }
- return _variables;
+ return _cachedFunctions;
}
List<InstanceMirror> get metadata {
@@ -1072,7 +983,7 @@
String toString() => "LibraryMirror on '${_n(simpleName)}'";
Function operator [](Symbol selector) {
- var target = functions[selector];
+ var target = _functions[selector];
if (target == null || !target.isRegularMethod) {
throw new ArgumentError(
"${MirrorSystem.getName(simpleName)} has no top-level method "
diff --git a/runtime/lib/schedule_microtask_patch.dart b/runtime/lib/schedule_microtask_patch.dart
index 75e87c8..f08de2b 100644
--- a/runtime/lib/schedule_microtask_patch.dart
+++ b/runtime/lib/schedule_microtask_patch.dart
@@ -5,10 +5,7 @@
patch class _AsyncRun {
/* patch */ static void _scheduleImmediate(void callback()) {
if (_ScheduleImmediate._closure == null) {
- // TODO(9001): don't default to using the Timer to enqueue the immediate
- // callback.
- _createTimer(Duration.ZERO, callback);
- return;
+ throw new UnsupportedError("Microtasks are not supported");
}
_ScheduleImmediate._closure(callback);
}
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 6b6e659..7c11e43 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -1259,6 +1259,13 @@
}
+void Assembler::fsincos() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitUint8(0xFB);
+}
+
+
void Assembler::fptan() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xD9);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 0afbb0f..37d4b9c 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -512,6 +512,7 @@
void fsin();
void fcos();
+ void fsincos();
void fptan();
void xchgl(Register dst, Register src);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 5628494..662bf2f 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -2016,6 +2016,31 @@
}
+ASSEMBLER_TEST_GENERATE(SinCos, assembler) {
+ __ fldl(Address(ESP, kWordSize));
+ __ fsincos();
+ __ subl(ESP, Immediate(2 * kWordSize));
+ __ fstpl(Address(ESP, 0)); // cos result.
+ __ movsd(XMM0, Address(ESP, 0));
+ __ fstpl(Address(ESP, 0)); // sin result.
+ __ movsd(XMM1, Address(ESP, 0));
+ __ subsd(XMM1, XMM0); // sin - cos.
+ __ movsd(Address(ESP, 0), XMM1);
+ __ fldl(Address(ESP, 0));
+ __ addl(ESP, Immediate(2 * kWordSize));
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(SinCos, test) {
+ typedef double (*SinCosCode)(double d);
+ const double arg = 1.2345;
+ const double expected = sin(arg) - cos(arg);
+ double res = reinterpret_cast<SinCosCode>(test->entry())(arg);
+ EXPECT_FLOAT_EQ(expected, res, 0.000001);
+}
+
+
ASSEMBLER_TEST_GENERATE(Tangent, assembler) {
__ fldl(Address(ESP, kWordSize));
__ fptan();
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 64a2c87..01e40a8 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1188,6 +1188,7 @@
/* is_const = */ field.is_const(),
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
cls,
field.token_pos()));
getter.set_result_type(type);
@@ -1798,6 +1799,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
mixin_app,
mixin_app.token_pos()));
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 0d007b2..11536a9 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -28,7 +28,7 @@
cls = Class::New(function_name, script, Scanner::kDummyTokenIndex);
const Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0));
+ true, false, false, false, false, cls, 0));
function.set_result_type(Type::Handle(Type::DynamicType()));
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 882f593..44ddb3e 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1703,6 +1703,14 @@
}
+void SinCos(double arg, double* cos_res, double* sin_res) {
+ // The compiler may merge the calls to sincos, if supported. This
+ // typically occurs only when compiling for 64-bit targets.
+ *cos_res = cos(arg);
+ *sin_res = sin(arg);
+}
+
+
// Update global type feedback recorded for a field recording the assignment
// of the given value.
// Arg0: Field object;
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index dc09e24..47e9444 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -102,6 +102,7 @@
void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes);
double DartModulo(double a, double b);
+void SinCos(double arg, double* sin_res, double* cos_res);
} // namespace dart
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index a9bfc71..b012f5f 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -28,7 +28,7 @@
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
const String& target_name = String::Handle(String::New("targetFunction"));
const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index bb893d4..f2e989a 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -28,7 +28,7 @@
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
const String& target_name = String::Handle(String::New("targetFunction"));
const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index c5b51b5..c42e384 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -28,7 +28,7 @@
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
const String& target_name = String::Handle(String::New("targetFunction"));
const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 67561db..876b754 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -28,7 +28,7 @@
const String& function_name = String::Handle(Symbols::New("callerFunction"));
const Function& function = Function::Handle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
const String& target_name = String::Handle(String::New("targetFunction"));
const Array& args_descriptor =
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index d8771dc..64fdad3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -354,10 +354,8 @@
optimizer.ApplyICData();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
- // Optimize (a << b) & c patterns, merge operations. Must occur before
- // 'SelectRepresentations' which inserts conversion nodes.
- // TODO(srdjan): Moved before inlining until environment use list can
- // be used to detect when shift-left is outside the scope of bit-and.
+ // Optimize (a << b) & c patterns, merge operations.
+ // Run early in order to have more opportunity to optimize left shifts.
optimizer.TryOptimizePatterns();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -440,6 +438,13 @@
DEBUG_ASSERT(flow_graph->VerifyUseLists());
}
}
+
+ // Optimize (a << b) & c patterns, merge operations.
+ // Run after CSE in order to have more opportunity to merge
+ // instructions that have same inputs.
+ optimizer.TryOptimizePatterns();
+ DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
if (FLAG_loop_invariant_code_motion &&
(function.deoptimization_counter() <
FLAG_deoptimization_counter_licm_threshold)) {
@@ -917,10 +922,11 @@
const Function& func = Function::ZoneHandle(Function::New(
String::Handle(Symbols::New(kEvalConst)),
RawFunction::kRegularFunction,
- true, // static function.
- false, // not const function.
+ true, // static function
+ false, // not const function
false, // not abstract
- false, // not external.
+ false, // not external
+ false, // not native
Class::Handle(Type::Handle(Type::Function()).type_class()),
fragment->token_pos()));
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 60b8df6..f84dc2e 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -2026,6 +2026,17 @@
static RawFunction* GetOriginalFunction(const Function& func) {
+ if (func.IsClosureFunction()) {
+ // Local functions (closures) in mixin functions do not have
+ // an original function they were cloned from.
+ // Note: this is a problem when a breakpoint is set in a mixed-in
+ // closure. The breakpoint is linked to the closure attached to the
+ // mixin application class, not the mixin class. When the same
+ // closure is compiled for another mixin application class, we
+ // don't find the breakpoint since we'll be looking in the
+ // mixin class.
+ return func.raw();
+ }
const Class& origin_class = Class::Handle(func.origin());
if (origin_class.is_patch()) {
// Patched functions from patch classes are removed from the
@@ -2073,8 +2084,11 @@
while (bpt != NULL) {
if (lookup_function.raw() == bpt->function()) {
// Check if the breakpoint is inside a closure or local function
- // within the newly compiled function.
- Class& owner = Class::Handle(lookup_function.Owner());
+ // within the newly compiled function. Note that we must look
+ // in the owner class of the function that just got compiled
+ // (i.e. func), not the owner class of the function we use to
+ // record the breakpoint (lookup_function).
+ Class& owner = Class::Handle(func.Owner());
Function& closure =
Function::Handle(owner.LookupClosureFunction(bpt->token_pos()));
if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) {
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d1908aa..9f99579 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -508,7 +508,6 @@
ASSERT(index >= 0);
it.SetCurrentLocation(Location::StackSlot(index));
} else if (loc.IsFpuRegister()) {
- assembler()->Comment("You betcha!");
intptr_t index = fpu_reg_slots[loc.fpu_reg()];
ASSERT(index >= 0);
Value* value = it.CurrentValue();
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index bf9df1a..e86da7e 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -245,6 +245,7 @@
~FlowGraphCompiler();
static bool SupportsUnboxedMints();
+ static bool SupportsSinCos();
// Accessors.
Assembler* assembler() const { return assembler_; }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 19a75bb..f4bc5f9 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -42,6 +42,11 @@
}
+bool FlowGraphCompiler::SupportsSinCos() {
+ return false;
+}
+
+
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 81ae0aa..a1661e0 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -46,6 +46,11 @@
}
+bool FlowGraphCompiler::SupportsSinCos() {
+ return true;
+}
+
+
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 9c09757..c615a12 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -42,6 +42,11 @@
}
+bool FlowGraphCompiler::SupportsSinCos() {
+ return false;
+}
+
+
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index c2b1561..9a28abd 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -43,6 +43,11 @@
}
+bool FlowGraphCompiler::SupportsSinCos() {
+ return true;
+}
+
+
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 3efaad4..8c4febc 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -255,19 +255,19 @@
// Used by TryMergeDivMod.
// Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction,
// and the using instruction. This is an intermediate step before merging.
-static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr,
- FlowGraph* flow_graph) {
- const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
- const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1;
+void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr,
+ intptr_t ix,
+ intptr_t cid) {
+ const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid);
ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix)));
- flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue);
+ flow_graph()->InsertAfter(instr, index_instr, NULL, Definition::kValue);
LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr),
new Value(index_instr),
index_scale,
- kArrayCid,
+ cid,
Isolate::kNoDeoptId);
instr->ReplaceUsesWith(load);
- flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue);
+ flow_graph()->InsertAfter(index_instr, load, NULL, Definition::kValue);
}
@@ -297,7 +297,7 @@
for (intptr_t i = 0; i < merge_candidates->length(); i++) {
BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
if (curr_instr == NULL) {
- // Instructions was merged already.
+ // Instruction was merged already.
continue;
}
ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
@@ -316,8 +316,14 @@
(other_binop->right()->definition() == right_def)) {
(*merge_candidates)[k] = NULL; // Clear it.
// Append a LoadIndexed behind TRUNC_DIV and MOD.
- DivModAppendLoadIndexed(curr_instr, flow_graph_);
- DivModAppendLoadIndexed(other_binop, flow_graph_);
+ AppendLoadIndexedForMerged(
+ curr_instr,
+ MergedMathInstr::ResultIndexOf(curr_instr->op_kind()),
+ kArrayCid);
+ AppendLoadIndexedForMerged(
+ other_binop,
+ MergedMathInstr::ResultIndexOf(other_binop->op_kind()),
+ kArrayCid);
ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2);
args->Add(new Value(curr_instr->left()->definition()));
@@ -337,16 +343,72 @@
}
+void FlowGraphOptimizer::TryMergeMathUnary(
+ GrowableArray<MathUnaryInstr*>* merge_candidates) {
+ if (!FlowGraphCompiler::SupportsSinCos()) {
+ return;
+ }
+ if (merge_candidates->length() < 2) {
+ // Need at least a SIN and a COS.
+ return;
+ }
+ for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+ MathUnaryInstr* curr_instr = (*merge_candidates)[i];
+ if (curr_instr == NULL) {
+ // Instruction was merged already.
+ continue;
+ }
+ ASSERT((curr_instr->kind() == MethodRecognizer::kMathSin) ||
+ (curr_instr->kind() == MethodRecognizer::kMathCos));
+ // Check if there is sin/cos binop with same inputs.
+ const intptr_t other_kind =
+ (curr_instr->kind() == MethodRecognizer::kMathSin) ?
+ MethodRecognizer::kMathCos : MethodRecognizer::kMathSin;
+ Definition* def = curr_instr->value()->definition();
+ for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+ MathUnaryInstr* other_op = (*merge_candidates)[k];
+ // 'other_op' can be NULL if it was already merged.
+ if ((other_op != NULL) && (other_op->kind() == other_kind) &&
+ (other_op->value()->definition() == def)) {
+ (*merge_candidates)[k] = NULL; // Clear it.
+ // Append a LoadIndexed behind SIN and COS.
+ AppendLoadIndexedForMerged(
+ curr_instr,
+ MergedMathInstr::ResultIndexOf(curr_instr->kind()),
+ kTypedDataFloat64ArrayCid);
+ AppendLoadIndexedForMerged(
+ other_op,
+ MergedMathInstr::ResultIndexOf(other_op->kind()),
+ kTypedDataFloat64ArrayCid);
+ ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(1);
+ args->Add(new Value(curr_instr->value()->definition()));
+
+ // Replace with TruncDivMod.
+ MergedMathInstr* div_mod = new MergedMathInstr(
+ args,
+ curr_instr->DeoptimizationTarget(),
+ MergedMathInstr::kSinCos);
+ curr_instr->ReplaceWith(div_mod, current_iterator());
+ other_op->ReplaceUsesWith(div_mod);
+ other_op->RemoveFromGraph();
+ }
+ }
+ }
+}
+
+
// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
// shift can be a truncating Smi shift-left and result is always Smi.
// Merging occurs only per basic-block.
void FlowGraphOptimizer::TryOptimizePatterns() {
if (!FLAG_truncating_left_shift) return;
ASSERT(current_iterator_ == NULL);
- GrowableArray<BinarySmiOpInstr*> for_merge;
+ GrowableArray<BinarySmiOpInstr*> div_mod_merge;
+ GrowableArray<MathUnaryInstr*> sin_cos_merge;
for (intptr_t i = 0; i < block_order_.length(); ++i) {
// Merging only per basic-block.
- for_merge.Clear();
+ div_mod_merge.Clear();
+ sin_cos_merge.Clear();
BlockEntryInstr* entry = block_order_[i];
ForwardInstructionIterator it(entry);
current_iterator_ = ⁢
@@ -359,7 +421,7 @@
binop->right()->definition());
} else if ((binop->op_kind() == Token::kTRUNCDIV) ||
(binop->op_kind() == Token::kMOD)) {
- for_merge.Add(binop);
+ div_mod_merge.Add(binop);
}
} else if (it.Current()->IsBinaryMintOp()) {
BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
@@ -368,9 +430,16 @@
mintop->left()->definition(),
mintop->right()->definition());
}
+ } else if (it.Current()->IsMathUnary()) {
+ MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
+ if ((math_unary->kind() == MethodRecognizer::kMathSin) ||
+ (math_unary->kind() == MethodRecognizer::kMathCos)) {
+ sin_cos_merge.Add(math_unary);
+ }
}
}
- TryMergeTruncDivMod(&for_merge);
+ TryMergeTruncDivMod(&div_mod_merge);
+ TryMergeMathUnary(&sin_cos_merge);
current_iterator_ = NULL;
}
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index b1fd751..c473514 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -205,6 +205,9 @@
Definition* left_instr,
Definition* right_instr);
void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
+ void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
+
+ void AppendLoadIndexedForMerged(Definition* instr, intptr_t ix, intptr_t cid);
FlowGraph* flow_graph_;
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 47015a9..6db56c5 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -1222,6 +1222,8 @@
CompileType MergedMathInstr::ComputeType() const {
if (kind() == MergedMathInstr::kTruncDivMod) {
return CompileType::FromCid(kArrayCid);
+ } else if (kind() == MergedMathInstr::kSinCos) {
+ return CompileType::FromCid(kTypedDataFloat64ArrayCid);
} else {
UNIMPLEMENTED();
return CompileType::Dynamic();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 07604df..edc727e 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2989,6 +2989,25 @@
deopt_id_ = original_deopt_id;
}
+
+intptr_t MergedMathInstr::ResultIndexOf(MethodRecognizer::Kind kind) {
+ switch (kind) {
+ case MethodRecognizer::kMathSin: return 0;
+ case MethodRecognizer::kMathCos: return 1;
+ default: UNIMPLEMENTED(); return -1;
+ }
+}
+
+
+intptr_t MergedMathInstr::ResultIndexOf(Token::Kind token) {
+ switch (token) {
+ case Token::kTRUNCDIV: return 0;
+ case Token::kMOD: return 1;
+ default: UNIMPLEMENTED(); return -1;
+ }
+}
+
+
#undef __
} // namespace dart
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f5f4ac7..43b9873 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -6667,6 +6667,8 @@
static intptr_t InputCountFor(MergedMathInstr::Kind kind) {
if (kind == kTruncDivMod) {
return 2;
+ } else if (kind == kSinCos) {
+ return 1;
} else {
UNIMPLEMENTED();
return -1;
@@ -6687,6 +6689,8 @@
virtual bool CanDeoptimize() const {
if (kind_ == kTruncDivMod) {
return true;
+ } else if (kind_ == kSinCos) {
+ return false;
} else {
UNIMPLEMENTED();
return false;
@@ -6696,6 +6700,8 @@
virtual Representation representation() const {
if (kind_ == kTruncDivMod) {
return kTagged;
+ } else if (kind_ == kSinCos) {
+ return kTagged;
} else {
UNIMPLEMENTED();
return kTagged;
@@ -6703,9 +6709,11 @@
}
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT((0 <= idx) && (idx < InputCount()));
if (kind_ == kTruncDivMod) {
- ASSERT((0 <= idx) && (idx < InputCount()));
return kTagged;
+ } else if (kind_ == kSinCos) {
+ return kUnboxedDouble;
} else {
UNIMPLEMENTED();
return kTagged;
@@ -6714,6 +6722,10 @@
virtual intptr_t DeoptimizationTarget() const { return deopt_id_; }
+ // Returns the result index for one of the merged instructjons
+ static intptr_t ResultIndexOf(MethodRecognizer::Kind kind);
+ static intptr_t ResultIndexOf(Token::Kind token);
+
DECLARE_INSTRUCTION(MergedMath)
// Returns a structure describing the location constraints required
@@ -6737,6 +6749,7 @@
static const char* KindToCString(MergedMathInstr::Kind kind) {
if (kind == kTruncDivMod) return "TruncDivMod";
+ if (kind == kSinCos) return "SinCos";
UNIMPLEMENTED();
return "";
}
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index c7854cd..1266a3b 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1488,7 +1488,25 @@
if (!ok_is_fall_through) {
__ b(&ok);
}
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ Bind(fail);
+
+ __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
+ __ CompareImmediate(IP, kDynamicCid);
+ __ b(&ok, EQ);
+
+ __ Push(field_reg);
+ __ Push(value_reg);
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+ __ Drop(2); // Drop the field and the value.
+ }
} else {
+ ASSERT(compiler->is_optimizing());
+ ASSERT(deopt != NULL);
+ ASSERT(ok_is_fall_through);
+ // Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
}
@@ -1527,18 +1545,11 @@
__ CompareImmediate(value_reg,
reinterpret_cast<intptr_t>(Object::null()));
}
-
- if (ok_is_fall_through) {
- __ b(fail, NE);
- } else {
- __ b(&ok, EQ);
- }
+ __ b(fail, NE);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
- if (ok_is_fall_through) {
- __ b(fail);
- }
+ __ b(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1551,31 +1562,12 @@
FieldAddress(value_reg, TypedData::length_offset()));
}
__ CompareImmediate(value_cid_reg, field_length);
- if (ok_is_fall_through) {
- __ b(fail, NE);
- }
+ __ b(fail, NE);
} else {
- // Nothing to emit.
- ASSERT(!compiler->is_optimizing());
- return;
+ UNREACHABLE();
}
}
}
-
- if (deopt == NULL) {
- ASSERT(!compiler->is_optimizing());
- __ Bind(fail);
-
- __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
- __ CompareImmediate(IP, kDynamicCid);
- __ b(&ok, EQ);
-
- __ Push(field_reg);
- __ Push(value_reg);
- __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
- __ Drop(2); // Drop the field and the value.
- }
-
__ Bind(&ok);
}
@@ -4145,6 +4137,9 @@
__ StoreIntoObjectNoBarrier(result, store_address, result_mod);
return;
}
+ if (kind() == MergedMathInstr::kSinCos) {
+ UNIMPLEMENTED();
+ }
UNIMPLEMENTED();
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index dc8a237..8c9c9eb 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1494,7 +1494,24 @@
if (!ok_is_fall_through) {
__ jmp(&ok);
}
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ Bind(fail);
+
+ __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
+ Immediate(kDynamicCid));
+ __ j(EQUAL, &ok);
+
+ __ pushl(field_reg);
+ __ pushl(value_reg);
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+ __ Drop(2); // Drop the field and the value.
+ }
} else {
+ ASSERT(compiler->is_optimizing());
+ ASSERT(deopt != NULL);
+ ASSERT(ok_is_fall_through);
// Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
@@ -1537,18 +1554,11 @@
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpl(value_reg, raw_null);
}
-
- if (ok_is_fall_through) {
- __ j(NOT_EQUAL, fail);
- } else {
- __ j(EQUAL, &ok);
- }
+ __ j(NOT_EQUAL, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
- if (ok_is_fall_through) {
- __ jmp(fail);
- }
+ __ jmp(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1561,31 +1571,12 @@
FieldAddress(value_reg, TypedData::length_offset()));
}
__ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length)));
- if (ok_is_fall_through) {
- __ j(NOT_EQUAL, fail);
- }
+ __ j(NOT_EQUAL, fail);
} else {
- // Nothing to emit.
- ASSERT(!compiler->is_optimizing());
- return;
+ UNREACHABLE();
}
}
}
-
- if (deopt == NULL) {
- ASSERT(!compiler->is_optimizing());
- __ Bind(fail);
-
- __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
- Immediate(kDynamicCid));
- __ j(EQUAL, &ok);
-
- __ pushl(field_reg);
- __ pushl(value_reg);
- __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
- __ Drop(2); // Drop the field and the value.
- }
-
__ Bind(&ok);
}
@@ -4012,11 +4003,27 @@
summary->set_temp(0, Location::RegisterLocation(EDX));
return summary;
}
+ if (kind() == MergedMathInstr::kSinCos) {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ summary->set_in(0, Location::FpuRegisterLocation(XMM1));
+ summary->set_out(Location::RegisterLocation(EAX));
+ return summary;
+ }
UNIMPLEMENTED();
return NULL;
}
+typedef void (*SinCosCFunction) (double x, double* res_sin, double* res_cos);
+
+extern const RuntimeEntry kSinCosRuntimeEntry(
+ "libc_sincos", reinterpret_cast<RuntimeFunction>(
+ static_cast<SinCosCFunction>(&SinCos)), 1, true, true);
+
+
void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Label* deopt = NULL;
if (CanDeoptimize()) {
@@ -4081,15 +4088,13 @@
__ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)));
const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
Address trunc_div_address(
- FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
- index_scale,
- result,
- 0));
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(Token::kTRUNCDIV)));
Address mod_address(
- FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
- index_scale,
- result,
- 1));
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(Token::kMOD)));
__ SmiTag(EAX);
__ SmiTag(EDX);
__ StoreIntoObjectNoBarrier(result, trunc_div_address, EAX);
@@ -4097,6 +4102,39 @@
return;
}
+ if (kind() == MergedMathInstr::kSinCos) {
+ // Do x87 sincos, since the ia32 compilers may not fuse sin/cos into
+ // sincos.
+ __ pushl(EAX);
+ __ pushl(EAX);
+ __ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
+ __ fldl(Address(ESP, 0));
+ __ fsincos();
+ __ fstpl(Address(ESP, 0));
+ __ movsd(XMM1, Address(ESP, 0));
+ __ fstpl(Address(ESP, 0));
+ __ movsd(XMM0, Address(ESP, 0));
+ __ addl(ESP, Immediate(2 * kWordSize));
+
+ Register result = locs()->out().reg();
+ const TypedData& res_array = TypedData::ZoneHandle(
+ TypedData::New(kTypedDataFloat64ArrayCid, 2, Heap::kOld));
+ __ LoadObject(result, res_array);
+ const intptr_t index_scale =
+ FlowGraphCompiler::ElementSizeFor(kTypedDataFloat64ArrayCid);
+ Address sin_address(
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataFloat64ArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathSin)));
+ Address cos_address(
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataFloat64ArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathCos)));
+ __ movsd(sin_address, XMM0);
+ __ movsd(cos_address, XMM1);
+ return;
+ }
+
UNIMPLEMENTED();
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 83d0b0c..07ac406 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1552,7 +1552,25 @@
if (!ok_is_fall_through) {
__ b(&ok);
}
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ Bind(fail);
+
+ __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
+ __ BranchEqual(CMPRES1, kDynamicCid, &ok);
+
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(field_reg, Address(SP, 1 * kWordSize));
+ __ sw(value_reg, Address(SP, 0 * kWordSize));
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+ __ Drop(2); // Drop the field and the value.
+ }
} else {
+ ASSERT(compiler->is_optimizing());
+ ASSERT(deopt != NULL);
+ ASSERT(ok_is_fall_through);
+ // Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
}
@@ -1594,17 +1612,11 @@
__ subu(CMPRES1, value_reg, TMP);
}
- if (ok_is_fall_through) {
- __ bne(CMPRES1, ZR, fail);
- } else {
- __ beq(CMPRES1, ZR, &ok);
- }
+ __ bne(CMPRES1, ZR, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
- if (ok_is_fall_through) {
- __ b(fail);
- }
+ __ b(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1618,31 +1630,12 @@
}
__ LoadImmediate(TMP, Smi::RawValue(field_length));
__ subu(CMPRES1, value_cid_reg, TMP);
- if (ok_is_fall_through) {
- __ bne(CMPRES1, ZR, fail);
- }
+ __ bne(CMPRES1, ZR, fail);
} else {
- // Nothing to emit.
- ASSERT(!compiler->is_optimizing());
- return;
+ UNREACHABLE();
}
}
}
-
- if (deopt == NULL) {
- ASSERT(!compiler->is_optimizing());
- __ Bind(fail);
-
- __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
- __ BranchEqual(CMPRES1, kDynamicCid, &ok);
-
- __ addiu(SP, SP, Immediate(-2 * kWordSize));
- __ sw(field_reg, Address(SP, 1 * kWordSize));
- __ sw(value_reg, Address(SP, 0 * kWordSize));
- __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
- __ Drop(2); // Drop the field and the value.
- }
-
__ Bind(&ok);
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 9f61a2f..72160c2 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1390,7 +1390,25 @@
if (!ok_is_fall_through) {
__ jmp(&ok);
}
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ Bind(fail);
+
+ __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
+ Immediate(kDynamicCid), PP);
+ __ j(EQUAL, &ok);
+
+ __ pushq(field_reg);
+ __ pushq(value_reg);
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+ __ Drop(2); // Drop the field and the value.
+ }
} else {
+ ASSERT(compiler->is_optimizing());
+ ASSERT(deopt != NULL);
+ ASSERT(ok_is_fall_through);
+ // Field guard class has been initialized and is known.
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
}
@@ -1430,18 +1448,11 @@
__ j(EQUAL, &ok);
__ CompareObject(value_reg, Object::null_object(), PP);
}
-
- if (ok_is_fall_through) {
- __ j(NOT_EQUAL, fail);
- } else {
- __ j(EQUAL, &ok);
- }
+ __ j(NOT_EQUAL, fail);
} else {
// Both value's and field's class id is known.
if ((value_cid != field_cid) && (value_cid != nullability)) {
- if (ok_is_fall_through) {
- __ jmp(fail);
- }
+ __ jmp(fail);
} else if (field_has_length && (value_cid == field_cid)) {
ASSERT(value_cid_reg != kNoRegister);
if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1455,31 +1466,12 @@
}
__ CompareImmediate(
value_cid_reg, Immediate(Smi::RawValue(field_length)), PP);
- if (ok_is_fall_through) {
- __ j(NOT_EQUAL, fail);
- }
+ __ j(NOT_EQUAL, fail);
} else {
- // Nothing to emit.
- ASSERT(!compiler->is_optimizing());
- return;
+ UNREACHABLE();
}
}
}
-
- if (deopt == NULL) {
- ASSERT(!compiler->is_optimizing());
- __ Bind(fail);
-
- __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
- Immediate(kDynamicCid), PP);
- __ j(EQUAL, &ok);
-
- __ pushq(field_reg);
- __ pushq(value_reg);
- __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
- __ Drop(2); // Drop the field and the value.
- }
-
__ Bind(&ok);
}
@@ -4052,11 +4044,28 @@
summary->set_temp(0, Location::RegisterLocation(RDX));
return summary;
}
+ if (kind() == MergedMathInstr::kSinCos) {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ summary->set_in(0, Location::FpuRegisterLocation(XMM1));
+ summary->set_out(Location::RegisterLocation(RAX));
+ return summary;
+ }
UNIMPLEMENTED();
return NULL;
}
+
+typedef void (*SinCosCFunction) (double x, double* res_sin, double* res_cos);
+
+extern const RuntimeEntry kSinCosRuntimeEntry(
+ "libc_sincos", reinterpret_cast<RuntimeFunction>(
+ static_cast<SinCosCFunction>(&SinCos)), 1, true, true);
+
+
void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Label* deopt = NULL;
if (CanDeoptimize()) {
@@ -4146,15 +4155,13 @@
__ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP);
const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
Address trunc_div_address(
- FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
- index_scale,
- result,
- 0));
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(Token::kTRUNCDIV)));
Address mod_address(
- FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
- index_scale,
- result,
- 1));
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(Token::kMOD)));
__ SmiTag(RAX);
__ SmiTag(RDX);
__ StoreIntoObjectNoBarrier(result, trunc_div_address, RAX);
@@ -4164,6 +4171,50 @@
// in-range arguments, cannot create out-of-range result.
return;
}
+ if (kind() == MergedMathInstr::kSinCos) {
+ __ EnterFrame(0);
+ // +-------------------------------+
+ // | double-argument | <- TOS
+ // +-------------------------------+
+ // | address-cos-result | +8
+ // +-------------------------------+
+ // | address-sin-result | +16
+ // +-------------------------------+
+ // | double-storage-for-cos-result | +24
+ // +-------------------------------+
+ // | double-storage-for-sin-result | +32
+ // +-------------------------------+
+ // ....
+ __ ReserveAlignedFrameSpace(kDoubleSize * 3 + kWordSize * 2);
+ __ movsd(Address(RSP, 0), locs()->in(0).fpu_reg());
+
+ __ leaq(RDI, Address(RSP, 2 * kWordSize + kDoubleSize));
+ __ leaq(RSI, Address(RSP, 2 * kWordSize + 2 * kDoubleSize));
+ __ movaps(XMM0, locs()->in(0).fpu_reg());
+
+ __ CallRuntime(kSinCosRuntimeEntry, InputCount());
+ __ movsd(XMM0, Address(RSP, 2 * kWordSize + kDoubleSize * 2)); // sin.
+ __ movsd(XMM1, Address(RSP, 2 * kWordSize + kDoubleSize)); // cos.
+ __ leave();
+
+ Register result = locs()->out().reg();
+ const TypedData& res_array = TypedData::ZoneHandle(
+ TypedData::New(kTypedDataFloat64ArrayCid, 2, Heap::kOld));
+ __ LoadObject(result, res_array, PP);
+ const intptr_t index_scale =
+ FlowGraphCompiler::ElementSizeFor(kTypedDataFloat64ArrayCid);
+ Address sin_address(
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataFloat64ArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathSin)));
+ Address cos_address(
+ FlowGraphCompiler::ElementAddressForIntIndex(
+ kTypedDataFloat64ArrayCid, index_scale, result,
+ MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathCos)));
+ __ movsd(sin_address, XMM0);
+ __ movsd(cos_address, XMM1);
+ return;
+ }
UNIMPLEMENTED();
}
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index a392731..473c63b 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -64,6 +64,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
cls,
0)); // No token position.
miss_handler_code_ = code.raw();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index a954661..b138c2a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1822,7 +1822,7 @@
closure ^= closures.At(i);
ASSERT(!closure.IsNull());
if ((closure.token_pos() <= token_pos) &&
- (token_pos < closure.end_token_pos()) &&
+ (token_pos <= closure.end_token_pos()) &&
(best_fit_token_pos < closure.token_pos())) {
best_fit_index = i;
best_fit_token_pos = closure.token_pos();
@@ -2129,6 +2129,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
*this,
0)); // No token position.
ArgumentsDescriptor desc(args_desc);
@@ -2337,6 +2338,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
temp_class,
0));
eval_func.set_result_type(Type::Handle(Type::DynamicType()));
@@ -5042,6 +5044,7 @@
bool is_const,
bool is_abstract,
bool is_external,
+ bool is_native,
const Object& owner,
intptr_t token_pos) {
ASSERT(!owner.IsNull());
@@ -5054,6 +5057,7 @@
result.set_is_const(is_const);
result.set_is_abstract(is_abstract);
result.set_is_external(is_external);
+ result.set_is_native(is_native);
result.set_is_visible(true); // Will be computed later.
result.set_is_intrinsic(false);
result.set_is_recognized(false);
@@ -5069,7 +5073,6 @@
result.set_optimized_call_site_count(0);
result.set_is_optimizable(true);
result.set_has_finally(false);
- result.set_is_native(false);
result.set_is_inlinable(true);
if (kind == RawFunction::kClosureFunction) {
const ClosureData& data = ClosureData::Handle(ClosureData::New());
@@ -5111,6 +5114,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
+ parent.is_native(),
parent_owner,
token_pos));
result.set_parent_function(parent);
@@ -5497,6 +5501,7 @@
false, // !const
false, // !abstract
false, // !external
+ false, // !native
Class::Handle(field.owner()),
field.token_pos()));
init_function.set_result_type(AbstractType::Handle(field.type()));
@@ -11040,6 +11045,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
temp_class,
0));
eval_func.set_result_type(Type::Handle(Type::DynamicType()));
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 99a9fb5..d41ba4c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1888,6 +1888,7 @@
bool is_const,
bool is_abstract,
bool is_external,
+ bool is_native,
const Object& owner,
intptr_t token_pos);
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a4a22a6..7a017b5 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -64,12 +64,12 @@
function_name = Symbols::New("foo");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- false, false, false, false, cls, 0);
+ false, false, false, false, false, cls, 0);
functions.SetAt(0, function);
function_name = Symbols::New("bar");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- false, false, false, false, cls, 0);
+ false, false, false, false, false, cls, 0);
const int kNumFixedParameters = 2;
const int kNumOptionalParameters = 3;
@@ -82,24 +82,24 @@
function_name = Symbols::New("baz");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- false, false, false, false, cls, 0);
+ false, false, false, false, false, cls, 0);
functions.SetAt(2, function);
function_name = Symbols::New("Foo");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0);
+ true, false, false, false, false, cls, 0);
functions.SetAt(3, function);
function_name = Symbols::New("Bar");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0);
+ true, false, false, false, false, cls, 0);
functions.SetAt(4, function);
function_name = Symbols::New("BaZ");
function = Function::New(
function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0);
+ true, false, false, false, false, cls, 0);
functions.SetAt(5, function);
// Setup the functions in the class.
@@ -2336,7 +2336,7 @@
Function& parent = Function::Handle();
const String& parent_name = String::Handle(Symbols::New("foo_papa"));
parent = Function::New(parent_name, RawFunction::kRegularFunction,
- false, false, false, false, cls, 0);
+ false, false, false, false, false, cls, 0);
functions.SetAt(0, parent);
cls.SetFunctions(functions);
@@ -2411,7 +2411,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
return &function;
}
@@ -2630,12 +2630,14 @@
const bool is_const = false;
const bool is_abstract = false;
const bool is_external = false;
+ const bool is_native = false;
return Function::New(function_name,
RawFunction::kRegularFunction,
is_static,
is_const,
is_abstract,
is_external,
+ is_native,
cls,
0);
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 18b58c4..66d3e48 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -525,6 +525,7 @@
has_var = false;
has_factory = false;
has_operator = false;
+ has_native = false;
metadata_pos = -1;
operator_token = Token::kILLEGAL;
type = NULL;
@@ -576,6 +577,7 @@
bool has_var;
bool has_factory;
bool has_operator;
+ bool has_native;
intptr_t metadata_pos;
Token::Kind operator_token;
const AbstractType* type;
@@ -930,7 +932,7 @@
ident->ToCString(),
cls.ToCString());
}
- expr = GenerateStaticFieldLookup(field, TokenPos());
+ expr = GenerateStaticFieldLookup(field, ident_pos);
}
}
if (expr->EvalConstExpr() == NULL) {
@@ -1065,6 +1067,7 @@
AddFormalParamsToScope(¶ms, current_block_->scope);
// Move forward to the start of the initializer expression.
+ intptr_t ident_pos = TokenPos();
ExpectIdentifier("identifier expected");
ExpectToken(Token::kASSIGN);
intptr_t token_pos = TokenPos();
@@ -1110,7 +1113,7 @@
AstNode* compare_transition_sentinel = new ComparisonNode(
token_pos,
Token::kEQ_STRICT,
- new LoadStaticFieldNode(token_pos, field),
+ new LoadStaticFieldNode(ident_pos, field),
new LiteralNode(field.token_pos(), Object::transition_sentinel()));
SequenceNode* store_null = new SequenceNode(token_pos, NULL);
@@ -1574,6 +1577,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
current_class(),
parameter.name_pos));
signature_function.set_result_type(result_type);
@@ -1997,9 +2001,9 @@
}
-AstNode* Parser::ParseSuperFieldAccess(const String& field_name) {
+AstNode* Parser::ParseSuperFieldAccess(const String& field_name,
+ intptr_t field_pos) {
TRACE_PARSER("ParseSuperFieldAccess");
- const intptr_t field_pos = TokenPos();
const Class& super_class = Class::ZoneHandle(current_class().SuperClass());
if (super_class.IsNull()) {
ErrorMsg("class '%s' does not have a superclass",
@@ -3274,6 +3278,7 @@
ParseNativeDeclaration();
method_end_pos = TokenPos();
ExpectSemicolon();
+ method->has_native = true;
} else {
// We haven't found a method body. Issue error if one is required.
const bool must_have_body =
@@ -3329,6 +3334,7 @@
method->has_const,
method->has_abstract,
method->has_external,
+ method->has_native,
current_class(),
method->decl_begin_pos));
func.set_result_type(*method->type);
@@ -3446,6 +3452,7 @@
field->has_const,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
current_class(),
field->name_pos);
getter.set_result_type(*field->type);
@@ -3468,6 +3475,7 @@
field->has_final,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
current_class(),
field->name_pos);
ParamList params;
@@ -3484,6 +3492,7 @@
field->has_final,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
current_class(),
field->name_pos);
ParamList params;
@@ -4010,6 +4019,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
cls,
cls.token_pos()));
ctor.set_end_token_pos(ctor.token_pos());
@@ -4238,6 +4248,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
function_type_alias,
alias_name_pos));
signature_function.set_result_type(result_type);
@@ -4571,6 +4582,7 @@
is_const,
/* is_abstract = */ false,
/* is_external = */ false,
+ /* is_native = */ false,
current_class(),
name_pos);
getter.set_result_type(type);
@@ -4651,6 +4663,7 @@
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
intptr_t function_end_pos = function_pos;
+ bool is_native = false;
if (is_external) {
function_end_pos = TokenPos();
ExpectSemicolon();
@@ -4667,6 +4680,7 @@
ParseNativeDeclaration();
function_end_pos = TokenPos();
ExpectSemicolon();
+ is_native = true;
} else {
ErrorMsg("function block expected");
}
@@ -4677,6 +4691,7 @@
/* is_const = */ false,
/* is_abstract = */ false,
is_external,
+ is_native,
current_class(),
decl_begin_pos));
func.set_result_type(result_type);
@@ -4781,6 +4796,7 @@
}
intptr_t accessor_end_pos = accessor_pos;
+ bool is_native = false;
if (is_external) {
accessor_end_pos = TokenPos();
ExpectSemicolon();
@@ -4797,17 +4813,19 @@
ParseNativeDeclaration();
accessor_end_pos = TokenPos();
ExpectSemicolon();
+ is_native = true;
} else {
ErrorMsg("function block expected");
}
Function& func = Function::Handle(
Function::New(accessor_name,
- is_getter? RawFunction::kGetterFunction :
- RawFunction::kSetterFunction,
+ is_getter ? RawFunction::kGetterFunction :
+ RawFunction::kSetterFunction,
is_static,
/* is_const = */ false,
/* is_abstract = */ false,
is_external,
+ is_native,
current_class(),
decl_begin_pos));
func.set_result_type(result_type);
@@ -5287,7 +5305,7 @@
// Builds ReturnNode/NativeBodyNode for a native function.
void Parser::ParseNativeFunctionBlock(const ParamList* params,
const Function& func) {
- func.set_is_native(true);
+ ASSERT(func.is_native());
TRACE_PARSER("ParseNativeFunctionBlock");
const Class& cls = Class::Handle(func.Owner());
const Library& library = Library::Handle(cls.library());
@@ -7775,6 +7793,28 @@
}
+// Check whether the syntax of expression expr is a grammatically legal
+// assignable expression. This check is used to detect situations where
+// the expression itself is assignable, but the source is grammatically
+// wrong. The AST representation of an expression cannot distinguish
+// between x = 0 and (x) = 0. The latter is illegal.
+// A syntactically legal assignable expression always ends with an
+// identifier token or a ] token. We rewind the token iterator and
+// check whether the token before end_pos is an identifier or ].
+bool Parser::IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos) {
+ ASSERT(expr->token_pos() >= 0);
+ ASSERT(expr->token_pos() < end_pos);
+ SetPosition(expr->token_pos());
+ Token::Kind token = Token::kILLEGAL;
+ while (TokenPos() < end_pos) {
+ token = CurrentToken();
+ ConsumeToken();
+ }
+ ASSERT(TokenPos() == end_pos);
+ return Token::IsIdentifier(token) || (token == Token::kRBRACK);
+}
+
+
AstNode* Parser::CreateAssignmentNode(AstNode* original,
AstNode* rhs,
const String* left_ident,
@@ -7915,6 +7955,9 @@
return expr;
}
// Assignment expressions.
+ if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+ ErrorMsg(expr_pos, "expression is not assignable");
+ }
const Token::Kind assignment_op = CurrentToken();
const intptr_t assignment_pos = TokenPos();
ConsumeToken();
@@ -7993,6 +8036,9 @@
Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
const intptr_t expr_pos = TokenPos();
expr = ParseUnaryExpr();
+ if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+ ErrorMsg(expr_pos, "expression is not assignable");
+ }
// Is prefix.
LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
Token::Kind binary_op =
@@ -8155,7 +8201,7 @@
intptr_t ident_pos) {
// If the static field has an initializer, initialize the field at compile
// time, which is only possible if the field is const.
- AstNode* initializing_getter = RunStaticFieldInitializer(field);
+ AstNode* initializing_getter = RunStaticFieldInitializer(field, ident_pos);
if (initializing_getter != NULL) {
// The field is not yet initialized and could not be initialized at compile
// time. The getter will initialize the field.
@@ -8188,7 +8234,6 @@
bool consume_cascades) {
TRACE_PARSER("ParseStaticFieldAccess");
AstNode* access = NULL;
- const intptr_t call_pos = TokenPos();
const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name));
Function& func = Function::ZoneHandle();
if (field.IsNull()) {
@@ -8205,14 +8250,14 @@
// there is a function of the same name.
func = cls.LookupStaticFunction(field_name);
if (!func.IsNull()) {
- access = CreateImplicitClosureNode(func, call_pos, NULL);
+ access = CreateImplicitClosureNode(func, ident_pos, NULL);
} else {
// No function to closurize found found.
// This field access may turn out to be a call to the setter.
// Create a getter call, which may later be turned into
// a setter call, or else the backend will generate
// a throw NoSuchMethodError().
- access = new StaticGetterNode(call_pos,
+ access = new StaticGetterNode(ident_pos,
NULL,
false,
Class::ZoneHandle(cls.raw()),
@@ -8220,14 +8265,14 @@
}
} else {
ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
- access = new StaticGetterNode(call_pos,
+ access = new StaticGetterNode(ident_pos,
NULL,
false,
Class::ZoneHandle(cls.raw()),
field_name);
}
} else {
- access = GenerateStaticFieldLookup(field, TokenPos());
+ access = GenerateStaticFieldLookup(field, ident_pos);
}
return access;
}
@@ -8530,6 +8575,9 @@
expr = ParseSelectors(expr, false);
if (IsIncrementOperator(CurrentToken())) {
TRACE_PARSER("IncrementOperator");
+ if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+ ErrorMsg(expr_pos, "expression is not assignable");
+ }
Token::Kind incr_op = CurrentToken();
ConsumeToken();
// Not prefix.
@@ -8736,7 +8784,8 @@
// If the field is already initialized, return no ast (NULL).
// Otherwise, if the field is constant, initialize the field and return no ast.
// If the field is not initialized and not const, return the ast for the getter.
-AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
+AstNode* Parser::RunStaticFieldInitializer(const Field& field,
+ intptr_t field_ref_pos) {
ASSERT(field.is_static());
const Class& field_owner = Class::ZoneHandle(field.owner());
const String& field_name = String::ZoneHandle(field.name());
@@ -8750,7 +8799,7 @@
field_name.ToCString());
} else {
// The implicit static getter will throw the exception if necessary.
- return new StaticGetterNode(TokenPos(),
+ return new StaticGetterNode(field_ref_pos,
NULL,
false,
field_owner,
@@ -8782,7 +8831,7 @@
field.set_value(Object::null_instance());
// It is a compile-time error if evaluation of a compile-time constant
// would raise an exception.
- AppendErrorMsg(error, TokenPos(),
+ AppendErrorMsg(error, field_ref_pos,
"error initializing const field '%s'",
String::Handle(field.name()).ToCString());
} else {
@@ -8792,11 +8841,11 @@
ASSERT(const_value.IsNull() || const_value.IsInstance());
Instance& instance = Instance::Handle();
instance ^= const_value.raw();
- instance = TryCanonicalize(instance, TokenPos());
+ instance = TryCanonicalize(instance, field_ref_pos);
field.set_value(instance);
return NULL; // Constant
} else {
- return new StaticGetterNode(TokenPos(),
+ return new StaticGetterNode(field_ref_pos,
NULL,
false,
field_owner,
@@ -8808,7 +8857,11 @@
return NULL;
}
ASSERT(getter.kind() == RawFunction::kImplicitGetter);
- return new StaticGetterNode(TokenPos(), NULL, false, field_owner, field_name);
+ return new StaticGetterNode(field_ref_pos,
+ NULL,
+ false,
+ field_owner,
+ field_name);
}
@@ -10321,21 +10374,23 @@
current_function().origin()).Name()).ToCString());
}
}
+ const intptr_t super_pos = TokenPos();
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
+ const intptr_t ident_pos = TokenPos();
const String& ident = *ExpectIdentifier("identifier expected");
if (CurrentToken() == Token::kLPAREN) {
primary = ParseSuperCall(ident);
} else {
- primary = ParseSuperFieldAccess(ident);
+ primary = ParseSuperFieldAccess(ident, ident_pos);
}
} else if ((CurrentToken() == Token::kLBRACK) ||
Token::CanBeOverloaded(CurrentToken()) ||
(CurrentToken() == Token::kNE)) {
primary = ParseSuperOperator();
} else {
- primary = new PrimaryNode(TokenPos(), Symbols::Super());
+ primary = new PrimaryNode(super_pos, Symbols::Super());
}
} else {
UnexpectedToken();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index fc9ddbe..a500605 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -318,7 +318,8 @@
void CheckRecursiveInvocation();
const Instance& EvaluateConstExpr(intptr_t expr_pos, AstNode* expr);
- AstNode* RunStaticFieldInitializer(const Field& field);
+ AstNode* RunStaticFieldInitializer(const Field& field,
+ intptr_t field_ref_pos);
RawObject* EvaluateConstConstructorCall(
const Class& type_class,
const AbstractTypeArguments& type_arguments,
@@ -421,7 +422,7 @@
bool resolve_getter,
bool* is_no_such_method);
AstNode* ParseSuperCall(const String& function_name);
- AstNode* ParseSuperFieldAccess(const String& field_name);
+ AstNode* ParseSuperFieldAccess(const String& field_name, intptr_t field_pos);
AstNode* ParseSuperOperator();
AstNode* BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super);
@@ -639,6 +640,7 @@
void EnsureExpressionTemp();
void EnsureSavedCurrentContext();
+ bool IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos);
AstNode* CreateAssignmentNode(AstNode* original,
AstNode* rhs,
const String* left_ident,
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 211c15e..fcbed02 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -77,6 +77,7 @@
false, // Not const.
false, // Not abstract.
false, // Not external.
+ false, // Not native.
owner,
0)); // No token position.
diff --git a/runtime/vm/runtime_entry_test.cc b/runtime/vm/runtime_entry_test.cc
index 138bea7..687782a 100644
--- a/runtime/vm/runtime_entry_test.cc
+++ b/runtime/vm/runtime_entry_test.cc
@@ -20,7 +20,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
const Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function);
owner_class.SetFunctions(functions);
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 70db148..bd9d7d1 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -33,7 +33,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
return &function;
}
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 20f6a23..c4bc94d 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -33,7 +33,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
return &function;
}
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index 71bcecf..25b3a7c 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -33,7 +33,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
return &function;
}
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index 09fb677..27e3c3f 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -33,7 +33,7 @@
const String& function_name = String::ZoneHandle(Symbols::New(name));
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, owner_class, 0));
+ true, false, false, false, false, owner_class, 0));
return &function;
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 5401651..ac7b0d9 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -134,9 +134,9 @@
V(Int, "int") \
V(Double, "double") \
V(_Float32x4, "_Float32x4") \
- V(_Int32x4, "_Int32x4") \
+ V(_Int32x4, "_Int32x4") \
V(Float32x4, "Float32x4") \
- V(Int32x4, "Int32x4") \
+ V(Int32x4, "Int32x4") \
V(Int8List, "Int8List") \
V(Int8ListFactory, "Int8List.") \
V(Uint8List, "Uint8List") \
@@ -157,8 +157,8 @@
V(Uint64ListFactory, "Uint64List.") \
V(Float32x4List, "Float32x4List") \
V(Float32x4ListFactory, "Float32x4List.") \
- V(Int32x4List, "Int32x4List") \
- V(Int32x4ListFactory, "Int32x4List.") \
+ V(Int32x4List, "Int32x4List") \
+ V(Int32x4ListFactory, "Int32x4List.") \
V(Float32List, "Float32List") \
V(Float32ListFactory, "Float32List.") \
V(Float64List, "Float64List") \
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index cca7e1a..7ffa38f 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -151,7 +151,7 @@
cls.set_library(lib);
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0));
+ true, false, false, false, false, cls, 0));
code_ = Code::FinalizeCode(function, assembler_);
if (FLAG_disassemble) {
OS::Print("Code for test '%s' {\n", name_);
@@ -179,7 +179,7 @@
Class::New(function_name, Script::Handle(), Scanner::kDummyTokenIndex));
function_ = Function::New(
function_name, RawFunction::kRegularFunction,
- true, false, false, false, cls, 0);
+ true, false, false, false, false, cls, 0);
function_.set_result_type(Type::Handle(Type::DynamicType()));
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function_);
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 38c18ee..2b08494 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -11,6 +11,7 @@
import "tree/tree.dart";
import "util/util.dart";
import "elements/modelx.dart" show ElementX, FunctionElementX, ClassElementX;
+import "elements/visitor.dart" show ElementVisitor;
class ClosureNamer {
String getClosureVariableName(String name, int id) {
@@ -98,6 +99,8 @@
}
String toString() => "ClosureFieldElement($name)";
+
+ accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this);
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -142,6 +145,8 @@
* The most outer method this closure is declared into.
*/
final Element methodElement;
+
+ accept(ElementVisitor visitor) => visitor.visitClosureClassElement(this);
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -152,6 +157,8 @@
: super(name, ElementKind.VARIABLE_LIST, enclosingElement);
DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
+ accept(ElementVisitor visitor) => visitor.visitBoxElement(this);
}
// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
@@ -168,6 +175,8 @@
}
final Element variableElement;
+
+ accept(ElementVisitor visitor) => visitor.visitBoxFieldElement(this);
}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -184,21 +193,8 @@
// Since there is no declaration corresponding to 'this', use the position of
// the enclosing method.
Token position() => enclosingElement.position();
-}
-// TODO(ahe): These classes continuously cause problems. We need to
-// move these classes to elements/modelx.dart or see if we can find a
-// more general solution.
-class CheckVariableElement extends ElementX {
- Element parameter;
- CheckVariableElement(String name, this.parameter, Element enclosing)
- : super(name, ElementKind.VARIABLE, enclosing);
-
- DartType computeType(Compiler compiler) => compiler.types.dynamicType;
-
- // Since there is no declaration for the synthetic 'check' variable, use
- // parameter.
- Token position() => parameter.position();
+ accept(ElementVisitor visitor) => visitor.visitThisElement(this);
}
// The box-element for a scope, and the captured variables that need to be
@@ -258,11 +254,6 @@
bool isClosure() => closureElement != null;
- bool isVariableCaptured(Element element) {
- return freeVariableMapping.containsKey(element)
- || capturingScopesBox(element);
- }
-
bool capturingScopesBox(Element element) {
return capturingScopes.values.any((scope) {
return scope.boxedLoopVariables.contains(element);
@@ -294,14 +285,6 @@
scope.capturedVariableMapping.forEach(f);
});
}
-
- void forEachNonBoxedCapturedVariable(void f(Element local, Element field)) {
- freeVariableMapping.forEach((variable, copy) {
- if (variable is BoxElement) return;
- if (isVariableBoxed(variable)) return;
- f(variable, copy);
- });
- }
}
class ClosureTranslator extends Visitor {
diff --git a/sdk/lib/_internal/compiler/implementation/code_buffer.dart b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
index f63a99a..00baef1 100644
--- a/sdk/lib/_internal/compiler/implementation/code_buffer.dart
+++ b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
@@ -74,8 +74,6 @@
CodeBuffer addAll(Iterable<Object> iterable) => writeAll(iterable);
- CodeBuffer addCharCode(int charCode) => writeCharCode(charCode);
-
CodeBuffer writeCharCode(int charCode) {
buffer.writeCharCode(charCode);
return this;
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index fd1163e..628ee9c 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -189,19 +189,6 @@
});
}
- /**
- * Returns an [Iterable] of static const fields that need to be initialized.
- * The fields must be evaluated in order since they might depend on each
- * other.
- */
- Iterable<VariableElement> getStaticFinalFieldsForEmission() {
- return initialVariableValues.keys.where((element) {
- return element.kind == ElementKind.FIELD
- && !element.isInstanceMember()
- && element.modifiers.isFinal();
- });
- }
-
List<VariableElement> getLazilyInitializedFieldsForEmission() {
return new List<VariableElement>.from(lazyStatics);
}
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 1ded67e..c49df9d 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -87,12 +87,6 @@
void initializeHelperClasses() {}
- void enqueueAllTopLevelFunctions(LibraryElement lib, Enqueuer world) {
- lib.forEachExport((Element e) {
- if (e.isFunction()) world.addToWorkList(e);
- });
- }
-
void enqueueHelpers(ResolutionEnqueuer world, TreeElements elements);
void codegen(CodegenWorkItem work);
@@ -1088,7 +1082,14 @@
enqueuer.resolution.logSummary(log);
if (compilationFailed) return;
- if (analyzeOnly) return;
+ if (analyzeOnly) {
+ if (!analyzeAll) {
+ // No point in reporting unused code when [analyzeAll] is true: all
+ // code is artificially used.
+ reportUnusedCode();
+ }
+ return;
+ }
assert(main != null);
phase = PHASE_DONE_RESOLVING;
@@ -1518,6 +1519,28 @@
}
return firstToken;
}
+
+ void reportUnusedCode() {
+ void checkLive(member) {
+ if (member.isFunction()) {
+ if (!enqueuer.resolution.isLive(member)) {
+ reportHint(member, MessageKind.UNUSED_METHOD,
+ {'method_name': member.name});
+ }
+ } else if (member.isClass() && !member.isMixinApplication) {
+ member.forEachLocalMember(checkLive);
+ }
+ }
+ libraries.forEach((_, library) {
+ // TODO(ahe): Implement better heuristics to discover entry points of
+ // packages and use that to discover unused implementation details in
+ // packages.
+ if (library.isPlatformLibrary || library.isPackageLibrary) return;
+ library.compilationUnits.forEach((unit) {
+ unit.forEachLocalMember(checkLive);
+ });
+ });
+ }
}
class CompilerTask {
diff --git a/sdk/lib/_internal/compiler/implementation/constant_system.dart b/sdk/lib/_internal/compiler/implementation/constant_system.dart
index b2e2b54..4a10d40 100644
--- a/sdk/lib/_internal/compiler/implementation/constant_system.dart
+++ b/sdk/lib/_internal/compiler/implementation/constant_system.dart
@@ -6,13 +6,11 @@
abstract class Operation {
String get name;
- bool isUserDefinable();
}
abstract class UnaryOperation extends Operation {
/** Returns [:null:] if it was unable to fold the operation. */
Constant fold(Constant constant);
- apply(value);
}
abstract class BinaryOperation extends Operation {
diff --git a/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart b/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
index a1067c3..64b6003 100644
--- a/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
+++ b/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
@@ -8,7 +8,6 @@
class BitNotOperation implements UnaryOperation {
final String name = '~';
- bool isUserDefinable() => true;
const BitNotOperation();
Constant fold(Constant constant) {
if (constant.isInt()) {
@@ -17,12 +16,10 @@
}
return null;
}
- apply(value) => ~value;
}
class NegateOperation implements UnaryOperation {
final String name = 'negate';
- bool isUserDefinable() => true;
const NegateOperation();
Constant fold(Constant constant) {
if (constant.isInt()) {
@@ -35,12 +32,10 @@
}
return null;
}
- apply(value) => -value;
}
class NotOperation implements UnaryOperation {
final String name = '!';
- bool isUserDefinable() => true;
const NotOperation();
Constant fold(Constant constant) {
if (constant.isBool()) {
@@ -49,14 +44,12 @@
}
return null;
}
- apply(value) => !value;
}
/**
* Operations that only work if both arguments are integers.
*/
abstract class BinaryBitOperation implements BinaryOperation {
- bool isUserDefinable() => true;
const BinaryBitOperation();
Constant fold(Constant left, Constant right) {
if (left.isInt() && right.isInt()) {
@@ -116,7 +109,6 @@
}
abstract class BinaryBoolOperation implements BinaryOperation {
- bool isUserDefinable() => false;
const BinaryBoolOperation();
Constant fold(Constant left, Constant right) {
if (left.isBool() && right.isBool()) {
@@ -146,7 +138,6 @@
}
abstract class ArithmeticNumOperation implements BinaryOperation {
- bool isUserDefinable() => true;
const ArithmeticNumOperation();
Constant fold(Constant left, Constant right) {
if (left.isNum() && right.isNum()) {
@@ -228,7 +219,6 @@
class AddOperation implements BinaryOperation {
final String name = '+';
- bool isUserDefinable() => true;
const AddOperation();
Constant fold(Constant left, Constant right) {
if (left.isInt() && right.isInt()) {
@@ -249,7 +239,6 @@
}
abstract class RelationalNumOperation implements BinaryOperation {
- bool isUserDefinable() => true;
const RelationalNumOperation();
Constant fold(Constant left, Constant right) {
if (left.isNum() && right.isNum()) {
@@ -294,7 +283,6 @@
class EqualsOperation implements BinaryOperation {
final String name = '==';
- bool isUserDefinable() => true;
const EqualsOperation();
Constant fold(Constant left, Constant right) {
if (left.isNum() && right.isNum()) {
@@ -317,7 +305,6 @@
class IdentityOperation implements BinaryOperation {
final String name = '===';
- bool isUserDefinable() => false;
const IdentityOperation();
BoolConstant fold(Constant left, Constant right) {
// In order to preserve runtime semantics which says that NaN !== NaN don't
diff --git a/sdk/lib/_internal/compiler/implementation/constants.dart b/sdk/lib/_internal/compiler/implementation/constants.dart
index 3e15ab8..d030524 100644
--- a/sdk/lib/_internal/compiler/implementation/constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/constants.dart
@@ -123,10 +123,6 @@
return compiler.typesTask.nullType;
}
- void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) {
- buffer.write(JsNull);
- }
-
// The magic constant has no meaning. It is just a random value.
int get hashCode => 785965825;
DartString toDartString() => const LiteralDartString("null");
@@ -337,6 +333,7 @@
final DartType type;
ObjectConstant(this.type);
+
bool isObject() => true;
DartType computeType(Compiler compiler) => type;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 3138995..1ab6de7 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -220,6 +220,9 @@
case 'c':
passThrough('--enable-checked-mode');
break;
+ case 'm':
+ passThrough('--minify');
+ break;
default:
throw 'Internal error: "$shortOption" did not match';
}
@@ -239,7 +242,7 @@
List<String> arguments = <String>[];
List<OptionHandler> handlers = <OptionHandler>[
- new OptionHandler('-[chv?]+', handleShortOptions),
+ new OptionHandler('-[chvm?]+', handleShortOptions),
new OptionHandler('--throw-on-error',
(_) => diagnosticHandler.throwOnError = true),
new OptionHandler('--suppress-warnings',
@@ -252,7 +255,7 @@
new OptionHandler('--library-root=.+', setLibraryRoot),
new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
new OptionHandler('--allow-mock-compilation', passThrough),
- new OptionHandler('--minify', passThrough),
+ new OptionHandler('--minify|-m', passThrough),
new OptionHandler('--force-strip=.*', setStrip),
new OptionHandler('--disable-diagnostic-colors',
(_) => diagnosticHandler.enableColors = false),
@@ -473,6 +476,7 @@
Common options:
-o <file> Generate the output into <file>.
-c Insert runtime type checks and enable assertions (checked mode).
+ -m Generate minified output.
-h Display this message (add -v for information about all options).''');
}
@@ -489,6 +493,9 @@
-c, --enable-checked-mode, --checked
Insert runtime type checks and enable assertions (checked mode).
+ -m, --minify
+ Generate minified output.
+
-h, /h, /?, --help
Display this message (add -v for information about all options).
@@ -517,9 +524,6 @@
Skip analysis of method bodies and field initializers. This option implies
--analyze-only.
- --minify
- Generate minified output.
-
--suppress-warnings
Do not display any warnings.
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 836d999..2ea2382 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -224,8 +224,6 @@
}
void codegen(CodegenWorkItem work) { }
- void processNativeClasses(Enqueuer world,
- Iterable<LibraryElement> libraries) { }
bool isUserLibrary(LibraryElement lib) {
final INTERNAL_HELPERS = [
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index be1ffda..fec7db6 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -370,8 +370,6 @@
compiler.cancel(reason, node: node);
}
- void unreachable() { internalError('Unreachable case'); }
-
visit(Node node) => (node == null) ? null : node.accept(this);
visitNode(Node node) { node.visitChildren(this); } // We must go deeper.
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index cd9dff9..a4603f0 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -1249,11 +1249,25 @@
this.moreSpecificVisitor, this.subtypeVisitor,
this.potentialSubtypeVisitor);
- /** Returns true if t is more specific than s */
+ /** Returns true if [t] is more specific than [s]. */
bool isMoreSpecific(DartType t, DartType s) {
return moreSpecificVisitor.isMoreSpecific(t, s);
}
+ /**
+ * Returns the most specific type of [t] and [s] or `null` if neither is more
+ * specific than the other.
+ */
+ DartType getMostSpecific(DartType t, DartType s) {
+ if (isMoreSpecific(t, s)) {
+ return t;
+ } else if (isMoreSpecific(s, t)) {
+ return s;
+ } else {
+ return null;
+ }
+ }
+
/** Returns true if t is a subtype of s */
bool isSubtype(DartType t, DartType s) {
return subtypeVisitor.isSubtype(t, s);
@@ -1652,3 +1666,97 @@
return super.isSubtype(t, s);
}
}
+
+/// Visitor used to compute an instantiation of a generic type that is more
+/// specific than a given type.
+///
+/// The visitor tries to compute constraints for all type variables in the
+/// visited type by structurally matching it with the argument type. If the
+/// constraints are too complex or the two types are too different, `false`
+/// is returned. Otherwise, the [constraintMap] holds the valid constraints.
+class MoreSpecificSubtypeVisitor extends DartTypeVisitor<bool, DartType> {
+ final Compiler compiler;
+ Map<TypeVariableType, DartType> constraintMap;
+
+ MoreSpecificSubtypeVisitor(Compiler this.compiler);
+
+ /// Compute an instance of [element] which is more specific than [supertype].
+ /// If no instance is found, `null` is returned.
+ ///
+ /// Note that this computation is a heuristic. It does not find a suggestion
+ /// in all possible cases.
+ InterfaceType computeMoreSpecific(ClassElement element,
+ InterfaceType supertype) {
+ InterfaceType supertypeInstance =
+ element.thisType.asInstanceOf(supertype.element);
+ if (supertypeInstance == null) return null;
+
+ constraintMap = new Map<TypeVariableType, DartType>();
+ element.typeVariables.forEach((TypeVariableType typeVariable) {
+ constraintMap[typeVariable] = compiler.types.dynamicType;
+ });
+ if (supertypeInstance.accept(this, supertype)) {
+ LinkBuilder<DartType> typeArguments = new LinkBuilder<DartType>();
+ element.typeVariables.forEach((TypeVariableType typeVariable) {
+ typeArguments.addLast(constraintMap[typeVariable]);
+ });
+ return element.thisType._createType(typeArguments.toLink());
+ }
+ return null;
+ }
+
+ bool visitType(DartType type, DartType argument) {
+ return compiler.types.isMoreSpecific(type, argument);
+ }
+
+ bool visitTypes(Link<DartType> a, Link<DartType> b) {
+ while (!a.isEmpty && !b.isEmpty) {
+ if (!a.head.accept(this, b.head)) return false;
+ a = a.tail;
+ b = b.tail;
+ }
+ return a.isEmpty && b.isEmpty;
+ }
+
+ bool visitTypeVariableType(TypeVariableType type, DartType argument) {
+ DartType constraint =
+ compiler.types.getMostSpecific(constraintMap[type], argument);
+ constraintMap[type] = constraint;
+ return constraint != null;
+ }
+
+ bool visitFunctionType(FunctionType type, DartType argument) {
+ if (argument is FunctionType) {
+ if (type.parameterTypes.slowLength() !=
+ argument.parameterTypes.slowLength()) {
+ return false;
+ }
+ if (type.optionalParameterTypes.slowLength() !=
+ argument.optionalParameterTypes.slowLength()) {
+ return false;
+ }
+ if (type.namedParameters != argument.namedParameters) {
+ return false;
+ }
+
+ if (!type.returnType.accept(this, argument.returnType)) return false;
+ if (visitTypes(type.parameterTypes, argument.parameterTypes)) {
+ return false;
+ }
+ if (visitTypes(type.optionalParameterTypes,
+ argument.optionalParameterTypes)) {
+ return false;
+ }
+ return visitTypes(type.namedParameterTypes, argument.namedParameterTypes);
+ }
+ return false;
+ }
+
+ bool visitGenericType(GenericType type, DartType argument) {
+ if (argument is GenericType) {
+ if (type.element != argument.element) return false;
+ return visitTypes(type.typeArguments, argument.typeArguments);
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 52c6b30..f06f740 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -30,6 +30,8 @@
import '../ordered_typeset.dart' show OrderedTypeSet;
+import 'visitor.dart' show ElementVisitor;
+
const int STATE_NOT_STARTED = 0;
const int STATE_STARTED = 1;
const int STATE_DONE = 2;
@@ -257,6 +259,8 @@
FunctionElement get targetConstructor;
void diagnose(Element context, DiagnosticListener listener);
+
+ accept(ElementVisitor visitor);
}
class Elements {
@@ -580,13 +584,6 @@
return false;
}
- static bool switchStatementHasDefault(SwitchStatement node) {
- for (SwitchCase switchCase in node.cases) {
- if (switchCase.isDefaultCase) return true;
- }
- return false;
- }
-
static bool isUnusedLabel(LabeledStatement node, TreeElements elements) {
Node body = node.statement;
TargetElement element = elements[body];
@@ -657,12 +654,18 @@
Link<Element> get exports;
/**
- * [:true:] if this library is part of the platform, that is its canonical
+ * [:true:] if this library is part of the platform, that is, its canonical
* uri has the scheme 'dart'.
*/
bool get isPlatformLibrary;
/**
+ * [:true:] if this library is from a package, that is, its canonical uri has
+ * the scheme 'package'.
+ */
+ bool get isPackageLibrary;
+
+ /**
* [:true:] if this library is a platform library whose path starts with
* an underscore.
*/
@@ -905,16 +908,11 @@
Element lookupSuperMemberInLibrary(String memberName,
LibraryElement library);
- Element lookupSuperInterfaceMember(String memberName,
- LibraryElement fromLibrary);
-
Element validateConstructorLookupResults(Selector selector,
Element result,
Element noMatch(Element));
Element lookupConstructor(Selector selector, [Element noMatch(Element)]);
- Element lookupFactoryConstructor(Selector selector,
- [Element noMatch(Element)]);
void forEachMember(void f(ClassElement enclosingClass, Element member),
{bool includeBackendMembers: false,
@@ -990,3 +988,5 @@
MetadataAnnotation ensureResolved(Compiler compiler);
}
+
+abstract class VoidElement extends Element {}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index b53316f..215b989 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -31,7 +31,9 @@
import '../ordered_typeset.dart' show OrderedTypeSet;
-class ElementX implements Element {
+import 'visitor.dart' show ElementVisitor;
+
+abstract class ElementX implements Element {
static int elementHashCode = 0;
final String name;
@@ -285,8 +287,6 @@
FunctionElement asFunctionElement() => null;
- static bool isInvalid(Element e) => e == null || e.isErroneous();
-
bool get isAbstract => modifiers.isAbstract();
bool isForeign(Compiler compiler) => getLibrary() == compiler.foreignLibrary;
@@ -356,6 +356,8 @@
String get message => '${messageKind.message(messageArguments)}';
String toString() => '<$name: $message>';
+
+ accept(ElementVisitor visitor) => visitor.visitErroneousElement(this);
}
/// A message attached to a [WarnOnUseElementX].
@@ -416,6 +418,8 @@
}
return unwrapped;
}
+
+ accept(ElementVisitor visitor) => visitor.visitWarnOnUseElement(this);
}
/**
@@ -483,6 +487,8 @@
});
}
}
+
+ accept(ElementVisitor visitor) => visitor.visitAmbiguousElement(this);
}
class ScopeX {
@@ -637,6 +643,8 @@
if (this == other) return 0;
return '${script.uri}'.compareTo('${other.script.uri}');
}
+
+ accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this);
}
class Importers {
@@ -975,7 +983,9 @@
Scope buildScope() => new LibraryScope(this);
- bool get isPlatformLibrary => canonicalUri.scheme == "dart";
+ bool get isPlatformLibrary => canonicalUri.scheme == 'dart';
+
+ bool get isPackageLibrary => canonicalUri.scheme == 'package';
bool get isInternalLibrary =>
isPlatformLibrary && canonicalUri.path.startsWith('_');
@@ -994,6 +1004,8 @@
if (this == other) return 0;
return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
}
+
+ accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
}
class PrefixElementX extends ElementX implements PrefixElement {
@@ -1013,6 +1025,8 @@
void addImport(Element element, Import import, DiagnosticListener listener) {
importScope.addImport(this, element, import, listener);
}
+
+ accept(ElementVisitor visitor) => visitor.visitPrefixElement(this);
}
class TypedefElementX extends ElementX implements TypedefElement {
@@ -1096,6 +1110,8 @@
computeType(compiler).accept(visitor, null);
hasBeenCheckedForCycles = true;
}
+
+ accept(ElementVisitor visitor) => visitor.visitTypedefElement(this);
}
class VariableElementX extends ElementX implements VariableElement {
@@ -1111,6 +1127,12 @@
: this.variables = variables,
super(name, kind, variables.enclosingElement);
+ VariableElementX.synthetic(String name,
+ ElementKind kind,
+ Element enclosing) :
+ variables = null,
+ super(name, kind, enclosing);
+
Node parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
VariableDefinitions definitions = variables.parseNode(listener);
@@ -1133,13 +1155,13 @@
return variables.computeType(compiler);
}
- DartType get type => variables.type;
-
bool isInstanceMember() => variables.isInstanceMember();
// Note: cachedNode.getBeginToken() will not be correct in all
// cases, for example, for function typed parameters.
Token position() => findMyName(variables.position());
+
+ accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
}
/**
@@ -1163,6 +1185,8 @@
}
return super.computeType(compiler);
}
+
+ accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
}
// This element represents a list of variable or field declaration.
@@ -1231,6 +1255,8 @@
bool isInstanceMember() {
return isMember() && !modifiers.isStatic();
}
+
+ accept(ElementVisitor visitor) => visitor.visitVariableListElement(this);
}
class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
@@ -1282,6 +1308,13 @@
bool isInstanceMember() {
return isMember() && !modifiers.isStatic();
}
+
+ accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);
+
+ bool get isAbstract {
+ return getter != null && getter.isAbstract
+ || setter != null && setter.isAbstract;
+ }
}
// TODO(johnniwinther): [FunctionSignature] should be merged with
@@ -1549,6 +1582,8 @@
(isFunction() || isAccessor()) &&
_hasNoBody;
}
+
+ accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
}
class ConstructorBodyElementX extends FunctionElementX
@@ -1578,6 +1613,8 @@
}
Token position() => constructor.position();
+
+ accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);
}
/**
@@ -1626,15 +1663,21 @@
get declaration => this;
get implementation => this;
get defaultImplementation => this;
+
+ accept(ElementVisitor visitor) {
+ return visitor.visitFunctionElement(this);
+ }
}
-class VoidElementX extends ElementX {
+class VoidElementX extends ElementX implements VoidElement {
VoidElementX(Element enclosing) : super('void', ElementKind.VOID, enclosing);
DartType computeType(compiler) => compiler.types.voidType;
Node parseNode(_) {
throw 'internal error: parseNode on void';
}
bool impliesType() => true;
+
+ accept(ElementVisitor visitor) => visitor.visitVoidElement(this);
}
class TypeDeclarationElementX {
@@ -1730,11 +1773,10 @@
bool get isUnnamedMixinApplication => false;
- // TODO(johnniwinther): Add [thisType] getter similar to [rawType].
- InterfaceType computeType(Compiler compiler) {
+ void computeThisAndRawType(Compiler compiler, Link<DartType> typeVariables) {
if (thisType == null) {
if (origin == null) {
- Link<DartType> parameters = computeTypeParameters(compiler);
+ Link<DartType> parameters = typeVariables;
thisType = new InterfaceType(this, parameters);
if (parameters.isEmpty) {
rawTypeCache = thisType;
@@ -1751,6 +1793,13 @@
rawTypeCache = origin.rawType;
}
}
+ }
+
+ // TODO(johnniwinther): Add [thisType] getter similar to [rawType].
+ InterfaceType computeType(Compiler compiler) {
+ if (thisType == null) {
+ computeThisAndRawType(compiler, computeTypeParameters(compiler));
+ }
return thisType;
}
@@ -1832,22 +1881,6 @@
return null;
}
- Element lookupSuperInterfaceMember(String memberName,
- LibraryElement fromLibrary) {
- bool isPrivate = isPrivateName(memberName);
- for (InterfaceType t in interfaces) {
- ClassElement cls = t.element;
- Element e = cls.lookupLocalMember(memberName);
- if (e == null) continue;
- // Private members from a different library are not visible.
- if (isPrivate && !identical(fromLibrary, e.getLibrary())) continue;
- // Static members are not inherited.
- if (e.modifiers.isStatic()) continue;
- return e;
- }
- return null;
- }
-
/**
* Find the first member in the class chain with the given [selector].
*
@@ -1968,13 +2001,6 @@
return validateConstructorLookupResults(selector, result, noMatch);
}
- Element lookupFactoryConstructor(Selector selector,
- [Element noMatch(Element)]) {
- String constructorName = selector.name;
- Element result = localLookup(constructorName);
- return validateConstructorLookupResults(selector, result, noMatch);
- }
-
Link<Element> get constructors {
// TODO(ajohnsen): See if we can avoid this method at some point.
Link<Element> result = const Link<Element>();
@@ -2256,10 +2282,16 @@
Link<DartType> computeTypeParameters(Compiler compiler) {
NamedMixinApplication named = node.asNamedMixinApplication();
- if (named == null) return const Link<DartType>();
+ if (named == null) {
+ throw new SpannableAssertionFailure(node,
+ "Type variables on unnamed mixin applications must be set on "
+ "creation.");
+ }
return TypeDeclarationElementX.createTypeVariables(
this, named.typeParameters);
}
+
+ accept(ElementVisitor visitor) => visitor.visitMixinApplicationElement(this);
}
class LabelElementX extends ElementX implements LabelElement {
@@ -2296,6 +2328,8 @@
Token position() => label.getBeginToken();
String toString() => "${labelName}:";
+
+ accept(ElementVisitor visitor) => visitor.visitLabelElement(this);
}
// Represents a reference to a statement or switch-case, either by label or the
@@ -2324,6 +2358,8 @@
Token position() => statement.getBeginToken();
String toString() => statement.toString();
+
+ accept(ElementVisitor visitor) => visitor.visitTargetElement(this);
}
class TypeVariableElementX extends ElementX implements TypeVariableElement {
@@ -2331,7 +2367,7 @@
TypeVariableType type;
DartType bound;
- TypeVariableElementX(name, Element enclosing, this.cachedNode,
+ TypeVariableElementX(String name, Element enclosing, this.cachedNode,
[this.type, this.bound])
: super(name, ElementKind.TYPE_VARIABLE, enclosing);
@@ -2342,6 +2378,8 @@
String toString() => "${enclosingElement.toString()}.${name}";
Token position() => cachedNode.getBeginToken();
+
+ accept(ElementVisitor visitor) => visitor.visitTypeVariableElement(this);
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
new file mode 100644
index 0000000..f8f1377
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
@@ -0,0 +1,50 @@
+// 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
+// BSD-style license that can be found in the LICENSE file.
+
+library visitor;
+
+import 'elements.dart';
+import '../ssa/ssa.dart'
+ show InterceptedElement;
+import '../closure.dart'
+ show ThisElement,
+ BoxElement,
+ BoxFieldElement,
+ ClosureClassElement,
+ ClosureFieldElement;
+
+abstract class ElementVisitor<R> {
+ R visit(Element e) => e.accept(this);
+
+ R visitElement(Element e);
+ R visitErroneousElement(ErroneousElement e) => visitFunctionElement(e);
+ R visitWarnOnUseElement(WarnOnUseElement e) => visitElement(e);
+ R visitAmbiguousElement(AmbiguousElement e) => visitElement(e);
+ R visitScopeContainerElement(ScopeContainerElement e) => visitElement(e);
+ R visitCompilationUnitElement(CompilationUnitElement e) => visitElement(e);
+ R visitLibraryElement(LibraryElement e) => visitScopeContainerElement(e);
+ R visitPrefixElement(PrefixElement e) => visitElement(e);
+ R visitTypedefElement(TypedefElement e) => visitElement(e);
+ R visitVariableElement(VariableElement e) => visitElement(e);
+ R visitFieldParameterElement(FieldParameterElement e) => visitElement(e);
+ R visitVariableListElement(VariableListElement e) => visitElement(e);
+ R visitAbstractFieldElement(AbstractFieldElement e) => visitElement(e);
+ R visitFunctionElement(FunctionElement e) => visitElement(e);
+ R visitConstructorBodyElement(ConstructorBodyElement e) => visitElement(e);
+ R visitClassElement(ClassElement e) => visitScopeContainerElement(e);
+ R visitTypeDeclarationElement(TypeDeclarationElement e) => visitElement(e);
+ R visitMixinApplicationElement(MixinApplicationElement e) {
+ visitClassElement(e);
+ }
+ R visitVoidElement(VoidElement e) => visitElement(e);
+ R visitLabelElement(LabelElement e) => visitElement(e);
+ R visitTargetElement(TargetElement e) => visitElement(e);
+ R visitTypeVariableElement(TypeVariableElement e) => visitElement(e);
+ R visitInterceptedElement(InterceptedElement e) => visitElement(e);
+ R visitThisElement(ThisElement e) => visitElement(e);
+ R visitBoxElement(BoxElement e) => visitElement(e);
+ R visitBoxFieldElement(BoxFieldElement e) => visitElement(e);
+ R visitClosureClassElement(ClosureClassElement e) => visitClassElement(e);
+ R visitClosureFieldElement(ClosureFieldElement e) => visitVariableElement(e);
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
index 3b75903..cb204ae 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
@@ -134,7 +134,14 @@
// The set of [TypeInformation] where the traced container could
// flow in, and operations done on them.
- final Setlet<TypeInformation> allUsers = new Setlet<TypeInformation>();
+ final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
+
+ // Work list that gets populated with [TypeInformation] that could
+ // contain the container.
+ final List<TypeInformation> workList = <TypeInformation>[];
+
+ // The current [TypeInformation] in the analysis.
+ TypeInformation currentUser;
// The list of found assignments to the container.
final List<TypeInformation> assignments = <TypeInformation>[];
@@ -148,22 +155,23 @@
ContainerTracerVisitor(this.container, inferrer)
: this.inferrer = inferrer, this.compiler = inferrer.compiler;
+ void addNewEscapeInformation(TypeInformation info) {
+ if (flowsInto.contains(info)) return;
+ flowsInto.add(info);
+ workList.add(info);
+ }
+
List<TypeInformation> run() {
// Collect the [TypeInformation] where the container can flow in,
// as well as the operations done on all these [TypeInformation]s.
- List<TypeInformation> workList = <TypeInformation>[];
- allUsers.add(container);
- workList.add(container);
+ addNewEscapeInformation(container);
while (!workList.isEmpty) {
- TypeInformation user = workList.removeLast();
- user.users.forEach((TypeInformation info) {
- if (allUsers.contains(info)) return;
- allUsers.add(info);
+ currentUser = workList.removeLast();
+ currentUser.users.forEach((TypeInformation info) {
analyzedElements.add(info.owner);
- if (info.reachedBy(user, inferrer)) {
- workList.add(info);
- }
+ info.accept(this);
});
+ if (!continueAnalyzing) break;
if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
bailout('Too many users');
break;
@@ -171,13 +179,6 @@
}
if (continueAnalyzing) {
- for (TypeInformation info in allUsers) {
- info.accept(this);
- if (!continueAnalyzing) break;
- }
- }
-
- if (continueAnalyzing) {
if (!callsGrowableMethod && container.inferredLength == null) {
container.inferredLength = container.originalLength;
}
@@ -196,10 +197,18 @@
callsGrowableMethod = true;
}
- visitNarrowTypeInformation(NarrowTypeInformation info) {}
- visitPhiElementTypeInformation(PhiElementTypeInformation info) {}
+ visitNarrowTypeInformation(NarrowTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
+ visitPhiElementTypeInformation(PhiElementTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
visitElementInContainerTypeInformation(
- ElementInContainerTypeInformation info) {}
+ ElementInContainerTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
visitContainerTypeInformation(ContainerTypeInformation info) {
if (container != info) {
@@ -214,17 +223,19 @@
}
visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
- analyzedElements.add(info.caller);
Element called = info.calledElement;
if (called.isForeign(compiler) && called.name == 'JS') {
bailout('Used in JS ${info.call}');
}
+ if (inferrer.types.getInferredTypeOf(called) == currentUser) {
+ addNewEscapeInformation(info);
+ }
}
visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
Selector selector = info.selector;
String selectorName = selector.name;
- if (allUsers.contains(info.receiver)) {
+ if (currentUser == info.receiver) {
if (!okSelectorsSet.contains(selectorName)) {
if (selector.isCall()) {
int positionalLength = info.arguments.positional.length;
@@ -259,6 +270,13 @@
bailout('Passed to a closure');
return;
}
+
+ if (info.targets
+ .map((element) => inferrer.types.getInferredTypeOf(element))
+ .any((other) => other == currentUser)) {
+ addNewEscapeInformation(info);
+ }
+
}
bool isClosure(Element element) {
@@ -274,5 +292,6 @@
if (compiler.backend.isNeededForReflection(info.element)) {
bailout('Escape in reflection');
}
+ addNewEscapeInformation(info);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 2dbdc3b..85f9ed5 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -238,11 +238,6 @@
bool inLoop);
/**
- * Returns the callers of [elements].
- */
- Iterable<Element> getCallersOf(Element element);
-
- /**
* Notifies to the inferrer that [analyzedElement] can have return
* type [newType]. [currentType] is the type the [InferrerVisitor]
* currently found.
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 2598dd3..06d0b06 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -108,10 +108,6 @@
users = const <TypeInformation>[];
}
- bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
- return true;
- }
-
/// Reset the analysis of this node by making its type empty.
void reset(TypeGraphInferrerEngine inferrer) {
if (abandonInferencing) return;
@@ -439,10 +435,6 @@
Iterable<Element> get callees => [calledElement.implementation];
- bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
- return info == inferrer.types.getInferredTypeOf(calledElement);
- }
-
accept(TypeInformationVisitor visitor) {
return visitor.visitStaticCallSiteTypeInformation(this);
}
@@ -680,12 +672,6 @@
super.removeAndClearReferences(inferrer);
}
- bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
- return targets
- .map((element) => inferrer.types.getInferredTypeOf(element))
- .any((other) => other == info);
- }
-
String toString() => 'Call site $call on ${receiver.type} $type';
accept(TypeInformationVisitor visitor) {
diff --git a/sdk/lib/_internal/compiler/implementation/js/builder.dart b/sdk/lib/_internal/compiler/implementation/js/builder.dart
index e02bd00..8958b50 100644
--- a/sdk/lib/_internal/compiler/implementation/js/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/builder.dart
@@ -90,12 +90,6 @@
return new Fun(parameters.map(toParameter).toList(), block(body));
}
- Assignment assign(Expression leftHandSide, Expression value) {
- return new Assignment(leftHandSide, value);
- }
-
- Expression undefined() => new Prefix('void', new LiteralNumber('0'));
-
VariableDeclarationList defineVar(String name, [initializer]) {
if (initializer != null) {
initializer = toExpression(initializer);
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index afc27de..e6268a3 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -481,12 +481,6 @@
return callWith(arguments);
}
- Expression equals(expression) => binary('==', expression);
-
- Expression strictEquals(expression) => binary('===', expression);
-
- Expression notEquals(expression) => binary('!=', expression);
-
Expression operator +(expression) => binary('+', expression);
Expression operator -(expression) => binary('-', expression);
@@ -503,10 +497,6 @@
return new Binary(operator, this, js.toExpression(expression));
}
- Expression assign(expression) {
- return new Assignment(this, js.toExpression(expression));
- }
-
Expression update(String operator, expression) {
return new Assignment.compound(this, operator, js.toExpression(expression));
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 17c53c0..384ca4e 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -974,10 +974,6 @@
enqueueInResolution(getTraceFromException(), elements);
}
- void registerSetRuntimeType(TreeElements elements) {
- enqueueInResolution(getSetRuntimeTypeInfo(), elements);
- }
-
void registerGetRuntimeTypeArgument(TreeElements elements) {
enqueueInResolution(getGetRuntimeTypeArgument(), elements);
enqueueInResolution(getGetTypeArgumentByIndex(), elements);
@@ -1326,8 +1322,12 @@
if (importTag == null) continue;
LibraryElement importedLibrary = library.getLibraryFromTag(tag);
if (importedLibrary != compiler.mirrorsLibrary) continue;
+ MessageKind kind =
+ compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
+ ? MessageKind.MIRROR_IMPORT
+ : MessageKind.MIRROR_IMPORT_NO_USAGE;
compiler.withCurrentElement(library, () {
- compiler.reportInfo(importTag, MessageKind.MIRROR_IMPORT);
+ compiler.reportInfo(importTag, kind);
});
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
index e966bc2..206b3df 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
@@ -30,7 +30,6 @@
const JavaScriptBinaryBitOperation(this.dartBitOperation);
- bool isUserDefinable() => dartBitOperation.isUserDefinable();
String get name => dartBitOperation.name;
Constant fold(Constant left, Constant right) {
@@ -79,7 +78,6 @@
const JavaScriptNegateOperation();
- bool isUserDefinable() => dartNegateOperation.isUserDefinable();
String get name => dartNegateOperation.name;
Constant fold(Constant constant) {
@@ -91,7 +89,6 @@
}
return dartNegateOperation.fold(constant);
}
- apply(value) => -value;
}
class JavaScriptBinaryArithmeticOperation implements BinaryOperation {
@@ -99,7 +96,6 @@
const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation);
- bool isUserDefinable() => dartArithmeticOperation.isUserDefinable();
String get name => dartArithmeticOperation.name;
Constant fold(Constant left, Constant right) {
@@ -116,7 +112,6 @@
const JavaScriptIdentityOperation();
- bool isUserDefinable() => dartIdentityOperation.isUserDefinable();
String get name => dartIdentityOperation.name;
BoolConstant fold(Constant left, Constant right) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index d137184..25f86da 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -298,8 +298,6 @@
}
}
- bool isReserved(String name) => name == isolateName;
-
String constantName(Constant constant) {
// In the current implementation it doesn't make sense to give names to
// function constants since the function-implementation itself serves as
@@ -520,13 +518,6 @@
return '$setterPrefix$name';
}
- String publicGetterName(String name) {
- // We dynamically create getters from the field-name. The getter name must
- // therefore be derived from the instance field-name.
- String fieldName = getMappedInstanceName(name);
- return '$getterPrefix$fieldName';
- }
-
String getterNameFromAccessorName(String name) {
// We dynamically create getters from the field-name. The getter name must
// therefore be derived from the instance field-name.
@@ -828,9 +819,6 @@
String getNameOfGlobalField(VariableElement field) => getNameX(field);
- // TODO(ahe): Remove this method. Use get getNameOfMember instead.
- String getNameOfGlobalFunction(FunctionElement element) => getNameX(element);
-
/// Returns true if [element] is stored on current isolate ('$'). We intend
/// to store only mutable static state in [currentIsolate], constants are
/// stored in 'C', and functions, accessors, classes, etc. are stored in one
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index 4a4d495..9488f91 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -498,7 +498,6 @@
// Unnamed mixin application classes do not need substitutions, because they
// are never instantiated and their checks are overwritten by the class that
// they are mixed into.
- if (cls.isUnnamedMixinApplication) return null;
InterfaceType type = cls.computeType(compiler);
InterfaceType target = type.asInstanceOf(check);
Link<DartType> typeVariables = cls.typeVariables;
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 60db17c..ac52424 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -748,20 +748,6 @@
classElement, properties, additionalProperties[classElement]);
}
- int _selectorRank(Selector selector) {
- int arity = selector.argumentCount * 3;
- if (selector.isGetter()) return arity + 2;
- if (selector.isSetter()) return arity + 1;
- return arity;
- }
-
- int _compareSelectorNames(Selector selector1, Selector selector2) {
- String name1 = selector1.name.toString();
- String name2 = selector2.name.toString();
- if (name1 != name2) return Comparable.compare(name1, name2);
- return _selectorRank(selector1) - _selectorRank(selector2);
- }
-
/**
* Return a function that returns true if its argument is a class
* that needs to be emitted.
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index 955acd0..0d521bb 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -120,9 +120,6 @@
bool haveSameTypeVariables(ClassElement a, ClassElement b) {
if (a.isClosure()) return true;
- if (b.isUnnamedMixinApplication) {
- return false;
- }
return a.typeVariables == b.typeVariables;
}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index 7dfd10c..453882a 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -456,7 +456,8 @@
Map<Uri, LibraryMirror> get libraries {
_ensureLibraries();
return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
- (library) => !library._element.isInternalLibrary);
+ (library) => new bool.fromEnvironment("list_all_libraries") ||
+ !library._element.isInternalLibrary);
}
Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors_used.dart b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
index 05ddb81..fad167e 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
@@ -105,11 +105,11 @@
void analyzeUsage(LibraryElement mainApp) {
if (compiler.mirrorsLibrary == null) return;
measure(analyzer.run);
- List /*<String|Element>*/ symbols = analyzer.mergedMirrorUsage.symbols;
+ List<String> symbols = analyzer.mergedMirrorUsage.symbols;
List<Element> targets = analyzer.mergedMirrorUsage.targets;
List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets;
compiler.backend.registerMirrorUsage(
- symbols == null ? null : new Set/*<String|Element>*/.from(symbols),
+ symbols == null ? null : new Set<String>.from(symbols),
targets == null ? null : new Set<Element>.from(targets),
metaTargets == null ? null : new Set<Element>.from(metaTargets));
librariesWithUsage = analyzer.librariesWithUsage;
@@ -146,17 +146,17 @@
value, mapper.constantToNodeMap);
if (named.name.source == 'symbols') {
- analyzer.cachedValues[value] =
+ analyzer.cachedStrings[value] =
builder.convertToListOfStrings(
builder.convertConstantToUsageList(value, onlyStrings: true));
} else if (named.name.source == 'targets') {
- analyzer.cachedValues[value] =
+ analyzer.cachedElements[value] =
builder.resolveUsageList(builder.convertConstantToUsageList(value));
} else if (named.name.source == 'metaTargets') {
- analyzer.cachedValues[value] =
+ analyzer.cachedElements[value] =
builder.resolveUsageList(builder.convertConstantToUsageList(value));
} else if (named.name.source == 'override') {
- analyzer.cachedValues[value] =
+ analyzer.cachedElements[value] =
builder.resolveUsageList(builder.convertConstantToUsageList(value));
}
}
@@ -168,13 +168,15 @@
final MirrorUsageAnalyzerTask task;
List<LibraryElement> wildcard;
final Set<LibraryElement> librariesWithUsage;
- final Map<Constant, List> cachedValues;
+ final Map<Constant, List<String>> cachedStrings;
+ final Map<Constant, List<Element>> cachedElements;
MirrorUsage mergedMirrorUsage;
MirrorUsageAnalyzer(Compiler compiler, this.task)
: compiler = compiler,
librariesWithUsage = new Set<LibraryElement>(),
- cachedValues = new Map<Constant, List>();
+ cachedStrings = new Map<Constant, List<String>>(),
+ cachedElements = new Map<Constant, List<Element>>();
/// Collect and merge all @MirrorsUsed annotations. As a side-effect, also
/// compute which libraries have the annotation (which is used by
@@ -304,7 +306,7 @@
return a;
}
// TODO(ahe): Test the following cases.
- List /*<String|Element>*/ symbols = a.symbols;
+ List<String> symbols = a.symbols;
if (symbols == null) {
symbols = b.symbols;
} else if (b.symbols != null) {
@@ -340,16 +342,16 @@
'override');
return new MirrorUsage(
- cachedValues[fields[symbolsField]],
- cachedValues[fields[targetsField]],
- cachedValues[fields[metaTargetsField]],
- cachedValues[fields[overrideField]]);
+ cachedStrings[fields[symbolsField]],
+ cachedElements[fields[targetsField]],
+ cachedElements[fields[metaTargetsField]],
+ cachedElements[fields[overrideField]]);
}
}
/// Used to represent a resolved MirrorsUsed constant.
class MirrorUsage {
- final List /* <String|Element> */ symbols;
+ final List<String> symbols;
final List<Element> targets;
final List<Element> metaTargets;
final List<Element> override;
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index bb42db9..b4e8016 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -1045,17 +1045,6 @@
return nativeTagInfo;
}
-bool isOverriddenMethod(FunctionElement element,
- ClassElement cls,
- NativeEmitter nativeEmitter) {
- List<ClassElement> subtypes = nativeEmitter.subtypes[cls];
- if (subtypes == null) return false;
- for (ClassElement subtype in subtypes) {
- if (subtype.lookupLocalMember(element.name) != null) return true;
- }
- return false;
-}
-
final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
diff --git a/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart b/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
index 6a68357..26a9e9f 100644
--- a/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
+++ b/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
@@ -1,203 +1,203 @@
-// 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
-// BSD-style license that can be found in the LICENSE file.
-
-library resolution.ordered_typeset_builder;
-
-import 'dart2jslib.dart' show Compiler, MessageKind;
-import 'dart_types.dart';
-import 'elements/elements.dart' show ClassElement;
-import 'util/util.dart' show Link, LinkBuilder;
-import 'util/util_implementation.dart' show LinkEntry;
-
-/**
- * An ordered set of the supertypes of a class. The supertypes of a class are
- * ordered by decreasing hierarchy depth and by the order they are extended,
- * mixed in, or implemented.
- *
- * For these classes
- *
- * class A {} // Depth = 1.
- * class B {} // Depth = 1.
- * class C extends B implements A {} // Depth 2.
- *
- * the ordered supertypes are
- *
- * A: [A, Object]
- * B: [B, Object]
- * C: [C, B, A, Object]
- */
-class OrderedTypeSet {
- final List<Link<DartType>> _levels;
- final Link<DartType> types;
- final Link<DartType> _supertypes;
-
- OrderedTypeSet._internal(List<Link<DartType>> this._levels,
- Link<DartType> this.types,
- Link<DartType> this._supertypes);
-
- factory OrderedTypeSet.singleton(DartType type) {
- Link<DartType> types =
- new LinkEntry<DartType>(type, const Link<DartType>());
- List<Link<DartType>> list = new List<Link<DartType>>(1);
- list[0] = types;
- return new OrderedTypeSet._internal(list, types, const Link<DartType>());
- }
-
- /// Creates a new [OrderedTypeSet] for [type] when it directly extends the
- /// class which this set represents. This is for instance used to create the
- /// type set for [ClosureClassElement] which extends [Closure].
- OrderedTypeSet extendClass(InterfaceType type) {
- assert(type.treatAsRaw);
- Link<DartType> extendedTypes =
- new LinkEntry<DartType>(type, types);
- List<Link<DartType>> list = new List<Link<DartType>>(levels + 1);
- for (int i = 0; i < levels; i++) {
- list[i] = _levels[i];
- }
- list[levels] = extendedTypes;
- return new OrderedTypeSet._internal(
- list, extendedTypes, _supertypes.prepend(types.head));
- }
-
- Link<DartType> get supertypes => _supertypes;
-
- int get levels => _levels.length;
-
- int get maxDepth => levels - 1;
-
- Link<DartType> operator [](int index) {
- if (index < levels) {
- return _levels[index];
- }
- return const Link<DartType>();
- }
-
- void forEach(int level, void f(DartType type)) {
- if (level < levels) {
- Link<DartType> pointer = _levels[level];
- Link<DartType> end =
- level > 0 ? _levels[level - 1] : const Link<DartType>();
- while (!identical(pointer, end)) {
- f(pointer.head);
- pointer = pointer.tail;
- }
- }
- }
-
- String toString() => types.toString();
-}
-
-/**
- * Builder for creation an ordered set of the supertypes of a class. The
- * supertypes are ordered by decreasing hierarchy depth and by the order they
- * are extended, mixed in, or implemented.
- *
- * For these classes
- *
- * class A {} // Depth = 1.
- * class B {} // Depth = 1.
- * class C extends B implements A {} // Depth 2.
- *
- * the ordered supertypes are
- *
- * A: [A, Object]
- * B: [B, Object]
- * C: [C, B, A, Object]
- */
-class OrderedTypeSetBuilder {
- Map<int, LinkEntry<DartType>> map = new Map<int, LinkEntry<DartType>>();
- // TODO(15296): Avoid computing this order on the side when member
- // lookup handles multiply inherited members correctly.
- LinkBuilder<DartType> allSupertypes = new LinkBuilder<DartType>();
- int maxDepth = -1;
-
- final ClassElement cls;
-
- OrderedTypeSetBuilder(this.cls);
-
- void add(Compiler compiler, InterfaceType type) {
- if (type.element == cls) {
- if (type.element != compiler.objectClass) {
- allSupertypes.addLast(compiler.objectClass.computeType(compiler));
- }
- _addAtDepth(compiler, type, maxDepth + 1);
- } else {
- if (type.element != compiler.objectClass) {
- allSupertypes.addLast(type);
- }
- _addAtDepth(compiler, type, type.element.hierarchyDepth);
- }
- }
-
- void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {
- LinkEntry<DartType> prev = null;
- LinkEntry<DartType> link = map[depth];
- while (link != null) {
- DartType existingType = link.head;
- if (existingType == type) return;
- if (existingType.element == type.element) {
- compiler.reportError(cls,
- MessageKind.MULTI_INHERITANCE,
- {'thisType': cls.computeType(compiler),
- 'firstType': existingType,
- 'secondType': type});
- return;
- }
- prev = link;
- link = link.tail;
- }
- LinkEntry<DartType> next = new LinkEntry<DartType>(type);
- next.tail = null;
- if (prev == null) {
- map[depth] = next;
- } else {
- prev.tail = next;
- }
- if (depth > maxDepth) {
- maxDepth = depth;
- }
- }
-
- OrderedTypeSet toTypeSet() {
- List<Link<DartType>> levels = new List<Link<DartType>>(maxDepth + 1);
- if (maxDepth < 0) {
- return new OrderedTypeSet._internal(
- levels, const Link<DartType>(), const Link<DartType>());
- }
- Link<DartType> next = const Link<DartType>();
- for (int depth = 0; depth <= maxDepth; depth++) {
- LinkEntry<DartType> first = map[depth];
- if (first == null) {
- levels[depth] = next;
- } else {
- levels[depth] = first;
- LinkEntry<DartType> last = first;
- while (last.tail != null) {
- last = last.tail;
- }
- last.tail = next;
- next = first;
- }
- }
- return new OrderedTypeSet._internal(
- levels, levels.last, allSupertypes.toLink());
- }
-
- String toString() {
- StringBuffer sb = new StringBuffer();
- for (int depth = 0; depth <= maxDepth; depth++) {
- sb.write('$depth: ');
- LinkEntry<DartType> first = map[depth];
- if (first != null) {
- sb.write('${first.head}');
- while (first.tail != null) {
- sb.write(', ${first.tail.head}');
- first = first.tail;
- }
- }
- sb.write('\n');
- }
- return sb.toString();
- }
-}
+// 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
+// BSD-style license that can be found in the LICENSE file.
+
+library resolution.ordered_typeset_builder;
+
+import 'dart2jslib.dart' show Compiler, MessageKind;
+import 'dart_types.dart';
+import 'elements/elements.dart' show ClassElement;
+import 'util/util.dart' show Link, LinkBuilder;
+import 'util/util_implementation.dart' show LinkEntry;
+
+/**
+ * An ordered set of the supertypes of a class. The supertypes of a class are
+ * ordered by decreasing hierarchy depth and by the order they are extended,
+ * mixed in, or implemented.
+ *
+ * For these classes
+ *
+ * class A {} // Depth = 1.
+ * class B {} // Depth = 1.
+ * class C extends B implements A {} // Depth 2.
+ *
+ * the ordered supertypes are
+ *
+ * A: [A, Object]
+ * B: [B, Object]
+ * C: [C, B, A, Object]
+ */
+class OrderedTypeSet {
+ final List<Link<DartType>> _levels;
+ final Link<DartType> types;
+ final Link<DartType> _supertypes;
+
+ OrderedTypeSet._internal(List<Link<DartType>> this._levels,
+ Link<DartType> this.types,
+ Link<DartType> this._supertypes);
+
+ factory OrderedTypeSet.singleton(DartType type) {
+ Link<DartType> types =
+ new LinkEntry<DartType>(type, const Link<DartType>());
+ List<Link<DartType>> list = new List<Link<DartType>>(1);
+ list[0] = types;
+ return new OrderedTypeSet._internal(list, types, const Link<DartType>());
+ }
+
+ /// Creates a new [OrderedTypeSet] for [type] when it directly extends the
+ /// class which this set represents. This is for instance used to create the
+ /// type set for [ClosureClassElement] which extends [Closure].
+ OrderedTypeSet extendClass(InterfaceType type) {
+ assert(type.treatAsRaw);
+ Link<DartType> extendedTypes =
+ new LinkEntry<DartType>(type, types);
+ List<Link<DartType>> list = new List<Link<DartType>>(levels + 1);
+ for (int i = 0; i < levels; i++) {
+ list[i] = _levels[i];
+ }
+ list[levels] = extendedTypes;
+ return new OrderedTypeSet._internal(
+ list, extendedTypes, _supertypes.prepend(types.head));
+ }
+
+ Link<DartType> get supertypes => _supertypes;
+
+ int get levels => _levels.length;
+
+ int get maxDepth => levels - 1;
+
+ Link<DartType> operator [](int index) {
+ if (index < levels) {
+ return _levels[index];
+ }
+ return const Link<DartType>();
+ }
+
+ void forEach(int level, void f(DartType type)) {
+ if (level < levels) {
+ Link<DartType> pointer = _levels[level];
+ Link<DartType> end =
+ level > 0 ? _levels[level - 1] : const Link<DartType>();
+ while (!identical(pointer, end)) {
+ f(pointer.head);
+ pointer = pointer.tail;
+ }
+ }
+ }
+
+ String toString() => types.toString();
+}
+
+/**
+ * Builder for creation an ordered set of the supertypes of a class. The
+ * supertypes are ordered by decreasing hierarchy depth and by the order they
+ * are extended, mixed in, or implemented.
+ *
+ * For these classes
+ *
+ * class A {} // Depth = 1.
+ * class B {} // Depth = 1.
+ * class C extends B implements A {} // Depth 2.
+ *
+ * the ordered supertypes are
+ *
+ * A: [A, Object]
+ * B: [B, Object]
+ * C: [C, B, A, Object]
+ */
+class OrderedTypeSetBuilder {
+ Map<int, LinkEntry<DartType>> map = new Map<int, LinkEntry<DartType>>();
+ // TODO(15296): Avoid computing this order on the side when member
+ // lookup handles multiply inherited members correctly.
+ LinkBuilder<DartType> allSupertypes = new LinkBuilder<DartType>();
+ int maxDepth = -1;
+
+ final ClassElement cls;
+
+ OrderedTypeSetBuilder(this.cls);
+
+ void add(Compiler compiler, InterfaceType type) {
+ if (type.element == cls) {
+ if (type.element != compiler.objectClass) {
+ allSupertypes.addLast(compiler.objectClass.computeType(compiler));
+ }
+ _addAtDepth(compiler, type, maxDepth + 1);
+ } else {
+ if (type.element != compiler.objectClass) {
+ allSupertypes.addLast(type);
+ }
+ _addAtDepth(compiler, type, type.element.hierarchyDepth);
+ }
+ }
+
+ void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {
+ LinkEntry<DartType> prev = null;
+ LinkEntry<DartType> link = map[depth];
+ while (link != null) {
+ DartType existingType = link.head;
+ if (existingType == type) return;
+ if (existingType.element == type.element) {
+ compiler.reportError(cls,
+ MessageKind.MULTI_INHERITANCE,
+ {'thisType': cls.computeType(compiler),
+ 'firstType': existingType,
+ 'secondType': type});
+ return;
+ }
+ prev = link;
+ link = link.tail;
+ }
+ LinkEntry<DartType> next = new LinkEntry<DartType>(type);
+ next.tail = null;
+ if (prev == null) {
+ map[depth] = next;
+ } else {
+ prev.tail = next;
+ }
+ if (depth > maxDepth) {
+ maxDepth = depth;
+ }
+ }
+
+ OrderedTypeSet toTypeSet() {
+ List<Link<DartType>> levels = new List<Link<DartType>>(maxDepth + 1);
+ if (maxDepth < 0) {
+ return new OrderedTypeSet._internal(
+ levels, const Link<DartType>(), const Link<DartType>());
+ }
+ Link<DartType> next = const Link<DartType>();
+ for (int depth = 0; depth <= maxDepth; depth++) {
+ LinkEntry<DartType> first = map[depth];
+ if (first == null) {
+ levels[depth] = next;
+ } else {
+ levels[depth] = first;
+ LinkEntry<DartType> last = first;
+ while (last.tail != null) {
+ last = last.tail;
+ }
+ last.tail = next;
+ next = first;
+ }
+ }
+ return new OrderedTypeSet._internal(
+ levels, levels.last, allSupertypes.toLink());
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int depth = 0; depth <= maxDepth; depth++) {
+ sb.write('$depth: ');
+ LinkEntry<DartType> first = map[depth];
+ if (first != null) {
+ sb.write('${first.head}');
+ while (first.tail != null) {
+ sb.write(', ${first.tail.head}');
+ first = first.tail;
+ }
+ }
+ sb.write('\n');
+ }
+ return sb.toString();
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 3e04dc9..c29501b 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -528,12 +528,6 @@
return new ResolverVisitor(compiler, element, mapping);
}
- void visitBody(ResolverVisitor visitor, Statement body) {
- if (!compiler.analyzeSignaturesOnly) {
- visitor.visit(body);
- }
- }
-
TreeElements resolveField(VariableElement element) {
Node tree = element.parseNode(compiler);
if(element.modifiers.isStatic() && element.variables.isTopLevel()) {
@@ -916,6 +910,25 @@
MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD);
}
}
+
+ if (!cls.isAbstract) {
+ for (DartType supertype in cls.allSupertypes) {
+ // This must have been reported elsewhere.
+ if (!supertype.element.isClass()) continue;
+ ClassElement superclass = supertype.element;
+ superclass.forEachMember((ClassElement holder, Element member) {
+ if (member.isAbstract) {
+ Element mine = cls.lookupMember(member.name);
+ if (mine == null || mine.isAbstract) {
+ compiler.reportWarningCode(
+ cls, MessageKind.UNIMPLEMENTED_METHOD,
+ {'class_name': cls.name, 'member_name': member.name});
+ compiler.reportHint(member, MessageKind.THIS_IS_THE_METHOD, {});
+ }
+ }
+ });
+ }
+ }
}
void checkAbstractField(Element member) {
@@ -1424,16 +1437,6 @@
}
}
- FunctionElement resolveRedirection(FunctionElement constructor,
- FunctionExpression functionNode) {
- if (functionNode.initializers == null) return null;
- Link<Node> link = functionNode.initializers.nodes;
- if (!link.isEmpty && Initializers.isConstructorRedirect(link.head)) {
- return resolveSuperOrThisForSend(constructor, functionNode, link.head);
- }
- return null;
- }
-
/**
* Resolve all initializers of this constructor. In the case of a redirecting
* constructor, the resolved constructor's function element is returned.
@@ -1528,20 +1531,12 @@
compiler.reportFatalError(node, kind, arguments);
}
- void dualError(Node node, DualKind kind, [Map arguments = const {}]) {
- error(node, kind.error, arguments);
- }
-
void warning(Node node, MessageKind kind, [Map arguments = const {}]) {
ResolutionWarning message =
new ResolutionWarning(kind, arguments, compiler.terseDiagnostics);
compiler.reportWarning(node, message);
}
- void dualWarning(Node node, DualKind kind, [Map arguments = const {}]) {
- warning(node, kind.warning, arguments);
- }
-
void cancel(Node node, String message) {
compiler.cancel(message, node: node);
}
@@ -2334,11 +2329,6 @@
visitIn(node.elsePart, new BlockScope(scope));
}
- static bool isLogicalOperator(Identifier op) {
- String str = op.source;
- return (identical(str, '&&') || str == '||' || str == '!');
- }
-
Element resolveSend(Send node) {
Selector selector = resolveSelector(node, null);
if (node.isSuperCall) mapping.superUses.add(node);
@@ -3832,8 +3822,8 @@
DartType supertype = resolveSupertype(element, superMixin.superclass);
Link<Node> link = superMixin.mixins.nodes;
while (!link.isEmpty) {
- supertype = applyMixin(
- supertype, checkMixinType(link.head), link.head);
+ supertype = applyMixin(supertype,
+ checkMixinType(link.head), link.head);
link = link.tail;
}
element.supertype = supertype;
@@ -3929,16 +3919,45 @@
DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
String superName = supertype.name;
String mixinName = mixinType.name;
- ClassElement mixinApplication = new MixinApplicationElementX(
+ MixinApplicationElementX mixinApplication = new MixinApplicationElementX(
"${superName}+${mixinName}",
element.getCompilationUnit(),
compiler.getNextFreeClassId(),
node,
Modifiers.EMPTY); // TODO(kasperl): Should this be abstract?
+ // Create synthetic type variables for the mixin application.
+ LinkBuilder<DartType> typeVariablesBuilder = new LinkBuilder<DartType>();
+ element.typeVariables.forEach((TypeVariableType type) {
+ TypeVariableElementX typeVariableElement = new TypeVariableElementX(
+ type.name, mixinApplication, type.element.parseNode(compiler));
+ TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
+ typeVariablesBuilder.addLast(typeVariable);
+ });
+ Link<DartType> typeVariables = typeVariablesBuilder.toLink();
+ // Setup bounds on the synthetic type variables.
+ Link<DartType> link = typeVariables;
+ element.typeVariables.forEach((TypeVariableType type) {
+ TypeVariableType typeVariable = link.head;
+ TypeVariableElement typeVariableElement = typeVariable.element;
+ typeVariableElement.type = typeVariable;
+ typeVariableElement.bound =
+ type.element.bound.subst(typeVariables, element.typeVariables);
+ link = link.tail;
+ });
+ // Setup this and raw type for the mixin application.
+ mixinApplication.computeThisAndRawType(compiler, typeVariables);
+ // Substitute in synthetic type variables in super and mixin types.
+ supertype = supertype.subst(typeVariables, element.typeVariables);
+ mixinType = mixinType.subst(typeVariables, element.typeVariables);
+
doApplyMixinTo(mixinApplication, supertype, mixinType);
mixinApplication.resolutionState = STATE_DONE;
mixinApplication.supertypeLoadState = STATE_DONE;
- return mixinApplication.computeType(compiler);
+ // Replace the synthetic type variables by the original type variables in
+ // the returned type (which should be the type actually extended).
+ InterfaceType mixinThisType = mixinApplication.computeType(compiler);
+ return mixinThisType.subst(element.typeVariables,
+ mixinThisType.typeArguments);
}
bool isDefaultConstructor(FunctionElement constructor) {
@@ -4135,7 +4154,7 @@
cls.allSupertypesAndSelf =
new OrderedTypeSet.singleton(cls.computeType(compiler));
}
- }
+ }
/**
* Adds [type] and all supertypes of [type] to [allSupertypes] while
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 136a930..463413a 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -22,6 +22,7 @@
LabelElementX,
TargetElementX,
MixinApplicationElementX,
+ TypeVariableElementX,
TypedefElementX,
SynthesizedConstructorElementX;
import '../util/util.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
index e31e9ff..ebc83d63 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
@@ -34,11 +34,6 @@
}
Element localLookup(String name);
-
- static Scope buildEnclosingScope(Element element) {
- return element.enclosingElement != null
- ? element.enclosingElement.buildScope() : element.buildScope();
- }
}
class VariableDefinitionScope extends NestedScope {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index eaf9feb..69a62ef 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -61,6 +61,8 @@
// TODO(johnniwinther): Ensure that modifiers are always available.
Modifiers get modifiers =>
cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY;
+
+ accept(ElementVisitor visitor) => visitor.visitClassElement(this);
}
class MemberListener extends NodeListener {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
index d447029..013e11c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
@@ -103,7 +103,6 @@
abstract class KeywordState {
KeywordState(this.keyword);
- bool isLeaf();
KeywordState next(int c);
final Keyword keyword;
@@ -172,8 +171,6 @@
ArrayKeywordState(List<KeywordState> this.table, String syntax)
: super((syntax == null) ? null : Keyword.keywords[syntax]);
- bool isLeaf() => false;
-
KeywordState next(int c) => table[c - $a];
String toString() {
@@ -201,8 +198,6 @@
class LeafKeywordState extends KeywordState {
LeafKeywordState(String syntax) : super(Keyword.keywords[syntax]);
- bool isLeaf() => true;
-
KeywordState next(int c) => null;
String toString() => keyword.syntax;
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index a35be99..71992fa 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -552,7 +552,13 @@
}
Token expectedExpression(Token token) {
- error("expected an expression, but got '${token.value}'", token);
+ String message;
+ if (token.info == BAD_INPUT_INFO) {
+ message = token.value;
+ } else {
+ message = "expected an expression, but got '${token.value}'";
+ }
+ error(message, token);
return skipToEof(token);
}
@@ -972,16 +978,22 @@
}
Token expectedExpression(Token token) {
- listener.cancel("expected an expression, but got '${token.value}'",
- token: token);
- pushNode(null);
- return skipToEof(token);
+ if (token.info == BAD_INPUT_INFO) {
+ reportError(token, MessageKind.GENERIC, {'text': token.value});
+ pushNode(new ErrorExpression(token));
+ return token.next;
+ } else {
+ listener.cancel("expected an expression, but got '${token.value}'",
+ token: token);
+ pushNode(null);
+ return skipToEof(token);
+ }
}
Token unexpected(Token token) {
String message = "unexpected token '${token.value}'";
if (token.info == BAD_INPUT_INFO) {
- message = token.stringValue;
+ message = token.value;
}
listener.cancel(message, token: token);
return skipToEof(token);
@@ -1071,13 +1083,6 @@
return node;
}
- Node peekNode() {
- assert(!nodes.isEmpty);
- Node node = nodes.head;
- if (VERBOSE) log("peek $node");
- return node;
- }
-
void log(message) {
print(message);
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index af56bf9..53f04db 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -431,16 +431,6 @@
return token;
}
- bool isDefaultKeyword(Token token) {
- String value = token.stringValue;
- if (identical(value, 'default')) return true;
- if (identical(value, 'factory')) {
- listener.recoverableError("expected 'default'", token: token);
- return true;
- }
- return false;
- }
-
Token skipBlock(Token token) {
if (!optional('{', token)) {
return listener.expectedBlockToSkip(token);
@@ -1778,8 +1768,11 @@
}
Token parseParenthesizedExpression(Token token) {
- var begin = (token as BeginGroupToken);
+ // We expect [begin] to be of type [BeginGroupToken], but we don't know for
+ // sure until after calling expect.
+ var begin = token;
token = expect('(', token);
+ // [begin] is now known to have type [BeginGroupToken].
token = parseExpression(token);
if (!identical(begin.endGroup, token)) {
listener.unexpected(token);
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
index 8659ead..c7e1ae7 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
@@ -17,6 +17,8 @@
}
abstract class AbstractScanner implements Scanner {
+ // TODO(ahe): Move this class to implementation.
+
final bool includeComments;
/**
@@ -186,14 +188,21 @@
/** Documentation in subclass [ArrayBasedScanner]. */
void discardOpenLt();
- // TODO(ahe): Move this class to implementation.
+ /// Return true when at EOF.
+ bool atEndOfFile();
Token tokenize() {
- int next = advance();
- while (!identical(next, $EOF)) {
- next = bigSwitch(next);
+ while (!atEndOfFile()) {
+ int next = advance();
+ while (!identical(next, $EOF)) {
+ next = bigSwitch(next);
+ }
+ if (atEndOfFile()) {
+ appendEofToken();
+ } else {
+ error('Unexpected ${$EOF} byte in input.');
+ }
}
- appendEofToken();
if (file != null) {
file.length = stringOffset;
@@ -921,7 +930,14 @@
int tokenizeInterpolatedIdentifier(int next) {
appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO);
beginToken(); // The identifier starts here.
- next = tokenizeKeywordOrIdentifier(next, false);
+
+ if ($a <= next && next <= $z) {
+ next = tokenizeKeywordOrIdentifier(next, false);
+ } else if (($A <= next && next <= $Z) || identical(next, $_)) {
+ next = tokenizeIdentifier(next, scanOffset, false);
+ } else {
+ error("expected identifier or '{'", shouldAdvance: false);
+ }
beginToken(); // The string interpolation suffix starts here.
return next;
}
@@ -1035,9 +1051,14 @@
return error("unterminated string literal");
}
- int error(String message) {
+ int error(String message, {bool shouldAdvance: true}) {
appendStringToken(BAD_INPUT_INFO, message);
- return advance(); // Ensure progress.
+ if (atEndOfFile()) return $EOF;
+ if (shouldAdvance) {
+ return advance(); // Ensure progress.
+ } else {
+ return -1;
+ }
}
void unmatchedBeginGroup(BeginGroupToken begin) {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
index 68aea9f..f5592f4 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
@@ -16,6 +16,8 @@
ClassElementX,
MetadataAnnotationX,
MixinApplicationElementX;
+import '../elements/visitor.dart'
+ show ElementVisitor;
import '../dart2jslib.dart';
import '../native_handler.dart' as native;
import '../string_validator.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
index f0f11e0..5a30e43 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
@@ -51,4 +51,6 @@
scanOffset + extraOffset, tokenStart, canonicalize: true);
tail = tail.next;
}
+
+ bool atEndOfFile() => scanOffset >= string.length - 1;
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
index 523495c..62722ea 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
@@ -190,4 +190,6 @@
info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
tail = tail.next;
}
+
+ bool atEndOfFile() => byteOffset >= bytes.length - 1;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index f556147..b70c2de 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -15,6 +15,8 @@
: super(name, ElementKind.PARAMETER, enclosing);
DartType computeType(Compiler compiler) => type;
+
+ accept(ElementVisitor visitor) => visitor.visitInterceptedElement(this);
}
class SsaBuilderTask extends CompilerTask {
@@ -313,12 +315,6 @@
}
}
- bool hasValueForDirectLocal(Element element) {
- assert(element != null);
- assert(isAccessedDirectly(element));
- return directLocals[element] != null;
- }
-
/**
* Returns true if the local can be accessed directly. Boxed variables or
* captured variables that are stored in the closure-field return [false].
@@ -1315,9 +1311,8 @@
assert(argumentIndex == compiledArguments.length);
// TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
- returnElement = new ElementX("result",
- ElementKind.VARIABLE,
- function);
+ returnElement = new VariableElementX.synthetic("result",
+ ElementKind.VARIABLE, function);
newLocalsHandler.updateLocal(returnElement,
graph.addConstantNull(compiler));
elements = compiler.enqueuer.resolution.getCachedElements(function);
@@ -1925,7 +1920,8 @@
if (source != null && allIndexed && typeVariables.isEmpty) {
copyRuntimeTypeInfo(source, newObject);
} else {
- callSetRuntimeTypeInfo(classElement, typeArguments, newObject);
+ newObject =
+ callSetRuntimeTypeInfo(classElement, typeArguments, newObject);
}
}
@@ -2147,8 +2143,6 @@
push(attachPosition(instruction, node));
}
- HInstruction peek() => stack.last;
-
HInstruction pop() {
return stack.removeLast();
}
@@ -2984,11 +2978,6 @@
return new HForeign(code, type, inputs);
}
- HInstruction getRuntimeTypeInfo(HInstruction target) {
- pushInvokeStatic(null, backend.getGetRuntimeTypeInfo(), [target]);
- return pop();
- }
-
HLiteralList buildLiteralList(List<HInstruction> inputs) {
return new HLiteralList(inputs, backend.extendableArrayType);
}
@@ -3779,17 +3768,17 @@
return result;
}
- void handleListConstructor(InterfaceType type,
- Node currentNode,
- HInstruction newObject) {
- if (!backend.classNeedsRti(type.element)) return;
- if (!type.treatAsRaw) {
- List<HInstruction> inputs = <HInstruction>[];
- type.typeArguments.forEach((DartType argument) {
- inputs.add(analyzeTypeArgument(argument));
- });
- callSetRuntimeTypeInfo(type.element, inputs, newObject);
+ HInstruction handleListConstructor(InterfaceType type,
+ Node currentNode,
+ HInstruction newObject) {
+ if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
+ return newObject;
}
+ List<HInstruction> inputs = <HInstruction>[];
+ type.typeArguments.forEach((DartType argument) {
+ inputs.add(analyzeTypeArgument(argument));
+ });
+ return callSetRuntimeTypeInfo(type.element, inputs, newObject);
}
void copyRuntimeTypeInfo(HInstruction source, HInstruction target) {
@@ -3798,11 +3787,11 @@
pop();
}
- void callSetRuntimeTypeInfo(ClassElement element,
- List<HInstruction> rtiInputs,
- HInstruction newObject) {
+ HInstruction callSetRuntimeTypeInfo(ClassElement element,
+ List<HInstruction> rtiInputs,
+ HInstruction newObject) {
if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) {
- return;
+ return newObject;
}
HInstruction typeInfo = buildLiteralList(rtiInputs);
@@ -3815,7 +3804,8 @@
typeInfoSetterElement,
<HInstruction>[newObject, typeInfo],
backend.dynamicType);
- pop();
+ stack.last.instructionType = newObject.instructionType;
+ return pop();
}
handleNewSend(NewExpression node) {
@@ -3823,6 +3813,8 @@
bool isFixedList = false;
bool isFixedListConstructorCall =
Elements.isFixedListConstructorCall(elements[send], send, compiler);
+ bool isGrowableListConstructorCall =
+ Elements.isGrowableListConstructorCall(elements[send], send, compiler);
TypeMask computeType(element) {
Element originalElement = elements[send];
@@ -3835,8 +3827,7 @@
return inferred.containsAll(compiler)
? backend.fixedArrayType
: inferred;
- } else if (Elements.isGrowableListConstructorCall(
- originalElement, send, compiler)) {
+ } else if (isGrowableListConstructorCall) {
TypeMask inferred =
TypeMaskFactory.inferredForNode(currentElement, send, compiler);
return inferred.containsAll(compiler)
@@ -3937,6 +3928,11 @@
add(new HForeign(
code, backend.nullType, [stack.last], canThrow: true));
}
+ } else if (isGrowableListConstructorCall) {
+ js.Expression code = js.js.parseForeignJS('Array()');
+ var behavior = new native.NativeBehavior();
+ behavior.typesReturned.add(expectedType);
+ push(new HForeign(code, elementType, inputs, nativeBehavior: behavior));
} else {
ClassElement cls = constructor.getEnclosingClass();
if (cls.isAbstract && constructor.isGenerativeConstructor()) {
@@ -3969,9 +3965,11 @@
// not know about the type argument. Therefore we special case
// this constructor to have the setRuntimeTypeInfo called where
// the 'new' is done.
- if ((isFixedListConstructorCall || isJSArrayTypedConstructor) &&
- backend.classNeedsRti(compiler.listClass)) {
- handleListConstructor(type, send, newInstance);
+ if (backend.classNeedsRti(compiler.listClass) &&
+ (isFixedListConstructorCall || isGrowableListConstructorCall ||
+ isJSArrayTypedConstructor)) {
+ newInstance = handleListConstructor(type, send, pop());
+ stack.add(newInstance);
}
// Finally, if we called a redirecting factory constructor, check the type.
@@ -4717,15 +4715,17 @@
}
}
- void setRtiIfNeeded(HInstruction object, Node node) {
+ HInstruction setRtiIfNeeded(HInstruction object, Node node) {
InterfaceType type = elements.getType(node);
- if (!backend.classNeedsRti(type.element) || type.treatAsRaw) return;
+ if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
+ return object;
+ }
List<HInstruction> arguments = <HInstruction>[];
for (DartType argument in type.typeArguments) {
arguments.add(analyzeTypeArgument(argument));
}
- callSetRuntimeTypeInfo(type.element, arguments, object);
compiler.enqueuer.codegen.registerInstantiatedType(type, elements);
+ return callSetRuntimeTypeInfo(type.element, arguments, object);
}
visitLiteralList(LiteralList node) {
@@ -4743,7 +4743,7 @@
}
instruction = buildLiteralList(inputs);
add(instruction);
- setRtiIfNeeded(instruction, node);
+ instruction = setRtiIfNeeded(instruction, node);
}
TypeMask type =
@@ -4946,7 +4946,7 @@
add(keyValuePairs);
TypeMask mapType = new TypeMask.nonNullSubtype(backend.mapLiteralClass);
pushInvokeStatic(node, backend.getMapMaker(), [keyValuePairs], mapType);
- setRtiIfNeeded(peek(), node);
+ stack.add(setRtiIfNeeded(pop(), node));
}
visitLiteralMapEntry(LiteralMapEntry node) {
@@ -5313,12 +5313,6 @@
jumpHandler.close();
}
- Element lookupOperator(ClassElement classElement, String operatorName) {
- String dartMethodName =
- Elements.constructOperatorName(operatorName, false);
- return classElement.lookupMember(dartMethodName);
- }
-
visitSwitchCase(SwitchCase node) {
compiler.internalError('SsaBuilder.visitSwitchCase');
}
@@ -5365,9 +5359,8 @@
open(startCatchBlock);
// TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
// Note that the name of this element is irrelevant.
- Element element = new ElementX('exception',
- ElementKind.PARAMETER,
- currentElement);
+ Element element = new VariableElementX.synthetic('exception',
+ ElementKind.PARAMETER, currentElement);
exception = new HLocalValue(element, backend.nonNullType);
add(exception);
HInstruction oldRethrowableException = rethrowableException;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 1af7f49..50aabfc 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -65,11 +65,6 @@
return attachPosition(new js.Fun(parameters, body), element);
}
- CodeBuffer prettyPrint(js.Node node) {
- var code = js.prettyPrint(node, compiler, allowVariableMinification: true);
- return code;
- }
-
js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
if (work.element.isField()) {
return generateLazyInitializer(work, graph);
@@ -408,10 +403,6 @@
return !identical(expressionType(info), TYPE_STATEMENT);
}
- bool isJSDeclaration(HExpressionInformation info) {
- return identical(expressionType(info), TYPE_DECLARATION);
- }
-
bool isJSCondition(HExpressionInformation info) {
HSubExpressionBlockInformation graph = info;
SubExpression limits = graph.subExpression;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 9af57d7..e13b16d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -795,11 +795,6 @@
void setUseGvn() { _useGvn = true; }
void clearUseGvn() { _useGvn = false; }
- void updateInput(int i, HInstruction insn) {
- assert(insn != null);
- inputs[i] = insn;
- }
-
/**
* A pure instruction is an instruction that does not have any side
* effect, nor any dependency. They can be moved anywhere in the
@@ -981,23 +976,6 @@
bool isInBasicBlock() => block != null;
- String inputsToString() {
- void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) {
- for (int i = 0; i < list.length; i++) {
- if (i != 0) buffer.write(', ');
- buffer.write("@${list[i].id}");
- }
- }
-
- StringBuffer buffer = new StringBuffer();
- buffer.write('(');
- addAsCommaSeparated(buffer, inputs);
- buffer.write(') - used at [');
- addAsCommaSeparated(buffer, usedBy);
- buffer.write(']');
- return buffer.toString();
- }
-
bool gvnEquals(HInstruction other) {
assert(useGvn() && other.useGvn());
// Check that the type and the sideEffects match.
@@ -1386,13 +1364,6 @@
String toString() => 'invoke dynamic method: $selector';
accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
-
- bool isIndexOperatorOnIndexablePrimitive(Compiler compiler) {
- return isInterceptedCall
- && selector.kind == SelectorKind.INDEX
- && selector.name == '[]'
- && inputs[1].isIndexablePrimitive(compiler);
- }
}
abstract class HInvokeDynamicField extends HInvokeDynamic {
@@ -1904,27 +1875,6 @@
: super(<HInstruction>[condition]);
toString() => 'loop-branch';
accept(HVisitor visitor) => visitor.visitLoopBranch(this);
-
- bool isDoWhile() {
- return identical(kind, DO_WHILE_LOOP);
- }
-
- HBasicBlock computeLoopHeader() {
- HBasicBlock result;
- if (isDoWhile()) {
- // In case of a do/while, the successor is a block that avoids
- // a critical edge and branchs to the loop header.
- result = block.successors[0].successors[0];
- } else {
- // For other loops, the loop header might be up the dominator
- // tree if the loop condition has control flow.
- result = block;
- while (!result.isLoopHeader()) result = result.dominator;
- }
-
- assert(result.isLoopHeader());
- return result;
- }
}
class HConstant extends HInstruction {
@@ -2024,15 +1974,6 @@
input.usedBy.add(this);
}
- bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR;
-
- String logicalOperator() {
- assert(isLogicalOperator());
- if (logicalOperatorType == IS_AND) return "&&";
- assert(logicalOperatorType == IS_OR);
- return "||";
- }
-
toString() => 'phi';
accept(HVisitor visitor) => visitor.visitPhi(this);
}
@@ -2550,19 +2491,6 @@
workQueue.addAll(block.predecessors);
}
}
-
- HBasicBlock getLastBackEdge() {
- int maxId = -1;
- HBasicBlock result = null;
- for (int i = 0, length = backEdges.length; i < length; i++) {
- HBasicBlock current = backEdges[i];
- if (current.id > maxId) {
- maxId = current.id;
- result = current;
- }
- }
- return result;
- }
}
@@ -2645,7 +2573,6 @@
visitor.visitSubGraphInfo(this);
}
-
/**
* Generic class wrapping a [SubExpression] as a block-information until
* expressions structures are handled properly.
@@ -2663,7 +2590,6 @@
visitor.visitSubExpressionInfo(this);
}
-
/** A sequence of separate statements. */
class HStatementSequenceInformation implements HStatementInformation {
final List<HStatementInformation> statements;
@@ -2676,7 +2602,6 @@
visitor.visitSequenceInfo(this);
}
-
class HLabeledBlockInformation implements HStatementInformation {
final HStatementInformation body;
final List<LabelElement> labels;
@@ -2766,8 +2691,6 @@
return node.accept(const LoopTypeVisitor());
}
- bool isDoWhile() => kind == DO_WHILE_LOOP;
-
bool accept(HStatementInformationVisitor visitor) =>
visitor.visitLoopInfo(this);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
index 64c9200..76a6ade 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
@@ -24,8 +24,12 @@
import '../scanner/scannerlib.dart'
show PartialFunctionElement, Token, PLUS_TOKEN;
+import '../elements/visitor.dart'
+ show ElementVisitor;
+
import '../elements/modelx.dart'
show ElementX,
+ VariableElementX,
ConstructorBodyElementX;
import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
diff --git a/sdk/lib/_internal/compiler/implementation/string_validator.dart b/sdk/lib/_internal/compiler/implementation/string_validator.dart
index 98ad8fa..ea96105 100644
--- a/sdk/lib/_internal/compiler/implementation/string_validator.dart
+++ b/sdk/lib/_internal/compiler/implementation/string_validator.dart
@@ -18,18 +18,6 @@
StringValidator(this.listener);
- DartString validateQuotedString(Token token) {
- String source = token.value;
- StringQuoting quoting = quotingFromString(source);
- int leftQuote = quoting.leftQuoteLength;
- int rightQuote = quoting.rightQuoteLength;
- String content = copyWithoutQuotes(source, leftQuote, rightQuote);
- return validateString(token,
- token.charOffset + leftQuote,
- content,
- quoting);
- }
-
DartString validateInterpolationPart(Token token, StringQuoting quoting,
{bool isFirst: false,
bool isLast: false}) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index de5cac5..e64cbf6 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -149,6 +149,7 @@
ContinueStatement asContinueStatement() => null;
DoWhile asDoWhile() => null;
EmptyStatement asEmptyStatement() => null;
+ ErrorExpression asErrorExpression() => null;
Export asExport() => null;
Expression asExpression() => null;
ExpressionStatement asExpressionStatement() => null;
@@ -171,6 +172,7 @@
LiteralMapEntry asLiteralMapEntry() => null;
LiteralNull asLiteralNull() => null;
LiteralString asLiteralString() => null;
+ LiteralSymbol asLiteralSymbol() => null;
MixinApplication asMixinApplication() => null;
Modifiers asModifiers() => null;
NamedArgument asNamedArgument() => null;
@@ -315,6 +317,16 @@
bool isValidBreakTarget() => true;
}
+/// Errorneous expression that behaves as a literal integer (0).
+class ErrorExpression extends LiteralInt {
+ ErrorExpression(token)
+ : super(token, null);
+
+ ErrorExpression asErrorExpression() => this;
+
+ int get value => 0;
+}
+
/**
* A message send aka method invocation. In Dart, most operations can
* (and should) be considered as message sends. Getters and setters
@@ -587,10 +599,6 @@
bool get hasElsePart => elsePart != null;
- void validate() {
- // TODO(ahe): Check that condition has size one.
- }
-
accept(Visitor visitor) => visitor.visitIf(this);
visitChildren(Visitor visitor) {
@@ -908,7 +916,6 @@
void visitChildren(Visitor visitor) {}
bool get isInterpolation => false;
- bool isValidated() => dartString != null;
Token getBeginToken() => token;
Token getEndToken() => token;
@@ -1715,8 +1722,6 @@
Token getEndToken() => statement.getEndToken();
bool isValidContinueTarget() => statement.isValidContinueTarget();
-
- Node getBody() => statement;
}
abstract class LibraryTag extends Node {
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index f5eccfd..a14859b 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -328,7 +328,6 @@
}
// TODO(karlklose): remove these functions.
- DartType unhandledStatement() => StatementType.NOT_RETURNING;
DartType unhandledExpression() => types.dynamicType;
DartType analyzeNonVoid(Node node) {
@@ -897,6 +896,41 @@
return type;
}
+ /// Compute a version of [shownType] that is more specific that [knownType].
+ /// This is used to provided better hints when trying to promote a supertype
+ /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List`
+ /// we suggest the use of `List<int>`, which would make promotion valid.
+ DartType computeMoreSpecificType(DartType shownType,
+ DartType knownType) {
+ if (knownType.kind == TypeKind.INTERFACE &&
+ shownType.kind == TypeKind.INTERFACE &&
+ types.isSubtype(shownType.asRaw(), knownType)) {
+ // For the comments in the block, assume the hierarchy:
+ // class A<T, V> {}
+ // class B<S, U> extends A<S, int> {}
+ // and a promotion from a [knownType] of `A<double, int>` to a
+ // [shownType] of `B`.
+ InterfaceType knownInterfaceType = knownType;
+ ClassElement shownClass = shownType.element;
+
+ // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using
+ // the relation between `A<S, int>` and `A<double, int>`.
+ MoreSpecificSubtypeVisitor visitor =
+ new MoreSpecificSubtypeVisitor(compiler);
+ InterfaceType shownTypeGeneric = visitor.computeMoreSpecific(
+ shownClass, knownInterfaceType);
+
+ if (shownTypeGeneric != null &&
+ types.isMoreSpecific(shownTypeGeneric, knownType)) {
+ // This should be the case but we double-check.
+ // TODO(johnniwinther): Ensure that we don't suggest malbounded types.
+ return shownTypeGeneric;
+ }
+ }
+ return null;
+
+ }
+
DartType visitSend(Send node) {
Element element = elements[node];
@@ -953,13 +987,30 @@
new TypePromotion(node, variable, shownType);
if (!types.isMoreSpecific(shownType, knownType)) {
String variableName = variable.name;
- // TODO(johnniwinther): Provide a how-to-fix in the case one tries
- // to promote a generic type to a raw type.
- typePromotion.addHint(node,
- MessageKind.NOT_MORE_SPECIFIC,
- {'variableName': variableName,
- 'shownType': shownType,
- 'knownType': knownType});
+ if (!types.isSubtype(shownType, knownType)) {
+ typePromotion.addHint(node,
+ MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
+ {'variableName': variableName,
+ 'shownType': shownType,
+ 'knownType': knownType});
+ } else {
+ DartType shownTypeSuggestion =
+ computeMoreSpecificType(shownType, knownType);
+ if (shownTypeSuggestion != null) {
+ typePromotion.addHint(node,
+ MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ {'variableName': variableName,
+ 'shownType': shownType,
+ 'shownTypeSuggestion': shownTypeSuggestion,
+ 'knownType': knownType});
+ } else {
+ typePromotion.addHint(node,
+ MessageKind.NOT_MORE_SPECIFIC,
+ {'variableName': variableName,
+ 'shownType': shownType,
+ 'knownType': knownType});
+ }
+ }
}
showTypePromotion(node, typePromotion);
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 5a2b13f..5e55fb5 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -6,7 +6,6 @@
import 'dart:collection' show Queue, IterableBase;
import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../dart_types.dart';
import '../elements/elements.dart';
import '../native_handler.dart' as native;
import '../tree/tree.dart';
@@ -407,36 +406,6 @@
return result;
}
- /**
- * Returns true if and only if the environment is compatible with [signature].
- */
- bool matches(FunctionSignature signature) {
- Types types = inferrer.compiler.types;
- bool paramMatches(ConcreteType concrete, VariableElement parameter) {
- DartType parameterType = parameter.variables.type;
- if (parameterType.treatAsDynamic || parameterType.treatAsRaw) {
- return true;
- }
- for (BaseType baseType in concrete.baseTypes) {
- if (baseType.isUnknown()) return false;
- if (baseType.isNull()) continue;
- ClassBaseType classType = baseType;
- if (!types.isSubtype(classType.element.rawType,
- parameterType)) return false;
- }
- return true;
- }
- for (VariableElement param in signature.requiredParameters) {
- ConcreteType concrete = environment[param];
- if (concrete == null || !paramMatches(concrete, param)) return false;
- }
- for (VariableElement param in signature.optionalParameters) {
- ConcreteType concrete = environment[param];
- if (concrete != null && !paramMatches(concrete, param)) return false;
- }
- return true;
- }
-
String toString() => "{ this: $typeOfThis, env: $environment }";
}
@@ -513,10 +482,6 @@
throw new UnsupportedError("");
}
- bool containsOnlyNull(Compiler compiler) {
- throw new UnsupportedError("");
- }
-
bool containsOnlyBool(Compiler compiler) {
throw new UnsupportedError("");
}
@@ -545,10 +510,6 @@
throw new UnsupportedError("");
}
- Iterable<ClassElement> containedClasses(Compiler compiler) {
- throw new UnsupportedError("");
- }
-
TypeMask union(TypeMask other, Compiler compiler) {
throw new UnsupportedError("");
}
@@ -557,10 +518,6 @@
throw new UnsupportedError("");
}
- bool understands(Selector selector, Compiler compiler) {
- throw new UnsupportedError("");
- }
-
bool canHit(Element element, Selector selector, Compiler compiler) {
throw new UnsupportedError("");
}
@@ -1075,10 +1032,6 @@
void clear() {}
- Iterable<Element> getCallersOf(Element element) {
- throw new UnsupportedError("");
- }
-
bool isCalledOnce(Element element) {
throw new UnsupportedError("");
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 2e99ab4..1938dfc 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -154,11 +154,6 @@
|| base == compiler.backend.numImplementation;
}
- bool containsOnlyNull(Compiler compiler) {
- return base == compiler.nullClass
- || base == compiler.backend.nullImplementation;
- }
-
bool containsOnlyBool(Compiler compiler) {
return base == compiler.boolClass
|| base == compiler.backend.boolImplementation;
@@ -403,16 +398,6 @@
return new TypeMask(null, EMPTY, isNullable && other.isNullable);
}
- Iterable<ClassElement> containedClasses(Compiler compiler) {
- Iterable<ClassElement> self = [ base ];
- if (isExact) {
- return self;
- } else {
- Set<ClassElement> subset = containedSubset(this, compiler);
- return (subset == null) ? self : [ self, subset ].expand((x) => x);
- }
- }
-
/**
* Returns whether [element] will be the one used at runtime when being
* invoked on an instance of [cls]. [selector] is used to ensure library
@@ -504,23 +489,6 @@
return selector.appliesUntyped(element, compiler);
}
- /**
- * Returns whether this [TypeMask] understands [selector].
- */
- bool understands(Selector selector, Compiler compiler) {
- ClassElement cls;
- if (isEmpty) {
- if (!isNullable) return false;
- cls = compiler.backend.nullImplementation;
- } else {
- cls = base;
- }
-
- // Use [lookupMember] because finding abstract members is okay.
- Element element = cls.implementation.lookupMember(selector.name);
- return element != null && selector.appliesUntyped(element, compiler);
- }
-
bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
// A call on an empty type mask is either dead code, or a call on
// `null`.
diff --git a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
index bb7b7a9..ec6acab 100644
--- a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
@@ -42,10 +42,6 @@
return forwardTo.containsOnlyNum(compiler);
}
- bool containsOnlyNull(Compiler compiler) {
- return forwardTo.containsOnlyNull(compiler);
- }
-
bool containsOnlyBool(Compiler compiler) {
return forwardTo.containsOnlyBool(compiler);
}
@@ -74,10 +70,6 @@
return forwardTo.singleClass(compiler);
}
- Iterable<ClassElement> containedClasses(Compiler compiler) {
- return forwardTo.containedClasses(compiler);
- }
-
TypeMask union(other, Compiler compiler) {
if (this == other) {
return this;
@@ -93,10 +85,6 @@
return forwardTo.intersection(other, compiler);
}
- bool understands(Selector selector, Compiler compiler) {
- return forwardTo.understands(selector, compiler);
- }
-
bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
return forwardTo.needsNoSuchMethodHandling(selector, compiler);
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index e99a8f4..24b60b4 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -57,7 +57,6 @@
bool containsOnlyInt(Compiler compiler);
bool containsOnlyDouble(Compiler compiler);
bool containsOnlyNum(Compiler compiler);
- bool containsOnlyNull(Compiler compiler);
bool containsOnlyBool(Compiler compiler);
bool containsOnlyString(Compiler compiler);
bool containsOnly(ClassElement element);
@@ -94,11 +93,6 @@
ClassElement singleClass(Compiler compiler);
/**
- * Returns the classes this type mask can be.
- */
- Iterable<ClassElement> containedClasses(Compiler compiler);
-
- /**
* Returns a type mask representing the union of [this] and [other].
*/
TypeMask union(TypeMask other, Compiler compiler);
@@ -109,11 +103,6 @@
TypeMask intersection(TypeMask other, Compiler compiler);
/**
- * Returns whether this [TypeMask] understands [selector].
- */
- bool understands(Selector selector, Compiler compiler);
-
- /**
* Returns whether this [TypeMask] applied to [selector] can hit a
* [noSuchMethod].
*/
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index d1ab26c..175f92f 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -30,7 +30,6 @@
TypeMask getTypeOfSelector(Selector selector);
Iterable<TypeMask> get containerTypes;
void clear();
- Iterable<Element> getCallersOf(Element element);
bool isCalledOnce(Element element);
bool isFixedArrayCheckedForGrowable(Node node);
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
index de7fc8f..b632e9b 100644
--- a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -219,10 +219,6 @@
});
}
- bool containsOnlyNull(Compiler compiler) {
- return disjointMasks.every((mask) => mask.containsOnlyNull(compiler));
- }
-
bool containsOnlyBool(Compiler compiler) {
return disjointMasks.every((mask) => mask.containsOnlyBool(compiler));
}
@@ -249,15 +245,6 @@
ClassElement singleClass(Compiler compiler) => null;
- Iterable<ClassElement> containedClasses(Compiler compiler) {
- return disjointMasks.expand(
- (TypeMask mask) => mask.containedClasses(compiler));
- }
-
- bool understands(Selector selector, Compiler compiler) {
- return disjointMasks.any((e) => e.understands(selector, compiler));
- }
-
bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
return disjointMasks.any(
(e) => e.needsNoSuchMethodHandling(selector, compiler));
diff --git a/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
index d6b06ad..e4a1fa4 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
@@ -36,7 +36,6 @@
bool getFlag(int position) => (flags & (1 << position)) != 0;
void setFlag(int position) { flags |= (1 << position); }
- void clearFlag(int position) { flags &= ~(1 << position); }
int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
int getDependsOnFlags() {
@@ -47,9 +46,7 @@
bool dependsOnSomething() => getDependsOnFlags() != 0;
void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
- bool hasAllSideEffects() {
- return getChangesFlags() == (1 << FLAG_CHANGES_COUNT) - 1;
- }
+
void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
void setDependsOnSomething() {
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 73bbb9f..8e9d506 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -92,14 +92,6 @@
return hasMatchingSelector(invokedSetters[member.name], member, compiler);
}
- bool hasFieldGetter(Element member, Compiler compiler) {
- return fieldGetters.contains(member);
- }
-
- bool hasFieldSetter(Element member, Compiler compiler) {
- return fieldSetters.contains(member);
- }
-
DartType registerIsCheck(DartType type, Compiler compiler) {
type = type.unalias(compiler);
// Even in checked mode, type annotations for return type and argument
@@ -278,7 +270,6 @@
bool isOperator() => identical(kind, SelectorKind.OPERATOR);
bool isUnaryOperator() => isOperator() && argumentCount == 0;
- bool isBinaryOperator() => isOperator() && argumentCount == 1;
/** Check whether this is a call to 'assert'. */
bool isAssert() => isCall() && identical(name, "assert");
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
new file mode 100644
index 0000000..f8a1f9e
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -0,0 +1,188 @@
+// 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
+// BSD-style license that can be found in the LICENSE file.
+
+/// This file use methods that aren't used by dart2js.dart, but that we wish to
+/// keep anyway. This might be general API that isn't currently in use,
+/// debugging aids, or API only used for testing (see TODO below).
+
+library dart2js.use_unused_api;
+
+import 'dart2js.dart' as dart2js;
+
+import 'dart2jslib.dart' as dart2jslib;
+
+import 'tree/tree.dart' as tree;
+
+import 'util/util.dart' as util;
+
+import 'elements/visitor.dart' as elements_visitor;
+
+import 'js/js.dart' as js;
+
+import 'types/concrete_types_inferrer.dart' as concrete_types_inferrer;
+
+import 'colors.dart' as colors;
+
+import 'filenames.dart' as filenames;
+
+import 'dart_types.dart' as dart_types;
+
+import 'universe/universe.dart' as universe;
+
+import 'inferrer/type_graph_inferrer.dart' as type_graph_inferrer;
+
+import 'source_file_provider.dart' as source_file_provider;
+
+import 'ssa/ssa.dart' as ssa;
+
+class ElementVisitor extends elements_visitor.ElementVisitor {
+ visitElement(e) {}
+}
+
+void main(List<String> arguments) {
+ dart2js.main(arguments);
+ useConstant(null, null);
+ useNode(null);
+ useUtil(null);
+ useElementVisitor(new ElementVisitor());
+ useJs(new js.Program(null));
+ useJs(new js.Blob(null));
+ useJs(new js.NamedFunction(null, null));
+ useConcreteTypesInferrer(null);
+ useColor();
+ useFilenames();
+ useSsa(null);
+ useCodeBuffer(null);
+ usedByTests();
+}
+
+void useConstant(dart2jslib.Constant constant, dart2jslib.ConstantSystem cs) {
+ constant.isObject();
+ cs.isBool(constant);
+}
+
+void useNode(tree.Node node) {
+ node
+ ..asBreakStatement()
+ ..asCascade()
+ ..asCatchBlock()
+ ..asClassNode()
+ ..asCombinator()
+ ..asConditional()
+ ..asContinueStatement()
+ ..asErrorExpression()
+ ..asExport()
+ ..asFor()
+ ..asFunctionDeclaration()
+ ..asIf()
+ ..asLabeledStatement()
+ ..asLibraryDependency()
+ ..asLibraryName()
+ ..asLiteralDouble()
+ ..asLiteralList()
+ ..asLiteralMap()
+ ..asLiteralMapEntry()
+ ..asLiteralNull()
+ ..asLiteralSymbol()
+ ..asModifiers()
+ ..asPart()
+ ..asPartOf()
+ ..asRethrow()
+ ..asStatement()
+ ..asStringInterpolation()
+ ..asStringInterpolationPart()
+ ..asStringJuxtaposition()
+ ..asStringNode()
+ ..asSwitchCase()
+ ..asSwitchStatement()
+ ..asTryStatement()
+ ..asTypeAnnotation()
+ ..asTypeVariable()
+ ..asTypedef()
+ ..asWhile();
+}
+
+void useUtil(util.Link link) {
+ link.reversePrependAll(link);
+ util.trace("");
+}
+
+void useElementVisitor(ElementVisitor visitor) {
+ visitor
+ ..visit(null)
+ ..visitAbstractFieldElement(null)
+ ..visitAmbiguousElement(null)
+ ..visitBoxElement(null)
+ ..visitBoxFieldElement(null)
+ ..visitClassElement(null)
+ ..visitClosureClassElement(null)
+ ..visitClosureFieldElement(null)
+ ..visitCompilationUnitElement(null)
+ ..visitConstructorBodyElement(null)
+ ..visitElement(null)
+ ..visitErroneousElement(null)
+ ..visitFieldParameterElement(null)
+ ..visitFunctionElement(null)
+ ..visitInterceptedElement(null)
+ ..visitLabelElement(null)
+ ..visitLibraryElement(null)
+ ..visitMixinApplicationElement(null)
+ ..visitPrefixElement(null)
+ ..visitScopeContainerElement(null)
+ ..visitTargetElement(null)
+ ..visitThisElement(null)
+ ..visitTypeDeclarationElement(null)
+ ..visitTypeVariableElement(null)
+ ..visitTypedefElement(null)
+ ..visitVariableElement(null)
+ ..visitVariableListElement(null)
+ ..visitVoidElement(null)
+ ..visitWarnOnUseElement(null);
+}
+
+useJs(js.Node node) {
+ node.asVariableUse();
+}
+
+useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
+ c.debug();
+}
+
+useColor() {
+ colors.white(null);
+ colors.blue(null);
+ colors.yellow(null);
+ colors.black(null);
+}
+
+useFilenames() {
+ filenames.appendSlash(null);
+}
+
+useSsa(ssa.HInstruction instruction) {
+ instruction.isConstantNumber();
+ new ssa.HAndOrBlockInformation(null, null, null);
+ new ssa.HStatementSequenceInformation(null);
+}
+
+useCodeBuffer(dart2jslib.CodeBuffer buffer) {
+ buffer.writeln();
+}
+
+usedByTests() {
+ // TODO(ahe): We should try to avoid including API used only for tests. In
+ // most cases, such API can be moved to a test library.
+ dart2jslib.World world = null;
+ dart2jslib.Compiler compiler = null;
+ type_graph_inferrer.TypeGraphInferrer typeGraphInferrer = null;
+ source_file_provider.SourceFileProvider sourceFileProvider = null;
+ world.hasAnyUserDefinedGetter(null);
+ compiler.importHelperLibrary(null);
+ typeGraphInferrer.getCallersOf(null);
+ dart_types.Types.sorted(null);
+ new universe.TypedSelector.subclass(null, null);
+ new universe.TypedSelector.subtype(null, null);
+ new universe.TypedSelector.exact(null, null);
+ sourceFileProvider.readStringFromUri(null);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 62dcce4..e1a8516 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -1079,11 +1079,18 @@
"a class.");
static const MessageKind STATIC_FUNCTION_BLOAT = const MessageKind(
- "Hint: Using '#{class}.#{name}' may result in larger output.");
+ "Hint: Using '#{class}.#{name}' may lead to unnecessarily large "
+ "generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog.");
- static const MessageKind NON_CONST_BLOAT = const MessageKind('''
-Hint: Using "new #{name}' may result in larger output.
-Use 'const #{name}' if possible.''');
+ static const MessageKind NON_CONST_BLOAT = const MessageKind(
+ "Hint: Using 'new #{name}' may lead to unnecessarily large generated "
+ "code.",
+ howToFix:
+ "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
+ "described at https://goo.gl/Akrrog.");
static const MessageKind STRING_EXPECTED = const MessageKind(
"Error: Expected a 'String', but got an instance of '#{type}'.");
@@ -1331,6 +1338,13 @@
static const MessageKind MIRROR_IMPORT = const MessageKind(
"Info: Import of 'dart:mirrors'.");
+ static const MessageKind MIRROR_IMPORT_NO_USAGE = const MessageKind(
+ "Info: This import is not annotated with @MirrorsUsed, which may lead to "
+ "unnecessarily large generated code.",
+ howToFix:
+ "Try adding '@MirrorsUsed(...)' as described at "
+ "https://goo.gl/Akrrog.");
+
static const MessageKind WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT =
const MessageKind(
"Error: Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant.");
@@ -1341,6 +1355,46 @@
howToFix: "Try using a different name.",
examples: const ["do() {} main() {}"]);
+ static const MessageKind UNUSED_METHOD = const MessageKind(
+ "Hint: The method '#{method_name}' is never called.",
+ howToFix: "Consider deleting it.",
+ examples: const ["deadCode() {} main() {}"]);
+
+ static const MessageKind UNIMPLEMENTED_METHOD = const MessageKind(
+ "Warning: '#{class_name}' doesn't implement '#{member_name}'.",
+ howToFix: "Try adding an implementation of '#{member_name}'.",
+ examples: const ["""
+abstract class I {
+ m();
+}
+
+class C implements I {}
+
+class D implements I {
+ m() {}
+}
+
+main() {
+ new D().m();
+ new C();
+}
+""", """
+abstract class I {
+ m();
+}
+
+class C extends I {}
+
+class D extends I {
+ m() {}
+}
+
+main() {
+ new D().m();
+ new C();
+}
+"""]);
+
static const MessageKind COMPILER_CRASHED = const MessageKind(
"Error: The compiler crashed when compiling this element.");
@@ -1394,6 +1448,17 @@
"'#{shownType}' because '#{shownType}' is not more specific than the "
"known type '#{knownType}' of '#{variableName}'.");
+ static const MessageKind NOT_MORE_SPECIFIC_SUBTYPE = const MessageKind(
+ "Hint: Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not a subtype of the "
+ "known type '#{knownType}' of '#{variableName}'.");
+
+ static const MessageKind NOT_MORE_SPECIFIC_SUGGESTION = const MessageKind(
+ "Hint: Variable '#{variableName}' is not shown to have type "
+ "'#{shownType}' because '#{shownType}' is not more specific than the "
+ "known type '#{knownType}' of '#{variableName}'.",
+ howToFix: "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'.");
+
//////////////////////////////////////////////////////////////////////////////
// Patch errors start.
//////////////////////////////////////////////////////////////////////////////
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index aa48510..8a044ec 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -20,8 +20,6 @@
// distinct sets to make class hierarchy analysis faster.
final Map<ClassElement, Set<ClassElement>> _subclasses =
new Map<ClassElement, Set<ClassElement>>();
- final Map<ClassElement, Set<ClassElement>> _superclasses =
- new Map<ClassElement, Set<ClassElement>>();
final Map<ClassElement, Set<ClassElement>> _subtypes =
new Map<ClassElement, Set<ClassElement>>();
final Map<ClassElement, Set<ClassElement>> _supertypes =
@@ -39,10 +37,6 @@
return _subtypes[cls.declaration];
}
- Set<ClassElement> superclassesOf(ClassElement cls) {
- return _superclasses[cls.declaration];
- }
-
Set<ClassElement> supertypesOf(ClassElement cls) {
return _supertypes[cls.declaration];
}
@@ -81,11 +75,8 @@
// implemented by that type on the superclasses.
DartType type = cls.supertype;
while (type != null) {
- Set<Element> superclassesOfClass =
- _superclasses.putIfAbsent(cls, () => new Set<ClassElement>());
Set<Element> subclassesOfSuperclass =
_subclasses.putIfAbsent(type.element, () => new Set<ClassElement>());
- superclassesOfClass.add(type.element);
subclassesOfSuperclass.add(cls);
Set<Element> typesImplementedBySubclassesOfCls =
@@ -151,10 +142,6 @@
return allFunctions.filter(selector).any((each) => each.isGetter());
}
- bool hasAnyUserDefinedSetter(Selector selector) {
- return allFunctions.filter(selector).any((each) => each.isSetter());
- }
-
// Returns whether a subclass of [superclass] implements [type].
bool hasAnySubclassThatImplements(ClassElement superclass,
ClassElement type) {
@@ -208,24 +195,6 @@
return mask.locateSingleElement(selector, compiler);
}
- bool hasSingleMatch(Selector selector) {
- Iterable<Element> targets = allFunctions.filter(selector);
- return targets.length == 1;
- }
-
- Iterable<ClassElement> locateNoSuchMethodHolders(Selector selector) {
- Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
- ti.TypeMask mask = selector.mask;
- if (mask != null) {
- noSuchMethodSelector = new TypedSelector(mask, noSuchMethodSelector);
- }
- ClassElement objectClass = compiler.objectClass;
- return allFunctions
- .filter(noSuchMethodSelector)
- .map((Element member) => member.getEnclosingClass())
- .where((ClassElement holder) => !identical(holder, objectClass));
- }
-
void addFunctionCalledInLoop(Element element) {
functionsCalledInLoop.add(element.declaration);
}
diff --git a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
index df3f21a..f4920ae 100644
--- a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
+++ b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
@@ -43,7 +43,7 @@
}
}
return compiler.compile(
- new Uri('memory:/main.dart'),
+ Uri.parse('memory:/main.dart'),
Uri.parse('sdk:/sdk/'),
null,
inputProvider,
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
index b25aab3..36596aa 100644
--- a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -56,14 +56,14 @@
}
jsonify(MirrorSystem mirrors) {
- var map = {};
+ var map = <String, String>{};
mirrors.libraries.forEach((_, LibraryMirror library) {
BackDoor.compilationUnitsOf(library).forEach((compilationUnit) {
Uri uri = compilationUnit.uri;
String filename = relativize(sdkRoot, uri, false);
SourceFile file = handler.provider.sourceFiles['$uri'];
- map['sdk:/$filename'] = file.text;
+ map['sdk:/$filename'] = file.slowText();
});
});
@@ -73,7 +73,7 @@
Uri uri = sdkRoot.resolve('sdk/lib/$patch');
String filename = relativize(sdkRoot, uri, false);
SourceFile file = handler.provider.sourceFiles['$uri'];
- map['sdk:/$filename'] = file.text;
+ map['sdk:/$filename'] = file.slowText();
}
});
diff --git a/sdk/lib/_internal/compiler/samples/leap/index.html b/sdk/lib/_internal/compiler/samples/leap/index.html
deleted file mode 100644
index e288ba0..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<!-- 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
- BSD-style license that can be found in the LICENSE file.
--->
-<html>
- <head>
- <title>Leap Leg</title>
- <link rel="stylesheet" type="text/css" href="leap.css" />
- </head>
- <body>
- <h2 id="status">Dart is not running</h2>
-
- <section id="outline">
- <h3>Outline</h3>
- <div id="out" style="white-space: pre-wrap"></div>
- </section>
-
- <section id="editor">
- <h3>Code</h3>
- <div id="code">void main() {
- print('Hello, World');
-}
-</div>
- </section>
-
- <iframe id="isolate" style="display:none" src="isolate.html"></iframe>
-
- <div id="popup"></div>
-
- <script type="application/dart" src="leap.dart"></script>
- <script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
- </body>
-</html>
diff --git a/sdk/lib/_internal/compiler/samples/leap/isolate.html b/sdk/lib/_internal/compiler/samples/leap/isolate.html
deleted file mode 100644
index 7b965b1..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/isolate.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<!-- 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
- BSD-style license that can be found in the LICENSE file.
--->
-<html>
- <head>
- <title>isolate</title>
- </head>
- <body>
- <h1>fisk</h1>
- </body>
-</html>
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap.css b/sdk/lib/_internal/compiler/samples/leap/leap.css
deleted file mode 100644
index 28e0dbe..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/* 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
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#popup {
- position: fixed;
- width: 400px;
- background: yellow;
- border: thin solid red;
- z-index: 100;
- top: 0px;
- left: 0px;
- visibility: hidden;
- white-space: pre-wrap
-}
-
-#outline {
- position: fixed;
- width: 250px;
- border: solid;
- padding: 5px;
-}
-
-#editor {
- position: absolute;
- left: 280px;
- border: solid;
- padding: 5px;
-}
-
-#code {
- white-space: pre;
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap.dart b/sdk/lib/_internal/compiler/samples/leap/leap.dart
deleted file mode 100644
index f352287..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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
-// BSD-style license that can be found in the LICENSE file.
-
-library leap;
-
-import 'dart:isolate';
-
-import 'dart:html' as html;
-import 'request_cache.dart';
-import '../../lib/compiler/implementation/elements/elements.dart';
-import '../../lib/compiler/implementation/dart2jslib.dart';
-import '../../lib/compiler/implementation/tree/tree.dart';
-import '../../lib/compiler/implementation/source_file.dart';
-import '../../lib/compiler/implementation/library_map.dart';
-
-part 'leap_leg.dart';
-part 'leap_script.dart';
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart b/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart
deleted file mode 100644
index 87ba938..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart
+++ /dev/null
@@ -1,295 +0,0 @@
-// 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
-// BSD-style license that can be found in the LICENSE file.
-
-compilerIsolate(port) {
- Runner runner = new Runner();
- runner.init();
-
- port.receive((msg, replyTo) {
- replyTo.send(runner.update(msg));
- });
-}
-
-main() {
- html.document.query('#status').innerHTML = 'Initializing...';
- setOutline(msg) {
- html.document.query('#out').innerHTML = msg;
- }
- final codeDiv = html.document.query('#code');
- final popup = html.document.query('#popup');
-
- // The port for communicating with the compiler isolate.
- var port = null;
-
- // Should be called when [codeDiv] has changed. For now, call it always
- // on mouse up and key up events.
- update() {
- if (port == null) return;
- port.call(codeDiv.text).then(setOutline);
- }
-
- hide(Element e) {
- e.style.visibility = 'hidden';
- }
-
- show(Element e) {
- e.style.visibility = 'visible';
- }
-
- insertTextAtPoint(Event e, String newText) {
- e.preventDefault();
- var selection = html.window.getSelection();
- var range = selection.getRangeAt(0);
- var offset = range.startOffset;
- Text text = codeDiv.nodes[0];
- text.insertData(offset, newText);
- selection.setPosition(text, offset + newText.length);
- }
-
- // This prevents creating a new div element when hitting enter.
- codeDiv.on.keyPress.add((Event e) {
- if (e.keyIdentifier == 'Enter') {
- // TODO(ahe): Is 'Enter' portable?
- insertTextAtPoint(e, '\n');
- }
- });
-
- // Override tab key.
- codeDiv.on.keyDown.add((Event e) {
- if (e.keyIdentifier == 'U+0009') {
- // TODO(ahe): Find better way to detect tab key.
- insertTextAtPoint(e, ' ');
- }
- });
-
- // Called on keyUp and mouseUp to display a marker at the current
- // insertion point (the selection's first range). This probably
- // needs more work before it works really well, but seems to be good
- // enough for now.
- handleUp(Event e) {
- var selection = html.window.getSelection();
- var range = selection.getRangeAt(0);
- var rects = range.getClientRects();
- if (rects.length < 1) {
- hide(popup);
- return;
- }
- html.ClientRect rect = rects.item(rects.length - 1);
- if (rect.width.toInt() != 0) {
- // This is a selection of multiple characters, not a single
- // point of insertion.
- hide(popup);
- return;
- }
- popup.style.top = "${rect.bottom.toInt()}px";
- popup.style.left = "${rect.right.toInt()}px";
- // Instead of displaying this immediately, we could set up a timer
- // event and display it later. This is a matter of getting the UX
- // just right, for now it simply demonstrates that we know where
- // the insertion point is (in pixels) and what the character
- // offset is.
- show(popup);
- popup.text = '''Code completion here...
-Current character offset: ${range.startOffset}''';
- // TODO(ahe): Better detection of when [codeDiv] has changed.
- update();
- }
-
- codeDiv.on.keyUp.add(handleUp);
- codeDiv.on.mouseUp.add(handleUp);
-
- codeDiv.on.blur.add((Event e) => hide(popup));
-
- // The event handlers are now set up. Allow editing.
- codeDiv.contentEditable = "true";
-
- // Creates a compiler isolate in its own iframe. This should prevent
- // the compiler from blocking the UI.
- spawnDomIsolate(html.document.query('#isolate').contentWindow,
- 'compilerIsolate').then((sendPort) {
- // The compiler isolate is now ready to talk. Store the port so
- // that the update function starts requesting outlines whenever
- // [codeDiv] changes.
- port = sendPort;
- // Make sure that we get an initial outline.
- update();
- html.document.query('#status').innerHTML = 'Ready';
- });
-}
-
-class Runner {
- final LeapCompiler compiler;
-
- Runner() : compiler = new LeapCompiler();
-
- String init() {
- Stopwatch sw = new Stopwatch()..start();
- // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
- // Delete this sample.
- compiler.scanBuiltinLibraries();
- sw.stop();
- return 'Scanned core libraries in ${sw.elapsedMilliseconds}ms';
- }
-
- String update(String codeText) {
- StringBuffer sb = new StringBuffer();
-
- Stopwatch sw = new Stopwatch()..start();
-
- LibraryElement e = compile(new LeapScript(codeText));
-
- void printFunction(FunctionElement fe, [String indentation = ""]) {
- var paramAcc = [];
-
- FunctionType ft = fe.computeType(compiler);
-
- sb.write("<div>${indentation}");
- ft.returnType.name.printOn(sb);
- sb.write(" ");
- fe.name.printOn(sb);
- sb.write("(");
- ft.parameterTypes.printOn(sb, ", ");
- sb.write(");</div>");
-
- }
-
- void printField(FieldElement fe, [String indentation = ""]) {
- sb.write("<div>${indentation}var ");
- fe.name.printOn(sb);
- sb.write(";</div>");
- }
-
- void printClass(ClassElement ce) {
- ce.parseNode(compiler);
-
- sb.write("<div>class ");
- ce.name.printOn(sb);
- sb.write(" {");
-
- for (Element e in ce.members.reverse()) {
- switch(e.kind) {
- case ElementKind.FUNCTION:
-
- printFunction(e, " ");
- break;
-
- case ElementKind.FIELD:
-
- printField(e, " ");
- break;
- }
- }
- sb.write("}</div>");
- }
-
- for (Element c in e.topLevelElements.reverse()) {
- switch (c.kind) {
- case ElementKind.FUNCTION:
- printFunction (c);
- break;
-
- case ElementKind.CLASS:
- printClass(c);
- break;
-
- case ElementKind.FIELD:
- printField (c);
- break;
- }
- }
-
- compiler.log("Outline ${sw.elapsedMilliseconds}");
- return sb.toString();
- }
-
- Element compile(String script) {
- return compiler.runSelective(script);
- }
-}
-
-class LeapCompiler extends Compiler {
- HttpRequestCache cache;
-
- final bool throwOnError = false;
-
- final libDir = "../..";
-
- LeapCompiler() : cache = new HttpRequestCache(), super() {
- tasks = [scanner, dietParser, parser, resolver, checker];
- }
-
- void log(message) { print(message); }
-
- String get legDirectory => libDir;
-
- // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
- // Delete this sample.
- LibraryElement scanBuiltinLibrary(String path) {
- Uri base = Uri.parse(html.window.location.toString());
- Uri libraryRoot = base.resolve(libDir);
- Uri resolved = libraryRoot.resolve(DART2JS_LIBRARY_MAP[path]);
- // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
- // Delete this sample.
- LibraryElement library = scanner.loadLibrary(resolved, null);
- return library;
- }
-
- currentScript() {
- if (currentElement == null) return null;
- CompilationUnitElement compilationUnit =
- currentElement.getCompilationUnit();
- if (compilationUnit == null) return null;
- return compilationUnit.script;
- }
-
- // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
- // Delete this sample.
- Script readScript(Uri uri, [ScriptTag node]) {
- String text = "";
- try {
- text = cache.readAll(uri.path.toString());
- } catch (exception) {
- cancel("${uri.path}: $exception", node: node);
- }
- SourceFile sourceFile = new SourceFile(uri.toString(), text);
- return new Script(uri, sourceFile);
- }
-
- reportWarning(Node node, var message) {
- print(message);
- }
-
- reportError(Node node, var message) {
- cancel(message.toString(), node);
- }
-
- void cancel(String reason, {Node node, token, instruction, element}) {
- print(reason);
- }
-
- Element runSelective(Script script) {
- Stopwatch sw = new Stopwatch()..start();
- Element e;
- try {
- e = runCompilerSelective(script);
- } on CompilerCancelledException catch (exception) {
- log(exception.toString());
- log('compilation failed');
- return null;
- }
- log('compilation succeeded: ${sw.elapsedMilliseconds}ms');
- return e;
- }
-
- LibraryElement runCompilerSelective(Script script) {
- mainApp = new LibraryElement(script);
-
- universe.libraries.remove(script.uri.toString());
- Element element;
- withCurrentElement(mainApp, () {
- scanner.scan(mainApp);
- });
- return mainApp;
- }
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_script.dart b/sdk/lib/_internal/compiler/samples/leap/leap_script.dart
deleted file mode 100644
index 3fa045f..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap_script.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class LeapScript {
- final text;
- LeapScript(this.text);
-
- String get name => "SomeName";
- String get uri => name;
- String get file => "somefile";
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/request_cache.dart b/sdk/lib/_internal/compiler/samples/leap/request_cache.dart
deleted file mode 100644
index 637fa7a..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/request_cache.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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
-// BSD-style license that can be found in the LICENSE file.
-
-library request_cache;
-
-import 'dart:html';
-
-/** File system implementation using HTML5's Web Storage. */
-class HttpRequestCache {
- final Storage storage;
-
- HttpRequestCache() : storage = window.sessionStorage;
-
- String readAll(String filename) {
- String response = storage[filename];
-
- if (response == null) {
- HttpRequest xr = new HttpRequest();
- xr.open("GET", filename, false);
- xr.send();
- response = xr.responseText;
- storage[filename] = response;
- }
- return response;
- }
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_server.dart b/sdk/lib/_internal/compiler/samples/leap_server/leap_server.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/samples/leap/leap_server.dart
rename to sdk/lib/_internal/compiler/samples/leap_server/leap_server.dart
diff --git a/sdk/lib/_internal/lib/collection_patch.dart b/sdk/lib/_internal/lib/collection_patch.dart
index feb40e6..192dfd3 100644
--- a/sdk/lib/_internal/lib/collection_patch.dart
+++ b/sdk/lib/_internal/lib/collection_patch.dart
@@ -515,7 +515,7 @@
// iterated over.
int _modifications = 0;
- _LinkedHash();
+ _LinkedHashMap();
int get length => _length;
diff --git a/sdk/lib/_internal/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
index 0fabc0b..398d37c 100644
--- a/sdk/lib/_internal/lib/constant_map.dart
+++ b/sdk/lib/_internal/lib/constant_map.dart
@@ -122,4 +122,6 @@
Iterable<V> get values {
return _getMap().values;
}
+
+ int get length => _getMap().length;
}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index d262d79..bc87e41 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -345,8 +345,9 @@
}
patch class _FileSystemWatcher {
- patch factory _FileSystemWatcher(String path, int events, bool recursive) {
- throw new UnsupportedError("_FileSystemWatcher._FileSystemWatcher");
+ patch static Stream<FileSystemEvent> watch(
+ String path, int events, bool recursive) {
+ throw new UnsupportedError("_FileSystemWatcher.watch");
}
patch static bool get isSupported {
throw new UnsupportedError("_FileSystemWatcher.isSupported");
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 474d6af..0ff3096 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -703,7 +703,7 @@
********************************************************/
/** Common functionality to all send ports. */
-class _BaseSendPort implements SendPort {
+abstract class _BaseSendPort implements SendPort {
/** Id for the destination isolate. */
final int _isolateId;
@@ -1216,6 +1216,7 @@
return copy;
}
+ visitSendPort(SendPort x) => throw new UnimplementedError();
}
/** Visitor that serializes a message as a JSON array. */
@@ -1257,6 +1258,8 @@
}
return result;
}
+
+ visitSendPort(SendPort x) => throw new UnimplementedError();
}
/** Deserializes arrays created with [_Serializer]. */
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index c62ffd2..b1fb4c4 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -183,9 +183,11 @@
class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror {
final DeclarationMirror owner;
final TypeVariable _typeVariable;
+ final int _metadataIndex;
TypeMirror _cachedUpperBound;
- JsTypeVariableMirror(TypeVariable typeVariable, this.owner)
+ JsTypeVariableMirror(TypeVariable typeVariable, this.owner,
+ this._metadataIndex)
: this._typeVariable = typeVariable,
super(s(typeVariable.name));
@@ -228,7 +230,9 @@
List<InstanceMirror> get metadata => throw new UnimplementedError();
bool get hasReflectedType => false;
- Type get reflectedType => throw new UnsupportedError("This type does not support reflectedTypees");
+ Type get reflectedType {
+ throw new UnsupportedError("This type does not support reflectedTypees");
+ }
List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
List<TypeMirror> get typeArguments => const <TypeMirror>[];
@@ -273,7 +277,7 @@
List<JsMethodMirror> get _methods => _functionMirrors;
- Map<Symbol, ClassMirror> get classes {
+ Map<Symbol, ClassMirror> get __classes {
if (_cachedClasses != null) return _cachedClasses;
var result = new Map();
for (String className in _classes) {
@@ -293,8 +297,8 @@
InstanceMirror setField(Symbol fieldName, Object arg) {
String name = n(fieldName);
if (name.endsWith('=')) throw new ArgumentError('');
- var mirror = functions[s('$name=')];
- if (mirror == null) mirror = variables[fieldName];
+ var mirror = __functions[s('$name=')];
+ if (mirror == null) mirror = __variables[fieldName];
if (mirror == null) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(this, setterSymbol(fieldName), [arg], null);
@@ -304,7 +308,7 @@
}
InstanceMirror getField(Symbol fieldName) {
- JsMirror mirror = members[fieldName];
+ JsMirror mirror = __members[fieldName];
if (mirror == null) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(this, fieldName, [], null);
@@ -318,7 +322,7 @@
if (namedArguments != null && !namedArguments.isEmpty) {
throw new UnsupportedError('Named arguments are not implemented.');
}
- JsDeclarationMirror mirror = members[memberName];
+ JsDeclarationMirror mirror = __members[memberName];
if (mirror == null) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(
@@ -386,7 +390,7 @@
return _cachedFields = result;
}
- Map<Symbol, MethodMirror> get functions {
+ Map<Symbol, MethodMirror> get __functions {
if (_cachedFunctions != null) return _cachedFunctions;
var result = new Map();
for (JsMethodMirror mirror in _functionMirrors) {
@@ -396,7 +400,7 @@
new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
- Map<Symbol, MethodMirror> get getters {
+ Map<Symbol, MethodMirror> get __getters {
if (_cachedGetters != null) return _cachedGetters;
var result = new Map();
// TODO(ahe): Implement this.
@@ -404,7 +408,7 @@
new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
- Map<Symbol, MethodMirror> get setters {
+ Map<Symbol, MethodMirror> get __setters {
if (_cachedSetters != null) return _cachedSetters;
var result = new Map();
// TODO(ahe): Implement this.
@@ -412,7 +416,7 @@
new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
- Map<Symbol, VariableMirror> get variables {
+ Map<Symbol, VariableMirror> get __variables {
if (_cachedVariables != null) return _cachedVariables;
var result = new Map();
for (JsVariableMirror mirror in _fields) {
@@ -422,16 +426,16 @@
new UnmodifiableMapView<Symbol, VariableMirror>(result);
}
- Map<Symbol, Mirror> get members {
+ Map<Symbol, Mirror> get __members {
if (_cachedMembers != null) return _cachedMembers;
- Map<Symbol, Mirror> result = new Map.from(classes);
+ Map<Symbol, Mirror> result = new Map.from(__classes);
addToResult(Symbol key, Mirror value) {
result[key] = value;
}
- functions.forEach(addToResult);
- getters.forEach(addToResult);
- setters.forEach(addToResult);
- variables.forEach(addToResult);
+ __functions.forEach(addToResult);
+ __getters.forEach(addToResult);
+ __setters.forEach(addToResult);
+ __variables.forEach(addToResult);
return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
}
@@ -441,7 +445,7 @@
addToResult(Symbol key, Mirror value) {
result[key] = value;
}
- members.forEach(addToResult);
+ __members.forEach(addToResult);
return _cachedDeclarations =
new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
}
@@ -455,6 +459,14 @@
// TODO(ahe): Test this getter.
DeclarationMirror get owner => null;
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get topLevelMembers
+ => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Function operator [](Symbol name)
+ => throw new UnimplementedError();
}
String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -676,15 +688,15 @@
// TODO(ahe): Remove this method, only here to silence warning.
get _mixin => mixin;
- Map<Symbol, Mirror> get members => _mixin.members;
+ Map<Symbol, Mirror> get __members => _mixin.__members;
- Map<Symbol, MethodMirror> get methods => _mixin.methods;
+ Map<Symbol, MethodMirror> get __methods => _mixin.__methods;
- Map<Symbol, MethodMirror> get getters => _mixin.getters;
+ Map<Symbol, MethodMirror> get __getters => _mixin.__getters;
- Map<Symbol, MethodMirror> get setters => _mixin.setters;
+ Map<Symbol, MethodMirror> get __setters => _mixin.__setters;
- Map<Symbol, VariableMirror> get variables => _mixin.variables;
+ Map<Symbol, VariableMirror> get __variables => _mixin.__variables;
Map<Symbol, DeclarationMirror> get declarations => mixin.declarations;
@@ -709,7 +721,7 @@
List<ClassMirror> get superinterfaces => [mixin];
- Map<Symbol, MethodMirror> get constructors => _mixin.constructors;
+ Map<Symbol, MethodMirror> get __constructors => _mixin.__constructors;
InstanceMirror newInstance(
Symbol constructorName,
@@ -729,6 +741,16 @@
}
List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get instanceMembers
+ => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Function operator [](Symbol name) => throw new UnimplementedError();
}
abstract class JsObjectMirror implements ObjectMirror {
@@ -879,6 +901,9 @@
// TODO(ahe): Remove this method from the API.
MirrorSystem get mirrors => currentJsMirrorSystem;
+
+ // TODO(ahe): Implement this method.
+ Function operator [](Symbol name) => throw new UnimplementedError();
}
/**
@@ -888,7 +913,8 @@
* to JsCLassMirror that returns an empty list since it represents original
* declarations and classes that are not generic.
*/
-class JsTypeBoundClassMirror extends JsDeclarationMirror implements ClassMirror {
+class JsTypeBoundClassMirror extends JsDeclarationMirror
+ implements ClassMirror {
final JsClassMirror _class;
/**
@@ -938,7 +964,7 @@
TypeVariable typeVariable = getMetadata(parsedIndex);
TypeMirror owner = reflectClass(typeVariable.owner);
TypeVariableMirror typeMirror =
- new JsTypeVariableMirror(typeVariable, owner);
+ new JsTypeVariableMirror(typeVariable, owner, parsedIndex);
result.add(typeMirror);
}
}
@@ -980,32 +1006,32 @@
return _cachedMethods =_class._getMethodsWithOwner(this);
}
- Map<Symbol, MethodMirror> get methods {
+ Map<Symbol, MethodMirror> get __methods {
if (_cachedMethodsMap != null) return _cachedMethodsMap;
return _cachedMethodsMap = new UnmodifiableMapView<Symbol, MethodMirror>(
filterMethods(_methods));
}
- Map<Symbol, MethodMirror> get constructors {
+ Map<Symbol, MethodMirror> get __constructors {
if (_cachedConstructors != null) return _cachedConstructors;
return _cachedConstructors =
new UnmodifiableMapView<Symbol, MethodMirror>(
filterConstructors(_methods));
}
- Map<Symbol, MethodMirror> get getters {
+ Map<Symbol, MethodMirror> get __getters {
if (_cachedGetters != null) return _cachedGetters;
return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
- filterGetters(_methods, variables));
+ filterGetters(_methods, __variables));
}
- Map<Symbol, MethodMirror> get setters {
+ Map<Symbol, MethodMirror> get __setters {
if (_cachedSetters != null) return _cachedSetters;
return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
- filterSetters(_methods, variables));
+ filterSetters(_methods, __variables));
}
- Map<Symbol, VariableMirror> get variables {
+ Map<Symbol, VariableMirror> get __variables {
if (_cachedVariables != null) return _cachedVariables;
var result = new Map();
for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) {
@@ -1015,18 +1041,18 @@
new UnmodifiableMapView<Symbol, VariableMirror>(result);
}
- Map<Symbol, DeclarationMirror> get members {
+ Map<Symbol, DeclarationMirror> get __members {
if (_cachedMembers != null) return _cachedMembers;
return _cachedMembers = new UnmodifiableMapView<Symbol, DeclarationMirror>(
- filterMembers(_methods, variables));
+ filterMembers(_methods, __variables));
}
Map<Symbol, DeclarationMirror> get declarations {
if (_cachedDeclarations != null) return _cachedDeclarations;
Map<Symbol, DeclarationMirror> result =
new Map<Symbol, DeclarationMirror>();
- result.addAll(members);
- result.addAll(constructors);
+ result.addAll(__members);
+ result.addAll(__constructors);
typeVariables.forEach((tv) => result[tv.simpleName] = tv);
return _cachedDeclarations =
new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
@@ -1090,6 +1116,19 @@
Type get reflectedType => _class.reflectedType;
Symbol get simpleName => _class.simpleName;
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get instanceMembers
+ => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ ClassMirror get mixin => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Function operator [](Symbol name) => throw new UnimplementedError();
}
class JsClassMirror extends JsTypeMirror with JsObjectMirror
@@ -1134,7 +1173,7 @@
}
}
- Map<Symbol, MethodMirror> get constructors {
+ Map<Symbol, MethodMirror> get __constructors {
if (_cachedConstructors != null) return _cachedConstructors;
return _cachedConstructors =
new UnmodifiableMapView<Symbol, MethodMirror>(
@@ -1222,25 +1261,25 @@
return _cachedFields = _getFieldsWithOwner(this);
}
- Map<Symbol, MethodMirror> get methods {
+ Map<Symbol, MethodMirror> get __methods {
if (_cachedMethodsMap != null) return _cachedMethodsMap;
return _cachedMethodsMap =
new UnmodifiableMapView<Symbol, MethodMirror>(filterMethods(_methods));
}
- Map<Symbol, MethodMirror> get getters {
+ Map<Symbol, MethodMirror> get __getters {
if (_cachedGetters != null) return _cachedGetters;
return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
- filterGetters(_methods, variables));
+ filterGetters(_methods, __variables));
}
- Map<Symbol, MethodMirror> get setters {
+ Map<Symbol, MethodMirror> get __setters {
if (_cachedSetters != null) return _cachedSetters;
return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
- filterSetters(_methods, variables));
+ filterSetters(_methods, __variables));
}
- Map<Symbol, VariableMirror> get variables {
+ Map<Symbol, VariableMirror> get __variables {
if (_cachedVariables != null) return _cachedVariables;
var result = new Map();
for (JsVariableMirror mirror in _fields) {
@@ -1250,10 +1289,10 @@
new UnmodifiableMapView<Symbol, VariableMirror>(result);
}
- Map<Symbol, Mirror> get members {
+ Map<Symbol, Mirror> get __members {
if (_cachedMembers != null) return _cachedMembers;
return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(
- filterMembers(_methods, variables));
+ filterMembers(_methods, __variables));
}
Map<Symbol, DeclarationMirror> get declarations {
@@ -1262,15 +1301,15 @@
addToResult(Symbol key, Mirror value) {
result[key] = value;
}
- members.forEach(addToResult);
- constructors.forEach(addToResult);
+ __members.forEach(addToResult);
+ __constructors.forEach(addToResult);
typeVariables.forEach((tv) => result[tv.simpleName] = tv);
return _cachedDeclarations =
new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
}
InstanceMirror setField(Symbol fieldName, Object arg) {
- JsVariableMirror mirror = variables[fieldName];
+ JsVariableMirror mirror = __variables[fieldName];
if (mirror != null && mirror.isStatic && !mirror.isFinal) {
// '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so
// we shouldn't use [JsLibraryMirror._globalObject] here.
@@ -1286,7 +1325,7 @@
}
InstanceMirror getField(Symbol fieldName) {
- JsVariableMirror mirror = variables[fieldName];
+ JsVariableMirror mirror = __variables[fieldName];
if (mirror != null && mirror.isStatic) {
String jsName = mirror._jsName;
// '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
@@ -1314,7 +1353,7 @@
JsMethodMirror mirror =
JsCache.fetch(_jsConstructorCache, n(constructorName));
if (mirror == null) {
- mirror = constructors.values.firstWhere(
+ mirror = __constructors.values.firstWhere(
(m) => m.constructorName == constructorName,
orElse: () {
// TODO(ahe): What receiver to use?
@@ -1336,7 +1375,7 @@
// This will set _owner field on all clasess as a side
// effect. This gives us a fast path to reflect on a
// class without parsing reflection data.
- library.classes;
+ library.__classes;
}
}
}
@@ -1392,7 +1431,7 @@
if (namedArguments != null && !namedArguments.isEmpty) {
throw new UnsupportedError('Named arguments are not implemented.');
}
- JsMethodMirror mirror = methods[memberName];
+ JsMethodMirror mirror = __methods[memberName];
if (mirror == null || !mirror.isStatic) {
// TODO(ahe): What receiver to use?
throw new NoSuchMethodError(
@@ -1438,12 +1477,26 @@
if (typeVariables == null) return result;
for (int i = 0; i < typeVariables.length; i++) {
TypeVariable typeVariable = getMetadata(typeVariables[i]);
- result.add(new JsTypeVariableMirror(typeVariable, this));
+ result.add(new JsTypeVariableMirror(typeVariable, this,
+ typeVariables[i]));
}
return _cachedTypeVariables = new UnmodifiableListView(result);
}
List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get instanceMembers
+ => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ ClassMirror get mixin => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this.
+ Function operator [](Symbol name) => throw new UnimplementedError();
}
class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
@@ -1553,6 +1606,9 @@
}
receiver._storeField(_jsName, arg);
}
+
+ // TODO(ahe): Implement this method.
+ bool get isConst => throw new UnimplementedError();
}
class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
@@ -1607,11 +1663,16 @@
String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
- // TODO(ahe): Implement these.
+ // TODO(ahe): Implement this method.
String get source => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
InstanceMirror findInContext(Symbol name) {
throw new UnsupportedError("ClosureMirror.findInContext not yet supported");
}
+
+ // TODO(ahe): Implement this method.
+ Function operator [](Symbol name) => throw new UnimplementedError();
}
class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
@@ -1761,11 +1822,20 @@
// TODO(ahe): Test this.
bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
- // TODO(ahe): Implement these.
+ // TODO(ahe): Implement this method.
bool get isConstConstructor => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
bool get isGenerativeConstructor => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
bool get isRedirectingConstructor => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
bool get isFactoryConstructor => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ String get source => throw new UnimplementedError();
}
class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror {
@@ -1818,9 +1888,63 @@
JsFunctionTypeMirror get value => referent;
String get _prettyName => 'TypedefMirror';
+
+ // TODO(ahe): Implement this method.
+ List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ List<TypeMirror> get typeArguments => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ bool get isOriginalDeclaration => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ TypeMirror get originalDeclaration => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ DeclarationMirror get owner => throw new UnimplementedError();
+
+ // TODO(ahe): Implement this method.
+ List<InstanceMirror> get metadata => throw new UnimplementedError();
}
-class JsFunctionTypeMirror implements FunctionTypeMirror {
+// TODO(ahe): Remove this class when API is updated.
+class BrokenClassMirror {
+ bool get hasReflectedType => throw new UnimplementedError();
+ Type get reflectedType => throw new UnimplementedError();
+ ClassMirror get superclass => throw new UnimplementedError();
+ List<ClassMirror> get superinterfaces => throw new UnimplementedError();
+ Map<Symbol, DeclarationMirror> get declarations
+ => throw new UnimplementedError();
+ Map<Symbol, MethodMirror> get instanceMembers
+ => throw new UnimplementedError();
+ Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+ ClassMirror get mixin => throw new UnimplementedError();
+ InstanceMirror newInstance(
+ Symbol constructorName,
+ List positionalArguments,
+ [Map<Symbol,dynamic> namedArguments]) => throw new UnimplementedError();
+ Function operator [](Symbol name) => throw new UnimplementedError();
+ InstanceMirror invoke(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments])
+ => throw new UnimplementedError();
+ InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError();
+ InstanceMirror setField(Symbol fieldName, Object value)
+ => throw new UnimplementedError();
+ List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
+ List<TypeMirror> get typeArguments => throw new UnimplementedError();
+ TypeMirror get originalDeclaration => throw new UnimplementedError();
+ Symbol get simpleName => throw new UnimplementedError();
+ Symbol get qualifiedName => throw new UnimplementedError();
+ bool get isPrivate => throw new UnimplementedError();
+ bool get isTopLevel => throw new UnimplementedError();
+ SourceLocation get location => throw new UnimplementedError();
+ List<InstanceMirror> get metadata => throw new UnimplementedError();
+}
+
+class JsFunctionTypeMirror extends BrokenClassMirror
+ implements FunctionTypeMirror {
final _typeData;
String _cachedToString;
TypeMirror _cachedReturnType;
@@ -1920,6 +2044,9 @@
}
return _cachedToString = "$s'";
}
+
+ // TODO(ahe): Implement this method.
+ MethodMirror get callMethod => throw new UnimplementedError();
}
int findTypeVariableIndex(List<TypeVariableMirror> typeVariables, String name) {
@@ -1952,7 +2079,7 @@
} else if (ownerClass == null) {
representation = runtimeTypeToString(type);
} else if (ownerClass.isOriginalDeclaration) {
- if (type is int) {
+ if (type is num) {
// [type] represents a type variable so in the context of an original
// declaration the corresponding type variable should be returned.
TypeVariable typeVariable = getMetadata(type);
@@ -1965,11 +2092,24 @@
representation = runtimeTypeToString(type);
}
} else {
- String substituteTypeVariable(int index) {
+ getTypeArgument(int index) {
TypeVariable typeVariable = getMetadata(index);
int variableIndex =
findTypeVariableIndex(ownerClass.typeVariables, typeVariable.name);
- var typeArgument = ownerClass.typeArguments[variableIndex];
+ return ownerClass.typeArguments[variableIndex];
+ }
+
+ if (type is num) {
+ // [type] represents a type variable used as type argument for example
+ // the type argument of Bar: class Foo<T> extends Bar<T> {}
+ TypeMirror typeArgument = getTypeArgument(type);
+ if (typeArgument is JsTypeVariableMirror)
+ return typeArgument;
+ }
+ String substituteTypeVariable(int index) {
+ var typeArgument = getTypeArgument(index);
+ if (typeArgument is JsTypeVariableMirror)
+ return '${typeArgument._metadataIndex}';
assert(typeArgument is JsClassMirror ||
typeArgument is JsTypeBoundClassMirror);
return typeArgument._mangledName;
@@ -1978,7 +2118,8 @@
runtimeTypeToString(type, onTypeVariable: substituteTypeVariable);
}
if (representation != null) {
- return reflectType(createRuntimeType(representation));
+ return reflectClassByMangledName(
+ getMangledTypeName(createRuntimeType(representation)));
}
return reflectClass(Function);
}
diff --git a/sdk/lib/_internal/lib/js_number.dart b/sdk/lib/_internal/lib/js_number.dart
index b40aa4b..d389a93 100644
--- a/sdk/lib/_internal/lib/js_number.dart
+++ b/sdk/lib/_internal/lib/js_number.dart
@@ -58,7 +58,7 @@
}
num abs() => JS('num', r'Math.abs(#)', this);
-
+
static const int _MIN_INT32 = -0x80000000;
static const int _MAX_INT32 = 0x7FFFFFFF;
diff --git a/sdk/lib/_internal/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
index 7def542..e3aabe3 100644
--- a/sdk/lib/_internal/lib/math_patch.dart
+++ b/sdk/lib/_internal/lib/math_patch.dart
@@ -42,17 +42,21 @@
return JS('num', r'Math.pow(#, #)', x, exponent);
}
+const int _POW2_32 = 0x100000000;
+
patch class Random {
- patch factory Random([int seed]) => const _Random();
+ patch factory Random([int seed]) =>
+ (seed == null) ? const _JSRandom() : new _Random(seed);
}
-class _Random implements Random {
+class _JSRandom implements Random {
// The Dart2JS implementation of Random doesn't use a seed.
- const _Random();
+ const _JSRandom();
int nextInt(int max) {
- if (max < 0) throw new ArgumentError("negative max: $max");
- if (max > 0xFFFFFFFF) max = 0xFFFFFFFF;
+ if (max <= 0 || max > _POW2_32) {
+ throw new RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+ }
return JS("int", "(Math.random() * #) >>> 0", max);
}
@@ -67,3 +71,97 @@
*/
bool nextBool() => JS("bool", "Math.random() < 0.5");
}
+
+
+class _Random implements Random {
+ // Constants used by the algorithm or masking.
+ static const double _POW2_53_D = 1.0 * (0x20000000000000);
+ static const double _POW2_27_D = 1.0 * (1 << 27);
+ static const int _MASK32 = 0xFFFFFFFF;
+
+ // State comprised of two unsigned 32 bit integers.
+ int _lo;
+ int _hi;
+
+ // Implements:
+ // do {
+ // seed = (seed + 0x5A17) & _Random._MASK_64;
+ // } while (seed == 0);
+ // _lo = seed & _MASK_32;
+ // _hi = seed >> 32;
+ // and then does four _nextState calls to shuffle bits around.
+ _Random(int seed) {
+ // Works the same as the VM version for positive integers up to 2^53.
+ // For bigints, the VM always uses zero as seed. That is really a bug, and
+ // we don't simulate that.
+ seed += 0x5A17;
+ _lo = seed & _MASK32;
+ _hi = (seed - _lo) ~/ _POW2_32;
+ if (_hi == 0 && _lo == 0) {
+ _lo = 0x5A17;
+ }
+ _nextState();
+ _nextState();
+ _nextState();
+ _nextState();
+ }
+
+ // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+ // http://en.wikipedia.org/wiki/Multiply-with-carry
+ // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+ // Edition" p.348 B1.
+
+ // Implements:
+ // var state = (A * _lo + _hi) & _MASK_64;
+ // _lo = state & _MASK_32;
+ // _hi = state >> 32;
+ void _nextState() {
+ // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+ int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
+ int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
+ int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
+ int tmpLo = 0xDA61 * _lo;
+ int tmpLoLo = tmpLo & _MASK32;
+ int tmpLoHi = tmpLo - tmpLoLo;
+
+ int newLo = tmpLoLo + tmpHiLo + _hi;
+ _lo = newLo & _MASK32;
+ int newLoHi = newLo - _lo;
+ _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+ assert(_lo < _POW2_32);
+ assert(_hi < _POW2_32);
+ }
+
+ int nextInt(int max) {
+ if (max <= 0 || max > _POW2_32) {
+ throw new RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+ }
+ if ((max & (max - 1)) == 0) {
+ // Fast case for powers of two.
+ _nextState();
+ return _lo & (max - 1);
+ }
+
+ int rnd32;
+ int result;
+ do {
+ _nextState();
+ rnd32 = _lo;
+ result = rnd32.remainder(max); // % max;
+ } while ((rnd32 - result + max) >= _POW2_32);
+ return result;
+ }
+
+ double nextDouble() {
+ _nextState();
+ int bits26 = _lo & ((1 << 26) - 1);
+ _nextState();
+ int bits27 = _lo & ((1 << 27) - 1);
+ return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+ }
+
+ bool nextBool() {
+ _nextState();
+ return (_lo & 1) == 0;
+ }
+}
diff --git a/sdk/lib/_internal/lib/native_helper.dart b/sdk/lib/_internal/lib/native_helper.dart
index bc77c48..6608481 100644
--- a/sdk/lib/_internal/lib/native_helper.dart
+++ b/sdk/lib/_internal/lib/native_helper.dart
@@ -442,7 +442,12 @@
const _baseHooks = const JS_CONST(r'''
function() {
- function typeNameInChrome(obj) { return obj.constructor.name; }
+ function typeNameInChrome(o) {
+ var name = o.constructor.name;
+ if (name) return name;
+ var s = Object.prototype.toString.call(o);
+ return s.substring(8, s.length - 1);
+ }
function getUnknownTag(object, tag) {
// This code really belongs in [getUnknownTagGenericBrowser] but having it
// here allows [getUnknownTag] to be tested on d8.
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index 06be67a..e19d9a0 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.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.
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:io';
import 'dart:math' as math;
diff --git a/sdk/lib/_internal/pub/lib/src/barback.dart b/sdk/lib/_internal/pub/lib/src/barback.dart
index 08e5665..bd06b66 100644
--- a/sdk/lib/_internal/pub/lib/src/barback.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback.dart
@@ -17,9 +17,31 @@
import 'log.dart' as log;
import 'package_graph.dart';
import 'utils.dart';
+import 'version.dart';
export 'barback/sources.dart' show WatcherType;
+/// The currently supported version of the Barback package that this version of
+/// pub works with.
+///
+/// Pub implicitly constrains barback to this version or later patch versions.
+///
+/// Barback is in a unique position. Pub imports it, so a copy of Barback is
+/// physically included in the SDK. Packages also depend on Barback (from
+/// pub.dartlang.org) when they implement their own transformers. Pub's plug-in
+/// API dynamically loads transformers into their own isolate.
+///
+/// This includes a string literal of Dart code ([_TRANSFORMER_ISOLATE] in
+/// load_transformers.dart). That code imports "package:barback/barback.dart".
+/// This string is included in the SDK, but that import is resolved using the
+/// application’s version of Barback. That means it must tightly control which
+/// version of Barback the application is using so that it's one that pub
+/// supports.
+///
+/// Whenever a new non-patch version of barback is published, this *must* be
+/// incremented to synchronize with that.
+final supportedVersion = new Version(0, 10, 0);
+
/// An identifier for a transformer and the configuration that will be passed to
/// it.
///
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 604a881..c4b0597 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -4,7 +4,8 @@
library pub.dart2js_transformer;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
+import 'dart:convert';
import 'dart:io';
import 'package:analyzer/analyzer.dart';
@@ -84,7 +85,7 @@
return null;
}
- var provider = new _BarbackInputProvider(_graph, transform);
+ var provider = new _BarbackCompilerProvider(_graph, transform);
// Create a "path" to the entrypoint script. The entrypoint may not
// actually be on disk, but this gives dart2js a root to resolve
@@ -100,22 +101,11 @@
// Need to report compile errors to the user in an easily visible way.
// Need to make sure paths in errors are mapped to the original source
// path so they can understand them.
- return dart.compile(entrypoint,
+ return dart.compile(entrypoint, provider,
packageRoot: packageRoot,
- minify: _mode == BarbackMode.RELEASE,
- inputProvider: provider.readStringFromUri,
- diagnosticHandler: provider.handleDiagnostic).then((js) {
- var id = transform.primaryInput.id.changeExtension(".dart.js");
- transform.addOutput(new Asset.fromString(id, js));
-
+ minify: _mode == BarbackMode.RELEASE).then((_) {
stopwatch.stop();
- transform.logger.info("Generated $id (${js.length} characters) in "
- "${stopwatch.elapsed}");
- }).catchError((error) {
- // The compile failed and errors have been reported through the
- // diagnostic handler, so just do nothing here.
- if (error is dart.CompilerException) return;
- throw error;
+ transform.logger.info("Took ${stopwatch.elapsed} to compile $id.");
});
}).whenComplete(() {
completer.complete();
@@ -124,14 +114,13 @@
}
}
-/// Defines methods implementig [CompilerInputProvider] and [DiagnosticHandler]
-/// for dart2js to use to load files from Barback and report errors.
+/// Defines an interface for dart2js to communicate with barback and pub.
///
/// Note that most of the implementation of diagnostic handling here was
/// copied from [FormattingDiagnosticHandler] in dart2js. The primary
/// difference is that it uses barback's logging code and, more importantly, it
/// handles missing source files more gracefully.
-class _BarbackInputProvider {
+class _BarbackCompilerProvider implements dart.CompilerProvider {
final PackageGraph _graph;
final Transform _transform;
@@ -166,10 +155,10 @@
compiler.Diagnostic.INFO.ordinal |
compiler.Diagnostic.VERBOSE_INFO.ordinal;
- _BarbackInputProvider(this._graph, this._transform);
+ _BarbackCompilerProvider(this._graph, this._transform);
/// A [CompilerInputProvider] for dart2js.
- Future<String> readStringFromUri(Uri resourceUri) {
+ Future<String> provideInput(Uri resourceUri) {
// We only expect to get absolute "file:" URLs from dart2js.
assert(resourceUri.isAbsolute);
assert(resourceUri.scheme == "file");
@@ -182,6 +171,29 @@
});
}
+ /// A [CompilerOutputProvider] for dart2js.
+ EventSink<String> provideOutput(String name, String extension) {
+ // Dart2js uses an empty string for the name of the entrypoint library.
+ // We only expect to get output files associated with that right now. For
+ // other files, we'd need some logic to determine the right relative path
+ // for it.
+ assert(name == "");
+
+ var primaryId = _transform.primaryInput.id;
+ var id = new AssetId(primaryId.package, "${primaryId.path}.$extension");
+
+ // Make a sink that dart2js can write to.
+ var sink = new StreamController<String>();
+
+ // dart2js gives us strings, but stream assets expect byte lists.
+ var stream = UTF8.encoder.bind(sink.stream);
+
+ // And give it to barback as a stream it can read from.
+ _transform.addOutput(new Asset.fromStream(id, stream));
+
+ return sink;
+ }
+
/// A [DiagnosticHandler] for dart2js, loosely based on
/// [FormattingDiagnosticHandler].
void handleDiagnostic(Uri uri, int begin, int end,
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
index 5418b91..1c2c38b 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
@@ -21,7 +21,7 @@
/// loaded, then adds the transformers to `server.barback`.
///
/// Any [builtInTransformers] that are provided will automatically be added to
-/// the end of every package's cascade.
+/// the end of the root package's cascade.
Future loadAllTransformers(BarbackServer server, PackageGraph graph,
BarbackMode mode, Iterable<Transformer> builtInTransformers) {
// In order to determine in what order we should load transformers, we need to
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
index aff85de..7c4e2a1 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
@@ -61,7 +61,9 @@
// TODO(nweiz): if no valid transformers are found, throw an error message
// describing candidates and why they were rejected.
- return mirrors.libraries[uri].classes.values.map((classMirror) {
+ return mirrors.libraries[uri].declarations.values.map((declaration) {
+ if (declaration is! ClassMirror) return null;
+ var classMirror = declaration;
if (classMirror.isPrivate) return null;
if (isAbstract(classMirror)) return null;
if (!classIsA(classMirror, transformerClass) &&
@@ -139,21 +141,15 @@
}
/// Returns the mirror for the root Object type.
-ClassMirror get objectMirror {
- if (_objectMirror == null) {
- _objectMirror = currentMirrorSystem()
- .libraries[Uri.parse('dart:core')]
- .classes[const Symbol('Object')];
- }
- return _objectMirror;
-}
-ClassMirror _objectMirror;
+ClassMirror get objectMirror => reflectClass(Object);
// TODO(nweiz): clean this up when issue 13248 is fixed.
MethodMirror getConstructor(ClassMirror classMirror, String constructor) {
var name = new Symbol("\${MirrorSystem.getName(classMirror.simpleName)}"
".\$constructor");
- return classMirror.constructors[name];
+ var candidate = classMirror.declarations[name];
+ if (candidate is MethodMirror && candidate.isConstructor) return candidate;
+ return null;
}
// TODO(nweiz): get rid of this when issue 12439 is fixed.
@@ -169,7 +165,7 @@
// TODO(nweiz): get rid of this when issue 12826 is fixed.
/// Returns whether or not [mirror] is an abstract class.
-bool isAbstract(ClassMirror mirror) => mirror.members.values
+bool isAbstract(ClassMirror mirror) => mirror.declarations.values
.any((member) => member is MethodMirror && member.isAbstract);
/// Converts [transformerOrGroup] into a serializable map.
@@ -299,26 +295,26 @@
/// property.
final String message;
- /// The exception's stack trace, or `null` if no stack trace was available.
- final Trace stackTrace;
+ /// The exception's stack chain, or `null` if no stack chain was available.
+ final Chain stackTrace;
- /// Loads a [CrossIsolateException] from a map.
+ /// Loads a [CrossIsolateException] from a serialized representation.
///
/// [error] should be the result of [CrossIsolateException.serialize].
CrossIsolateException.deserialize(Map error)
: type = error['type'],
message = error['message'],
stackTrace = error['stack'] == null ? null :
- new Trace.parse(error['stack']);
+ new Chain.parse(error['stack']);
- /// Serializes [error] to a map that can safely be passed across isolate
+ /// Serializes [error] to an object that can safely be passed across isolate
/// boundaries.
static Map serialize(error, [StackTrace stack]) {
if (stack == null && error is Error) stack = error.stackTrace;
return {
'type': error.runtimeType.toString(),
'message': getErrorMessage(error),
- 'stack': stack == null ? null : stack.toString()
+ 'stack': stack == null ? null : new Chain.forTrace(stack).toString()
};
}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/sources.dart b/sdk/lib/_internal/pub/lib/src/barback/sources.dart
index 8d2a79a..ece690b 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/sources.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/sources.dart
@@ -4,7 +4,7 @@
library pub.barback.sources;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index ffd7fff..221bc45 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -5,7 +5,7 @@
library pub.command;
import 'dart:io';
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/build.dart b/sdk/lib/_internal/pub/lib/src/command/build.dart
index ef2e80b..1c9e37e 100644
--- a/sdk/lib/_internal/pub/lib/src/command/build.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/build.dart
@@ -4,7 +4,7 @@
library pub.command.build;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache.dart b/sdk/lib/_internal/pub/lib/src/command/cache.dart
index 6479781..97e5dbe 100644
--- a/sdk/lib/_internal/pub/lib/src/command/cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/cache.dart
@@ -4,7 +4,7 @@
library pub.command.cache;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:convert';
import '../command.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/command/help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
index 9467721..f02841f 100644
--- a/sdk/lib/_internal/pub/lib/src/command/help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -4,7 +4,7 @@
library pub.command.help;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import '../command.dart';
import '../exit_codes.dart' as exit_codes;
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index 6a8b744..1cc95ac 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -4,7 +4,7 @@
library pub.command.lish;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:http/http.dart' as http;
diff --git a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
index 15fb4da..31c6916 100644
--- a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
@@ -4,7 +4,7 @@
library pub.command.list_package_dirs;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:convert';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index 0d07f7b..f6df4ce 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -4,7 +4,7 @@
library pub.command.serve;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:barback/barback.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/command/uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
index d02472b..330efcc 100644
--- a/sdk/lib/_internal/pub/lib/src/command/uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -4,7 +4,7 @@
library pub.command.uploader;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index fcd27b15..bf6cb2a 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -5,7 +5,7 @@
/// A library for compiling Dart code and manipulating analyzer parse trees.
library pub.dart;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:isolate';
import 'package:analyzer/analyzer.dart';
@@ -21,21 +21,38 @@
import 'sdk.dart' as sdk;
import 'utils.dart';
-/// Returns [entrypoint] compiled to JavaScript (or to Dart if [toDart] is
-/// true).
+/// Interface to communicate with dart2js.
+///
+/// This is basically an amalgamation of dart2js's
+/// [compiler.CompilerInputProvider], [compiler.CompilerOutputProvider], and
+/// [compiler.DiagnosticHandler] function types so that we can provide them
+/// as a single unit.
+abstract class CompilerProvider {
+ /// Given [uri], responds with a future that completes to the contents of
+ /// the input file at that URI.
+ ///
+ /// The future can complete to a string or a list of bytes.
+ Future/*<String | List<int>>*/ provideInput(Uri uri);
+
+ /// Reports a diagnostic message from dart2js to the user.
+ void handleDiagnostic(Uri uri, int begin, int end, String message,
+ compiler.Diagnostic kind);
+
+ /// Given a [name] (which will be "" for the entrypoint) and a file extension,
+ /// returns an [EventSink] that dart2js can write to to emit an output file.
+ EventSink<String> provideOutput(String name, String extension);
+}
+
+/// Compiles [entrypoint] to JavaScript (or to Dart if [toDart] is true) as
+/// well as any ancillary outputs dart2js creates.
+///
+/// Uses [provider] to communcate between dart2js and the caller. Returns a
+/// future that completes when compilation is done.
///
/// By default, the package root is assumed to be adjacent to [entrypoint], but
/// if [packageRoot] is passed that will be used instead.
-///
-/// If [inputProvider] and [diagnosticHandler] are omitted, uses a default
-/// [compiler.CompilerInputProvider] that loads directly from the filesystem.
-/// If either is provided, both must be.
-Future<String> compile(String entrypoint, {
- String packageRoot,
- bool toDart: false,
- bool minify: true,
- compiler.CompilerInputProvider inputProvider,
- compiler.DiagnosticHandler diagnosticHandler}) {
+Future compile(String entrypoint, CompilerProvider provider, {
+ String packageRoot, bool toDart: false, bool minify: true}) {
return new Future.sync(() {
var options = <String>['--categories=Client,Server'];
if (toDart) options.add('--output-type=dart');
@@ -45,27 +62,14 @@
packageRoot = path.join(path.dirname(entrypoint), 'packages');
}
- // Must either pass both of these or neither.
- if ((inputProvider == null) != (diagnosticHandler == null)) {
- throw new ArgumentError("If either inputProvider or diagnosticHandler "
- "is passed, then both must be.");
- }
-
- if (inputProvider == null) {
- var provider = new CompilerSourceFileProvider();
- inputProvider = provider.readStringFromUri;
- diagnosticHandler = new FormattingDiagnosticHandler(provider)
- .diagnosticHandler;
- }
-
return compiler.compile(
path.toUri(entrypoint),
path.toUri(appendSlash(_libPath)),
path.toUri(appendSlash(packageRoot)),
- inputProvider, diagnosticHandler, options).then((js) {
- if (js == null) throw new CompilerException(entrypoint);
- return js;
- });
+ provider.provideInput,
+ provider.handleDiagnostic,
+ options,
+ provider.provideOutput);
});
}
@@ -150,24 +154,17 @@
/// property.
final String message;
- /// The exception's stack trace, or `null` if no stack trace was available.
- final Trace stackTrace;
+ /// The exception's stack chain, or `null` if no stack chain was available.
+ final Chain stackTrace;
/// Loads a [CrossIsolateException] from a serialized representation.
///
/// [error] should be the result of [CrossIsolateException.serialize].
- factory CrossIsolateException.deserialize(Map error) {
- var type = error['type'];
- var message = error['message'];
- var stackTrace = error['stack'] == null ? null :
- new Trace.parse(error['stack']);
- return new CrossIsolateException._(type, message, stackTrace);
- }
-
- /// Loads a [CrossIsolateException] from a serialized representation.
- ///
- /// [error] should be the result of [CrossIsolateException.serialize].
- CrossIsolateException._(this.type, this.message, this.stackTrace);
+ CrossIsolateException.deserialize(Map error)
+ : type = error['type'],
+ message = error['message'],
+ stackTrace = error['stack'] == null ? null :
+ new Chain.parse(error['stack']);
/// Serializes [error] to an object that can safely be passed across isolate
/// boundaries.
@@ -176,15 +173,9 @@
return {
'type': error.runtimeType.toString(),
'message': getErrorMessage(error),
- 'stack': stack == null ? null : stack.toString()
+ 'stack': stack == null ? null : new Chain.forTrace(stack).toString()
};
}
String toString() => "$message\n$stackTrace";
}
-
-/// An exception thrown when dart2js generates compiler errors.
-class CompilerException extends ApplicationException {
- CompilerException(String entrypoint)
- : super('Failed to compile "$entrypoint".');
-}
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index 65cecc3..cf7e5d0 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -4,7 +4,7 @@
library pub.entrypoint;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
@@ -14,9 +14,10 @@
import 'log.dart' as log;
import 'package.dart';
import 'package_graph.dart';
+import 'solver/version_solver.dart';
import 'system_cache.dart';
import 'utils.dart';
-import 'solver/version_solver.dart';
+import 'version.dart';
/// Pub operates over a directed graph of dependencies that starts at a root
/// "entrypoint" package. This is typically the package where the current
@@ -146,9 +147,18 @@
// Warn the user if any overrides were in effect.
if (result.overrides.isNotEmpty) {
var buffer = new StringBuffer();
- buffer.write("Warning: You are overriding these dependencies:");
+ buffer.write("Warning: You are using these overridden dependencies:");
for (var override in result.overrides) {
- buffer.write("\n- $override");
+ var source = cache.sources[override.source];
+ buffer.write("\n- ${override.name}");
+ if (override.constraint != VersionConstraint.any) {
+ buffer.write(" version ${override.constraint}");
+ }
+ if (source != cache.sources.defaultSource) {
+ var description = source.formatDescription(root.dir,
+ override.description);
+ buffer.write(" (from ${override.source} $description)");
+ }
}
log.warning(buffer);
}
@@ -178,10 +188,8 @@
/// This will be `false` if there is no lockfile at all, or if the pubspec
/// contains dependencies that are not in the lockfile or that don't match
/// what's in there.
- bool isLockFileUpToDate() {
- var lockFile = loadLockFile();
-
- checkDependency(package) {
+ bool _isLockFileUpToDate(LockFile lockFile) {
+ return root.immediateDependencies.every((package) {
var locked = lockFile.packages[package.name];
if (locked == null) return false;
@@ -189,36 +197,75 @@
if (!package.constraint.allows(locked.version)) return false;
var source = cache.sources[package.source];
- if (!source.descriptionsEqual(package.description, locked.description)) {
- return false;
- }
+ if (source == null) return false;
- return true;
- }
+ return source.descriptionsEqual(package.description, locked.description);
+ });
+ }
- if (!root.dependencies.every(checkDependency)) return false;
- if (!root.devDependencies.every(checkDependency)) return false;
+ /// Determines whether all of the packages in the lockfile are already
+ /// installed and available.
+ ///
+ /// Note: this assumes [isLockFileUpToDate] has already been called and
+ /// returned `true`.
+ Future<bool> _arePackagesAvailable(LockFile lockFile) {
+ return Future.wait(lockFile.packages.values.map((package) {
+ var source = cache.sources[package.source];
- return true;
+ // This should only be called after [_isLockFileUpToDate] has returned
+ // `true`, which ensures all of the sources in the lock file are valid.
+ assert(source != null);
+
+ // We only care about cached sources. Uncached sources aren't "installed".
+ // If one of those is missing, we want to show the user the file not
+ // found error later since installing won't accomplish anything.
+ if (!source.shouldCache) return new Future.value(true);
+
+ // Get the directory.
+ return source.getDirectory(package).then((dir) {
+ // See if the directory is there and looks like a package.
+ return dirExists(dir) || fileExists(path.join(dir, "pubspec.yaml"));
+ });
+ })).then((results) {
+ // Make sure they are all true.
+ return results.every((result) => result);
+ });
}
/// Gets dependencies if the lockfile is out of date with respect to the
/// pubspec.
Future ensureLockFileIsUpToDate() {
return new Future.sync(() {
- if (isLockFileUpToDate()) return null;
+ var lockFile = loadLockFile();
- if (lockFileExists) {
- log.message(
- "Your pubspec has changed, so we need to update your lockfile:");
- } else {
- log.message(
- "You don't have a lockfile, so we need to generate that:");
+ // If we don't have a current lock file, we definitely need to install.
+ if (!_isLockFileUpToDate(lockFile)) {
+ if (lockFileExists) {
+ log.message(
+ "Your pubspec has changed, so we need to update your lockfile:");
+ } else {
+ log.message(
+ "You don't have a lockfile, so we need to generate that:");
+ }
+
+ return false;
}
- return getDependencies().then((_) {
- log.message("Got dependencies!");
+ // If we do have a lock file, we still need to make sure the packages
+ // are actually installed. The user may have just gotten a package that
+ // includes a lockfile.
+ return _arePackagesAvailable(lockFile).then((available) {
+ if (!available) {
+ log.message(
+ "You are missing some dependencies, so we need to install them "
+ "first:");
+ }
+
+ return available;
});
+ }).then((upToDate) {
+ if (upToDate) return null;
+ return getDependencies().then((_) => log.message("Got dependencies!"));
});
}
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index ae0410f..52a284c 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -194,9 +194,9 @@
return _completer.future.whenComplete(action);
}
- Future timeout(Duration timeLimit, [void onTimeout()]) {
+ Future timeout(Duration timeLimit, {void onTimeout()}) {
_hasListeners = true;
- return _completer.future.timeout(timeLimit, onTimeout);
+ return _completer.future.timeout(timeLimit, onTimeout: onTimeout);
}
Stream asStream() {
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index e692a47..e94e493 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -5,7 +5,7 @@
/// Helper functionality for invoking Git.
library pub.git;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'io.dart';
import 'log.dart' as log;
diff --git a/sdk/lib/_internal/pub/lib/src/http.dart b/sdk/lib/_internal/pub/lib/src/http.dart
index 969042f..017b387 100644
--- a/sdk/lib/_internal/pub/lib/src/http.dart
+++ b/sdk/lib/_internal/pub/lib/src/http.dart
@@ -5,7 +5,7 @@
/// Helpers for dealing with HTTP.
library pub.http;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 90b06f9..533790c 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -5,7 +5,7 @@
/// Helper functionality to make working with IO easier.
library pub.io;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
@@ -16,11 +16,20 @@
import 'error_group.dart';
import 'log.dart' as log;
+import 'pool.dart';
import 'sdk.dart' as sdk;
import 'utils.dart';
export 'package:http/http.dart' show ByteStream;
+/// The pool used for restricting access to asynchronous operations that consume
+/// file descriptors.
+///
+/// The maximum number of allocated descriptors is based on empirical tests that
+/// indicate that beyond 32, additional file reads don't provide substantial
+/// additional throughput.
+final _descriptorPool = new Pool(32);
+
/// Returns whether or not [entry] is nested somewhere within [dir]. This just
/// performs a path comparison; it doesn't look at the actual filesystem.
bool isBeneath(String entry, String dir) {
@@ -177,11 +186,21 @@
/// Writes [stream] to a new file at path [file]. Will replace any file already
/// at that path. Completes when the file is done being written.
Future<String> createFileFromStream(Stream<List<int>> stream, String file) {
- log.io("Creating $file from stream.");
+ // TODO(nweiz): remove extra logging when we figure out the windows bot issue.
+ log.io("Creating $file from stream (is the stream broadcast? "
+ "${stream.isBroadcast}).");
- return stream.pipe(new File(file).openWrite()).then((_) {
- log.fine("Created $file from stream.");
- return file;
+ var pair = tee(stream);
+ pair.first.listen(
+ (data) => log.io("stream emitted ${data.length} bytes"),
+ onError: (error, st) => log.io("stream emitted $error\n$st"),
+ onDone: () => log.io("stream is done"));
+
+ return _descriptorPool.withResource(() {
+ return pair.last.pipe(new File(file).openWrite()).then((_) {
+ log.fine("Created $file from stream.");
+ return file;
+ });
});
}
@@ -207,27 +226,11 @@
return dir;
}
-/// Ensures that [dirPath] and all its parent directories exist. If they don't
+/// Ensures that [dir] and all its parent directories exist. If they don't
/// exist, creates them.
-String ensureDir(String dirPath) {
- log.fine("Ensuring directory $dirPath exists.");
- var dir = new Directory(dirPath);
- if (dirPath == '.' || dirExists(dirPath)) return dirPath;
-
- ensureDir(path.dirname(dirPath));
-
- try {
- createDir(dirPath);
- } on FileSystemException catch (ex) {
- // Error 17 means the directory already exists (or 183 on Windows).
- if (ex.osError.errorCode == 17 || ex.osError.errorCode == 183) {
- log.fine("Got 'already exists' error when creating directory.");
- } else {
- throw ex;
- }
- }
-
- return dirPath;
+String ensureDir(String dir) {
+ new Directory(dir).createSync(recursive: true);
+ return dir;
}
/// Creates a temp directory in [dir], whose name will be [prefix] with
@@ -486,21 +489,23 @@
/// the inherited variables.
Future<PubProcessResult> runProcess(String executable, List<String> args,
{workingDir, Map<String, String> environment}) {
- return _doProcess(Process.run, executable, args, workingDir, environment)
- .then((result) {
- // TODO(rnystrom): Remove this and change to returning one string.
- List<String> toLines(String output) {
- var lines = splitLines(output);
- if (!lines.isEmpty && lines.last == "") lines.removeLast();
- return lines;
- }
+ return _descriptorPool.withResource(() {
+ return _doProcess(Process.run, executable, args, workingDir, environment)
+ .then((result) {
+ // TODO(rnystrom): Remove this and change to returning one string.
+ List<String> toLines(String output) {
+ var lines = splitLines(output);
+ if (!lines.isEmpty && lines.last == "") lines.removeLast();
+ return lines;
+ }
- var pubResult = new PubProcessResult(toLines(result.stdout),
- toLines(result.stderr),
- result.exitCode);
+ var pubResult = new PubProcessResult(toLines(result.stdout),
+ toLines(result.stderr),
+ result.exitCode);
- log.processResult(executable, pubResult);
- return pubResult;
+ log.processResult(executable, pubResult);
+ return pubResult;
+ });
});
}
@@ -511,9 +516,16 @@
/// [environment] is provided, that will be used to augment (not replace) the
/// the inherited variables.
Future<PubProcess> startProcess(String executable, List<String> args,
- {workingDir, Map<String, String> environment}) =>
- _doProcess(Process.start, executable, args, workingDir, environment)
- .then((process) => new PubProcess(process));
+ {workingDir, Map<String, String> environment}) {
+ return _descriptorPool.request().then((resource) {
+ return _doProcess(Process.start, executable, args, workingDir, environment)
+ .then((ioProcess) {
+ var process = new PubProcess(ioProcess);
+ process.exitCode.whenComplete(resource.release);
+ return process;
+ });
+ });
+}
/// A wrapper around [Process] that exposes `dart:async`-style APIs.
class PubProcess {
@@ -630,10 +642,12 @@
/// Note that timing out will not cancel the asynchronous operation behind
/// [input].
Future timeout(Future input, int milliseconds, String description) {
+ // TODO(nwiez): Replace this with [Future.timeout].
var completer = new Completer();
- var timer = new Timer(new Duration(milliseconds: milliseconds), () {
+ var duration = new Duration(milliseconds: milliseconds);
+ var timer = new Timer(duration, () {
completer.completeError(new TimeoutException(
- 'Timed out while $description.'),
+ 'Timed out while $description.', duration),
new Trace.current());
});
input.then((value) {
@@ -750,79 +764,61 @@
/// considered to be [baseDir], which defaults to the current working directory.
/// Returns a [ByteStream] that will emit the contents of the archive.
ByteStream createTarGz(List contents, {baseDir}) {
- var buffer = new StringBuffer();
- buffer.write('Creating .tag.gz stream containing:\n');
- contents.forEach((file) => buffer.write('$file\n'));
- log.fine(buffer.toString());
+ return new ByteStream(futureStream(new Future.sync(() {
+ var buffer = new StringBuffer();
+ buffer.write('Creating .tag.gz stream containing:\n');
+ contents.forEach((file) => buffer.write('$file\n'));
+ log.fine(buffer.toString());
- var controller = new StreamController<List<int>>(sync: true);
+ var controller = new StreamController<List<int>>(sync: true);
- if (baseDir == null) baseDir = path.current;
- baseDir = path.absolute(baseDir);
- contents = contents.map((entry) {
- entry = path.absolute(entry);
- if (!isBeneath(entry, baseDir)) {
- throw new ArgumentError('Entry $entry is not inside $baseDir.');
+ if (baseDir == null) baseDir = path.current;
+ baseDir = path.absolute(baseDir);
+ contents = contents.map((entry) {
+ entry = path.absolute(entry);
+ if (!isBeneath(entry, baseDir)) {
+ throw new ArgumentError('Entry $entry is not inside $baseDir.');
+ }
+ return path.relative(entry, from: baseDir);
+ }).toList();
+
+ if (Platform.operatingSystem != "windows") {
+ var args = ["--create", "--gzip", "--directory", baseDir];
+ args.addAll(contents);
+ // TODO(nweiz): It's possible that enough command-line arguments will
+ // make the process choke, so at some point we should save the arguments
+ // to a file and pass them in via --files-from for tar and -i@filename
+ // for 7zip.
+ return startProcess("tar", args).then((process) => process.stdout);
}
- return path.relative(entry, from: baseDir);
- }).toList();
- if (Platform.operatingSystem != "windows") {
- var args = ["--create", "--gzip", "--directory", baseDir];
- args.addAll(contents);
- // TODO(nweiz): It's possible that enough command-line arguments will make
- // the process choke, so at some point we should save the arguments to a
- // file and pass them in via --files-from for tar and -i@filename for 7zip.
- startProcess("tar", args).then((process) {
- store(process.stdout, controller);
- }).catchError((e, stackTrace) {
- // We don't have to worry about double-signaling here, since the store()
- // above will only be reached if startProcess succeeds.
- controller.addError(e, stackTrace);
- controller.close();
+ // Don't use [withTempDir] here because we don't want to delete the temp
+ // directory until the returned stream has closed.
+ var tempDir = createSystemTempDir();
+ return new Future.sync(() {
+ // Create the tar file.
+ var tarFile = path.join(tempDir, "intermediate.tar");
+ var args = ["a", "-w$baseDir", tarFile];
+ args.addAll(contents.map((entry) => '-i!$entry'));
+
+ // We're passing 'baseDir' both as '-w' and setting it as the working
+ // directory explicitly here intentionally. The former ensures that the
+ // files added to the archive have the correct relative path in the
+ // archive. The latter enables relative paths in the "-i" args to be
+ // resolved.
+ return runProcess(pathTo7zip, args, workingDir: baseDir).then((_) {
+ // GZIP it. 7zip doesn't support doing both as a single operation.
+ // Send the output to stdout.
+ args = ["a", "unused", "-tgzip", "-so", tarFile];
+ return startProcess(pathTo7zip, args);
+ }).then((process) => process.stdout);
+ }).then((stream) {
+ return stream.transform(onDoneTransformer(() => deleteEntry(tempDir)));
+ }).catchError((e) {
+ deleteEntry(tempDir);
+ throw e;
});
- return new ByteStream(controller.stream);
- }
-
- withTempDir((tempDir) {
- // Create the tar file.
- var tarFile = path.join(tempDir, "intermediate.tar");
- var args = ["a", "-w$baseDir", tarFile];
- args.addAll(contents.map((entry) => '-i!$entry'));
-
- // We're passing 'baseDir' both as '-w' and setting it as the working
- // directory explicitly here intentionally. The former ensures that the
- // files added to the archive have the correct relative path in the archive.
- // The latter enables relative paths in the "-i" args to be resolved.
- return runProcess(pathTo7zip, args, workingDir: baseDir).then((_) {
- // GZIP it. 7zip doesn't support doing both as a single operation. Send
- // the output to stdout.
- args = ["a", "unused", "-tgzip", "-so", tarFile];
- return startProcess(pathTo7zip, args);
- }).then((process) {
- // Ignore 7zip's stderr. 7zip writes its normal output to stderr. We don't
- // want to show that since it's meaningless.
- //
- // TODO(rnystrom): Should log the stderr and display it if an actual error
- // occurs.
- return store(process.stdout, controller);
- });
- }).catchError((e, stackTrace) {
- // We don't have to worry about double-signaling here, since the store()
- // above will only be reached if everything succeeds.
- controller.addError(e, stackTrace);
- controller.close();
- });
- return new ByteStream(controller.stream);
-}
-
-/// Exception thrown when an operation times out.
-class TimeoutException implements Exception {
- final String message;
-
- const TimeoutException(this.message);
-
- String toString() => message;
+ })));
}
/// Contains the results of invoking a [Process] and waiting for it to complete.
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index 83e5edc..10f220d 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -6,7 +6,7 @@
library pub.log;
import 'dart:io';
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'io.dart';
import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/oauth2.dart b/sdk/lib/_internal/pub/lib/src/oauth2.dart
index 1bc1d9f..7146817 100644
--- a/sdk/lib/_internal/pub/lib/src/oauth2.dart
+++ b/sdk/lib/_internal/pub/lib/src/oauth2.dart
@@ -4,7 +4,7 @@
library pub.oauth2;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:io';
import 'package:oauth2/oauth2.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 6b31e56..e783221 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -40,6 +40,25 @@
/// The dependency overrides this package specifies in its pubspec.
List<PackageDep> get dependencyOverrides => pubspec.dependencyOverrides;
+ /// All immediate dependencies this package specifies.
+ ///
+ /// This includes regular, dev dependencies, and overrides.
+ Set<PackageDep> get immediateDependencies {
+ var deps = {};
+
+ addToMap(dep) {
+ deps[dep.name] = dep;
+ }
+
+ dependencies.forEach(addToMap);
+ devDependencies.forEach(addToMap);
+
+ // Make sure to add these last so they replace normal dependencies.
+ dependencyOverrides.forEach(addToMap);
+
+ return deps.values.toSet();
+ }
+
/// Returns the path to the README file at the root of the entrypoint, or null
/// if no README file is found. If multiple READMEs are found, this uses the
/// same conventions as pub.dartlang.org for choosing the primary one: the
diff --git a/sdk/lib/_internal/pub/lib/src/pool.dart b/sdk/lib/_internal/pub/lib/src/pool.dart
new file mode 100644
index 0000000..24100ca
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/pool.dart
@@ -0,0 +1,141 @@
+// 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 barback.pool;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:stack_trace/stack_trace.dart';
+
+import 'utils.dart';
+
+// TODO(nweiz): put this somewhere that it can be shared between packages.
+/// Manages an abstract pool of resources with a limit on how many may be in use
+/// at once.
+///
+/// When a resource is needed, the user should call [request]. When the returned
+/// future completes with a [PoolResource], the resource may be allocated. Once
+/// the resource has been released, the user should call [PoolResource.release].
+/// The pool will ensure that only a certain number of [PoolResource]s may be
+/// allocated at once.
+class Pool {
+ /// Completers for requests beyond the first [_maxAllocatedResources].
+ ///
+ /// When an item is released, the next element of [_requestedResources] will
+ /// be completed.
+ final _requestedResources = new Queue<Completer<PoolResource>>();
+
+ /// The maximum number of resources that may be allocated at once.
+ final int _maxAllocatedResources;
+
+ /// The number of resources that are currently allocated.
+ int _allocatedResources = 0;
+
+ /// The timeout timer.
+ ///
+ /// If [_timeout] isn't null, this timer is set as soon as the resource limit
+ /// is reached and is reset every time an resource is released or a new
+ /// resource is requested. If it fires, that indicates that the caller became
+ /// deadlocked, likely due to files waiting for additional files to be read
+ /// before they could be closed.
+ Timer _timer;
+
+ /// The amount of time to wait before timing out the pending resources.
+ Duration _timeout;
+
+ /// Creates a new pool with the given limit on how many resources may be
+ /// allocated at once.
+ ///
+ /// If [timeout] is passed, then if that much time passes without any activity
+ /// all pending [request] futures will throw an exception. This is indented
+ /// to avoid deadlocks.
+ Pool(this._maxAllocatedResources, {Duration timeout})
+ : _timeout = timeout;
+
+ /// Request a [PoolResource].
+ ///
+ /// If the maximum number of resources is already allocated, this will delay
+ /// until one of them is released.
+ Future<PoolResource> request() {
+ if (_allocatedResources < _maxAllocatedResources) {
+ _allocatedResources++;
+ return new Future.value(new PoolResource._(this));
+ } else {
+ var completer = new Completer<PoolResource>();
+ _requestedResources.add(completer);
+ _resetTimer();
+ return completer.future;
+ }
+ }
+
+ /// Requests a resource for the duration of [callback], which may return a
+ /// Future.
+ ///
+ /// The return value of [callback] is piped to the returned Future.
+ Future withResource(callback()) {
+ return request().then((resource) =>
+ syncFuture(callback).whenComplete(resource.release));
+ }
+
+ /// If there are any pending requests, this will fire the oldest one.
+ void _onResourceReleased() {
+ if (_requestedResources.isEmpty) {
+ _allocatedResources--;
+ if (_timer != null) {
+ _timer.cancel();
+ _timer = null;
+ }
+ return;
+ }
+
+ _resetTimer();
+ var pending = _requestedResources.removeFirst();
+ pending.complete(new PoolResource._(this));
+ }
+
+ /// A resource has been requested, allocated, or released.
+ void _resetTimer() {
+ if (_timer != null) _timer.cancel();
+ if (_timeout == null) {
+ _timer = null;
+ } else {
+ _timer = new Timer(_timeout, _onTimeout);
+ }
+ }
+
+ /// Handles [_timer] timing out by causing all pending resource completers to
+ /// emit exceptions.
+ void _onTimeout() {
+ for (var completer in _requestedResources) {
+ completer.completeError("Pool deadlock: all resources have been "
+ "allocated for too long.", new Chain.current());
+ }
+ _requestedResources.clear();
+ _timer = null;
+ }
+}
+
+/// A member of a [Pool].
+///
+/// A [PoolResource] is a token that indicates that a resource is allocated.
+/// When the associated resource is released, the user should call [release].
+class PoolResource {
+ final Pool _pool;
+
+ /// Whether [this] has been released yet.
+ bool _released = false;
+
+ PoolResource._(this._pool);
+
+ /// Tells the parent [Pool] that the resource associated with this resource is
+ /// no longer allocated, and that a new [PoolResource] may be allocated.
+ void release() {
+ if (_released) {
+ throw new StateError("A PoolResource may only be released once.");
+ }
+ _released = true;
+ _pool._onResourceReleased();
+ }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
index c38295c..5ff0d08 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -36,6 +36,7 @@
import 'dart:async';
import 'dart:collection' show Queue;
+import '../barback.dart' as barback;
import '../lock_file.dart';
import '../log.dart' as log;
import '../package.dart';
@@ -594,9 +595,24 @@
/// Gets the combined [VersionConstraint] currently being placed on package
/// [name].
VersionConstraint _getConstraint(String name) {
- return _getDependencies(name)
+ var constraint = _getDependencies(name)
.map((dep) => dep.dep.constraint)
.fold(VersionConstraint.any, (a, b) => a.intersect(b));
+
+ // If the package is barback, pub has an implicit version constraint on it
+ // since pub itself uses barback too. Note that we don't check for the
+ // hosted source here because we still want to do this even when people on
+ // the Dart team are on the bleeding edge and have a path dependency on the
+ // tip version of barback in the Dart repo.
+ if (name == "barback") {
+ var range = new VersionRange(
+ min: barback.supportedVersion, includeMin: true,
+ max: barback.supportedVersion.nextMinor, includeMax: false);
+ constraint = constraint.intersect(range);
+ _solver.logSolve('add implicit $range constraint to barback');
+ }
+
+ return constraint;
}
/// Gets the package [name] that's currently contained in the lockfile if it
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index 78b4450..a27a909 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -4,7 +4,7 @@
library pub.source;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
@@ -228,12 +228,23 @@
}
/// When a [LockFile] is serialized, it uses this method to get the
- /// [description] in the right format. [containingPath] references the
- /// containing directory of the root package.
+ /// [description] in the right format.
+ ///
+ /// [containingPath] is the containing directory of the root package.
dynamic serializeDescription(String containingPath, description) {
return description;
}
+ /// When a package [description] is shown to the user, this is called to
+ /// convert it into a human-friendly form.
+ ///
+ /// By default, it just converts the description to a string, but sources
+ /// may customize this. [containingPath] is the containing directory of the
+ /// root package.
+ String formatDescription(String containingPath, description) {
+ return description.toString();
+ }
+
/// Returns whether or not [description1] describes the same package as
/// [description2] for this source. This method should be light-weight. It
/// doesn't need to validate that either package exists.
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index 7caf1dae..5a7f5e5 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -4,7 +4,7 @@
library pub.source.git;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/source/hosted.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
index 295d2a5..1429e28 100644
--- a/sdk/lib/_internal/pub/lib/src/source/hosted.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -4,7 +4,7 @@
library pub.source.hosted;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:io' as io;
import "dart:convert";
@@ -30,10 +30,7 @@
/// Gets the default URL for the package server for hosted dependencies.
static String get defaultUrl {
var url = io.Platform.environment["PUB_HOSTED_URL"];
- if (url != null) {
- log.fine("Got server $url from PUB_HOSTED_URL.");
- return url;
- }
+ if (url != null) return url;
return "https://pub.dartlang.org";
}
@@ -86,7 +83,7 @@
"$server/packages/$package/versions/$version.tar.gz");
log.io("Get package from $url.");
- log.message('Downloading $id...');
+ log.message('Downloading ${id.name} ${id.version}...');
// Download and extract the archive to a temp directory.
var tempDir = systemCache.createTempDir();
diff --git a/sdk/lib/_internal/pub/lib/src/source/path.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
index 4d57069..76892e1 100644
--- a/sdk/lib/_internal/pub/lib/src/source/path.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -4,7 +4,7 @@
library pub.source.path;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
@@ -113,6 +113,16 @@
return description;
}
+ /// Converts a parsed relative path to its original relative form.
+ String formatDescription(String containingPath, description) {
+ var sourcePath = description["path"];
+ if (description["relative"]) {
+ sourcePath = path.relative(description['path'], from: containingPath);
+ }
+
+ return sourcePath;
+ }
+
/// Ensures that [description] is a valid path description and returns a
/// normalized path to the package.
///
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index fe28502..bfc6cea 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -4,7 +4,7 @@
library pub.system_cache;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 711b224..222941a 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -77,10 +77,71 @@
Future<List> get future => _completer.future;
}
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
+/// Returns a buffered stream that will emit the same values as the stream
+/// returned by [future] once [future] completes.
+///
+/// If [future] completes to an error, the return value will emit that error and
+/// then close.
+///
+/// If [broadcast] is true, a broadcast stream is returned. This assumes that
+/// the stream returned by [future] will be a broadcast stream as well.
+/// [broadcast] defaults to false.
+Stream futureStream(Future<Stream> future, {bool broadcast: false}) {
+ var subscription;
+ var controller;
+
+ future = future.catchError((e, stackTrace) {
+ // Since [controller] is synchronous, it's likely that emitting an error
+ // will cause it to be cancelled before we call close.
+ if (controller != null) controller.addError(e, stackTrace);
+ if (controller != null) controller.close();
+ controller = null;
+ });
+
+ onListen() {
+ future.then((stream) {
+ if (controller == null) return;
+ subscription = stream.listen(
+ controller.add,
+ onError: controller.addError,
+ onDone: controller.close);
+ });
+ }
+
+ onCancel() {
+ if (subscription != null) subscription.cancel();
+ subscription = null;
+ controller = null;
+ }
+
+ if (broadcast) {
+ controller = new StreamController.broadcast(
+ sync: true, onListen: onListen, onCancel: onCancel);
+ } else {
+ controller = new StreamController(
+ sync: true, onListen: onListen, onCancel: onCancel);
+ }
+ return controller.stream;
+}
+
/// Like [new Future], but avoids around issue 11911 by using [new Future.value]
/// under the covers.
Future newFuture(callback()) => new Future.value().then((_) => callback());
+/// Returns a [StreamTransformer] that will call [onDone] when the stream
+/// completes.
+///
+/// The stream will be passed through unchanged.
+StreamTransformer onDoneTransformer(void onDone()) {
+ return new StreamTransformer.fromHandlers(handleDone: (sink) {
+ onDone();
+ sink.close();
+ });
+}
+
// TODO(rnystrom): Move into String?
/// Pads [source] to [length] by adding spaces at the end.
String padRight(String source, int length) {
diff --git a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
index ab98a18..d6abf6d 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
@@ -4,7 +4,7 @@
library pub.validator.compiled_dartdoc;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 01ddf91..6039fc5 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -4,7 +4,7 @@
library pub.validator.directory;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/lib.dart b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
index 622ee03..98bed28 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/lib.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
@@ -4,7 +4,7 @@
library pub.validator.lib;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index 0948860..222d693 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.dart
@@ -4,7 +4,7 @@
library pub.validator.license;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/name.dart b/sdk/lib/_internal/pub/lib/src/validator/name.dart
index d62325d..1285fb1 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/name.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/name.dart
@@ -4,7 +4,7 @@
library pub.validator.name;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
index d14e674..9f30d65 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
@@ -4,7 +4,7 @@
library pub.validator.utf8_readme;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:convert';
import '../entrypoint.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/version.dart b/sdk/lib/_internal/pub/lib/src/version.dart
index dcba9d4..e8738ff 100644
--- a/sdk/lib/_internal/pub/lib/src/version.dart
+++ b/sdk/lib/_internal/pub/lib/src/version.dart
@@ -64,7 +64,7 @@
Version._(this.major, this.minor, this.patch, String preRelease, String build,
this._text)
- : preRelease = preRelease == null ? [] : _splitParts(preRelease),
+ : preRelease = preRelease == null ? [] : _splitParts(preRelease),
build = build == null ? [] : _splitParts(build) {
if (major < 0) throw new ArgumentError(
'Major version must be non-negative.');
@@ -154,6 +154,45 @@
/// Whether or not this is a pre-release version.
bool get isPreRelease => preRelease.isNotEmpty;
+ /// Gets the next major version number that follows this one.
+ ///
+ /// If this version is a pre-release of a major version release (i.e. the
+ /// minor and patch versions are zero), then it just strips the pre-release
+ /// suffix. Otherwise, it increments the major version and resets the minor
+ /// and patch.
+ Version get nextMajor {
+ if (isPreRelease && minor == 0 && patch == 0) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major + 1, 0, 0);
+ }
+
+ /// Gets the next minor version number that follows this one.
+ ///
+ /// If this version is a pre-release of a minor version release (i.e. the
+ /// patch version is zero), then it just strips the pre-release suffix.
+ /// Otherwise, it increments the minor version and resets the patch.
+ Version get nextMinor {
+ if (isPreRelease && patch == 0) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major, minor + 1, 0);
+ }
+
+ /// Gets the next patch version number that follows this one.
+ ///
+ /// If this version is a pre-release, then it just strips the pre-release
+ /// suffix. Otherwise, it increments the patch version.
+ Version get nextPatch {
+ if (isPreRelease) {
+ return new Version(major, minor, patch);
+ }
+
+ return new Version(major, minor, patch + 1);
+ }
+
/// Tests if [other] matches this version exactly.
bool allows(Version other) => this == other;
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index bf04ee6..3e49ab9 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -2,14 +2,13 @@
# 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.
-test/serve/missing_file_test: Pass, Fail # Issue 12570
-
test/hosted/version_negotiation_test: Pass, Timeout # Issue 14346
test/upgrade/hosted/upgrade_removed_constraints_test: Pass, Fail # Issue 15349
[ $runtime == vm && $system == windows ]
test/serve/watch_removed_file_test: Pass, Fail # Issue 13026
+test/serve/missing_file_test: Pass, Fail # Issue 15431
# Pub only runs on the VM, so just rule out all compilers.
[ $compiler == dart2js || $compiler == dart2dart ]
diff --git a/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart b/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
index 725fac5..bc8319f 100644
--- a/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
+++ b/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
@@ -10,9 +10,6 @@
main() {
initConfig();
- // TODO(rnystrom): Should also add tests that other transformers work
- // (#14556).
-
integration("compiles Dart entrypoints to JS", () {
// Dart2js can take a long time to compile dart code, so we increase the
// timeout to cope with that.
@@ -32,16 +29,20 @@
// TODO(rnystrom): If we flesh out the command-line output, validate that
// here.
schedulePub(args: ["build"],
- output: new RegExp(r"Built 2 files!"),
+ output: new RegExp(r"Built 6 files!"),
exitCode: 0);
d.dir(appPath, [
d.dir('build', [
d.matcherFile('file.dart.js', isNot(isEmpty)),
+ d.matcherFile('file.dart.precompiled.js', isNot(isEmpty)),
+ d.matcherFile('file.dart.js.map', isNot(isEmpty)),
d.nothing('file.dart'),
d.nothing('lib.dart'),
d.dir('subdir', [
d.matcherFile('subfile.dart.js', isNot(isEmpty)),
+ d.matcherFile('subfile.dart.precompiled.js', isNot(isEmpty)),
+ d.matcherFile('subfile.dart.js.map', isNot(isEmpty)),
d.nothing('subfile.dart')
])
])
diff --git a/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart b/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
index a8e22f4..9bd4ff4 100644
--- a/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
+++ b/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
@@ -62,12 +62,14 @@
pubGet();
schedulePub(args: ["build"],
- output: new RegExp(r"Built 8 files!"),
+ output: new RegExp(r"Built 12 files!"),
exitCode: 0);
d.dir(appPath, [
d.dir('build', [
d.matcherFile('file.dart.js', isNot(isEmpty)),
+ d.matcherFile('file.dart.precompiled.js', isNot(isEmpty)),
+ d.matcherFile('file.dart.js.map', isNot(isEmpty)),
d.dir('packages', [d.dir('browser', [
d.file('dart.js', 'contents of dart.js'),
d.file('interop.js', 'contents of interop.js')
@@ -77,7 +79,9 @@
d.file('dart.js', 'contents of dart.js'),
d.file('interop.js', 'contents of interop.js')
])]),
- d.matcherFile('subfile.dart.js', isNot(isEmpty))
+ d.matcherFile('subfile.dart.js', isNot(isEmpty)),
+ d.matcherFile('subfile.dart.precompiled.js', isNot(isEmpty)),
+ d.matcherFile('subfile.dart.js.map', isNot(isEmpty))
])
])
]).validate();
diff --git a/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart b/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
index 0778ab1..fd8a7ac 100644
--- a/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
+++ b/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
@@ -47,12 +47,14 @@
]).create();
schedulePub(args: ["build"],
- output: new RegExp(r"Built 1 file!"),
+ output: new RegExp(r"Built 3 files!"),
exitCode: 0);
d.dir(appPath, [
d.dir('build', [
- d.matcherFile('main.dart.js', isNot(isEmpty))
+ d.matcherFile('main.dart.js', isNot(isEmpty)),
+ d.matcherFile('main.dart.precompiled.js', isNot(isEmpty)),
+ d.matcherFile('main.dart.js.map', isNot(isEmpty))
])
]).validate();
});
diff --git a/sdk/lib/_internal/pub/test/dependency_override_test.dart b/sdk/lib/_internal/pub/test/dependency_override_test.dart
index c930dd5..7e0f229 100644
--- a/sdk/lib/_internal/pub/test/dependency_override_test.dart
+++ b/sdk/lib/_internal/pub/test/dependency_override_test.dart
@@ -2,6 +2,8 @@
// 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:path/path.dart' as path;
+
import 'descriptor.dart' as d;
import 'test_pub.dart';
@@ -86,27 +88,33 @@
integration("warns about overridden dependencies", () {
servePackages([
packageMap("foo", "1.0.0"),
- packageMap("bar", "1.0.0"),
- packageMap("baz", "1.0.0")
+ packageMap("bar", "1.0.0")
]);
+ d.dir("baz", [
+ d.libDir("baz"),
+ d.libPubspec("baz", "0.0.1")
+ ]).create();
+
d.dir(appPath, [
d.pubspec({
"name": "myapp",
"dependency_overrides": {
"foo": "any",
"bar": "any",
- "baz": "any"
+ "baz": {"path": "../baz"}
}
})
]).create();
+ var bazPath = path.join("..", "baz");
+
schedulePub(args: [command.name], output: command.success, error:
"""
- Warning: You are overriding these dependencies:
- - bar any from hosted (bar)
- - baz any from hosted (baz)
- - foo any from hosted (foo)
+ Warning: You are using these overridden dependencies:
+ - bar
+ - baz (from path $bazPath)
+ - foo
""");
});
});
diff --git a/sdk/lib/_internal/pub/test/descriptor/tar.dart b/sdk/lib/_internal/pub/test/descriptor/tar.dart
index f297abb..2a04a03 100644
--- a/sdk/lib/_internal/pub/test/descriptor/tar.dart
+++ b/sdk/lib/_internal/pub/test/descriptor/tar.dart
@@ -4,7 +4,7 @@
library descriptor.tar;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'package:path/path.dart' as path;
import 'package:scheduled_test/scheduled_test.dart';
diff --git a/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
new file mode 100644
index 0000000..02f2363
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
@@ -0,0 +1,84 @@
+// 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.
+
+import 'descriptor.dart' as d;
+import 'test_pub.dart';
+import '../lib/src/barback.dart' as barback;
+import '../lib/src/version.dart';
+
+main() {
+ initConfig();
+
+ var previousVersion = new Version(
+ barback.supportedVersion.major, barback.supportedVersion.minor - 1, 0);
+
+ forBothPubGetAndUpgrade((command) {
+ integration("implicitly constrains barback to versions pub supports", () {
+ servePackages([
+ packageMap("barback", previousVersion.toString()),
+ packageMap("barback", barback.supportedVersion.toString()),
+ packageMap("barback", barback.supportedVersion.nextPatch.toString()),
+ packageMap("barback", barback.supportedVersion.nextMinor.toString())
+ ]);
+
+ d.appDir({
+ "barback": "any"
+ }).create();
+
+ pubCommand(command);
+
+ d.packagesDir({
+ "barback": barback.supportedVersion.nextPatch.toString()
+ }).validate();
+ });
+
+ integration("discovers transitive dependency on barback", () {
+ servePackages([
+ packageMap("barback", previousVersion.toString()),
+ packageMap("barback", barback.supportedVersion.toString()),
+ packageMap("barback", barback.supportedVersion.nextPatch.toString()),
+ packageMap("barback", barback.supportedVersion.nextMinor.toString())
+ ]);
+
+ d.dir("foo", [
+ d.libDir("foo", "foo 0.0.1"),
+ d.libPubspec("foo", "0.0.1", deps: {
+ "barback": "any"
+ })
+ ]).create();
+
+ d.appDir({
+ "foo": {"path": "../foo"}
+ }).create();
+
+ pubCommand(command);
+
+ d.packagesDir({
+ "barback": barback.supportedVersion.nextPatch.toString(),
+ "foo": "0.0.1"
+ }).validate();
+ });
+ });
+
+ integration("unlock if the locked version doesn't meet pub's constraint", () {
+ servePackages([
+ packageMap("barback", previousVersion.toString()),
+ packageMap("barback", barback.supportedVersion.toString())
+ ]);
+
+ d.appDir({"barback": "any"}).create();
+
+ // Hand-create a lockfile to pin barback to an older version.
+ createLockFile("myapp", hosted: {
+ "barback": previousVersion.toString()
+ });
+
+ pubGet();
+
+ // It should be upgraded.
+ d.packagesDir({
+ "barback": barback.supportedVersion.toString()
+ }).validate();
+ });
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/io_test.dart b/sdk/lib/_internal/pub/test/io_test.dart
index c4f5151..bc8d708 100644
--- a/sdk/lib/_internal/pub/test/io_test.dart
+++ b/sdk/lib/_internal/pub/test/io_test.dart
@@ -4,7 +4,7 @@
library io_test;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_test.dart
new file mode 100644
index 0000000..5c4ed3a
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_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.
+
+library pub_tests;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ // This is a regression test for https://dartbug.com/15180.
+ initConfig();
+ integration("does not get if the locked version matches the override", () {
+ d.dir("foo", [
+ d.libPubspec("foo", "0.0.1"),
+ d.libDir("foo")
+ ]).create();
+
+ // Get "foo" into the lock file.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": "any"
+ },
+ "dependency_overrides": {
+ "foo": {
+ "path": "../foo",
+ "version": ">=0.0.1"
+ }
+ }
+ })
+ ]).create();
+ pubGet();
+
+ pubServe(shouldGetFirst: false);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_test.dart b/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_test.dart
new file mode 100644
index 0000000..8926faf
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_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.
+
+library pub_tests;
+
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../lib/src/io.dart';
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("gets first if a dependency is not installed", () {
+ servePackages([packageMap("foo", "1.2.3")]);
+
+ d.appDir({"foo": "1.2.3"}).create();
+
+ // Run pub to get a lock file.
+ pubGet();
+
+ // Delete the system cache so it isn't installed any more.
+ schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+ pubServe(shouldGetFirst: true, numDownloads: 1);
+ requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo 1.2.3";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_test.dart b/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_test.dart
new file mode 100644
index 0000000..963eb09
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_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.
+
+library pub_tests;
+
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../lib/src/io.dart';
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+ initConfig();
+ integration("gets first if a transitive dependency is not installed", () {
+ servePackages([packageMap("bar", "1.2.3")]);
+
+ d.dir("foo", [
+ d.libPubspec("foo", "1.0.0", deps: {
+ "bar": "any"
+ }),
+ d.libDir("foo")
+ ]).create();
+
+ d.appDir({
+ "foo": {"path": "../foo"}
+ }).create();
+
+ // Run pub to install everything.
+ pubGet();
+
+ // Delete the system cache so bar isn't installed any more.
+ schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+ pubServe(shouldGetFirst: true, numDownloads: 1);
+ requestShouldSucceed("packages/bar/bar.dart", 'main() => "bar 1.2.3";');
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
index b57a984..43f1966 100644
--- a/sdk/lib/_internal/pub/test/serve/utils.dart
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -114,11 +114,13 @@
/// Schedules starting the "pub serve" process and records its port number for
/// future requests.
///
-/// If [shouldGetFirst] is `true`, validates that pub get is run first.
+/// If [shouldGetFirst] is `true`, validates that pub get is run first. In that
+/// case, you can also pass [numDownloads] to specify how many packages should
+/// be downloaded during the get.
///
/// Returns the `pub serve` process.
ScheduledProcess pubServe({bool shouldGetFirst: false,
- Iterable<String> args}) {
+ Iterable<String> args, int numDownloads: 0}) {
_pubServer = startPubServe(args);
currentSchedule.onComplete.schedule(() {
@@ -133,9 +135,16 @@
expect(_pubServer.nextLine(),
completion(anyOf(
startsWith("Your pubspec has changed"),
- startsWith("You don't have a lockfile"))));
+ startsWith("You don't have a lockfile"),
+ startsWith("You are missing some dependencies"))));
expect(_pubServer.nextLine(),
completion(startsWith("Resolving dependencies...")));
+
+ for (var i = 0; i < numDownloads; i++) {
+ expect(_pubServer.nextLine(),
+ completion(startsWith("Downloading")));
+ }
+
expect(_pubServer.nextLine(),
completion(equals("Got dependencies!")));
}
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index f398887..6eef80b 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -8,7 +8,7 @@
/// tests like that.
library test_pub;
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
@@ -32,6 +32,7 @@
import '../lib/src/log.dart' as log;
import '../lib/src/package.dart';
import '../lib/src/safe_http_server.dart';
+import '../lib/src/source/hosted.dart';
import '../lib/src/source/path.dart';
import '../lib/src/source_registry.dart';
import '../lib/src/system_cache.dart';
@@ -331,9 +332,12 @@
void _integration(String description, void body(), [Function testFn]) {
testFn(description, () {
+ // TODO(nweiz): remove this when issue 15362 is fixed.
+ currentSchedule.timeout *= 2;
+
// The windows bots are very slow, so we increase the default timeout.
if (Platform.operatingSystem == "windows") {
- currentSchedule.timeout = new Duration(seconds: 10);
+ currentSchedule.timeout *= 2;
}
_sandboxDir = createSystemTempDir();
@@ -395,7 +399,7 @@
if (outputJson == null) {
_validateOutput(failures, 'stdout', output, results[0]);
- return;
+ return null;
}
// Allow the expected JSON to contain futures.
@@ -608,12 +612,15 @@
/// Create a lock file for [package] without running `pub get`.
///
-/// This creates a lock file with only path dependencies. [sandbox] is a list of
-/// dependencies to be found in the sandbox directory. [pkg] is a list of
-/// packages in the Dart repo's "pkg" directory; each package listed here and
-/// all its dependencies will be linked to the version in the Dart repo.
+/// [sandbox] is a list of path dependencies to be found in the sandbox
+/// directory. [pkg] is a list of packages in the Dart repo's "pkg" directory;
+/// each package listed here and all its dependencies will be linked to the
+/// version in the Dart repo.
+///
+/// [hosted] is a list of package names to version strings for dependencies on
+/// hosted packages.
void createLockFile(String package, {Iterable<String> sandbox,
- Iterable<String> pkg}) {
+ Iterable<String> pkg, Map<String, Version> hosted}) {
var dependencies = {};
if (sandbox != null) {
@@ -650,8 +657,16 @@
lockFile.packages[name] = id;
});
- var sources = new SourceRegistry()
- ..register(new PathSource());
+ if (hosted != null) {
+ hosted.forEach((name, version) {
+ var id = new PackageId(name, 'hosted', new Version.parse(version), name);
+ lockFile.packages[name] = id;
+ });
+ }
+
+ var sources = new SourceRegistry();
+ sources.register(new HostedSource());
+ sources.register(new PathSource());
d.file(path.join(package, 'pubspec.lock'),
lockFile.serialize(null, sources)).create();
diff --git a/sdk/lib/_internal/pub/test/version_test.dart b/sdk/lib/_internal/pub/test/version_test.dart
index f2c8c2c..0e7452a 100644
--- a/sdk/lib/_internal/pub/test/version_test.dart
+++ b/sdk/lib/_internal/pub/test/version_test.dart
@@ -11,10 +11,13 @@
main() {
initConfig();
- final v123 = new Version.parse('1.2.3');
final v114 = new Version.parse('1.1.4');
+ final v123 = new Version.parse('1.2.3');
final v124 = new Version.parse('1.2.4');
+ final v130 = new Version.parse('1.3.0');
+ final v140 = new Version.parse('1.4.0');
final v200 = new Version.parse('2.0.0');
+ final v201 = new Version.parse('2.0.1');
final v234 = new Version.parse('2.3.4');
final v250 = new Version.parse('2.5.0');
final v300 = new Version.parse('3.0.0');
@@ -118,6 +121,46 @@
expect(v123.isEmpty, isFalse);
});
+ test('nextMajor', () {
+ expect(v123.nextMajor, equals(v200));
+ expect(v114.nextMajor, equals(v200));
+ expect(v200.nextMajor, equals(v300));
+
+ // Ignores pre-release if not on a major version.
+ expect(new Version.parse('1.2.3-dev').nextMajor, equals(v200));
+
+ // Just removes it if on a major version.
+ expect(new Version.parse('2.0.0-dev').nextMajor, equals(v200));
+
+ // Strips build suffix.
+ expect(new Version.parse('1.2.3+patch').nextMajor, equals(v200));
+ });
+
+ test('nextMinor', () {
+ expect(v123.nextMinor, equals(v130));
+ expect(v130.nextMinor, equals(v140));
+
+ // Ignores pre-release if not on a minor version.
+ expect(new Version.parse('1.2.3-dev').nextMinor, equals(v130));
+
+ // Just removes it if on a minor version.
+ expect(new Version.parse('1.3.0-dev').nextMinor, equals(v130));
+
+ // Strips build suffix.
+ expect(new Version.parse('1.2.3+patch').nextMinor, equals(v130));
+ });
+
+ test('nextPatch', () {
+ expect(v123.nextPatch, equals(v124));
+ expect(v200.nextPatch, equals(v201));
+
+ // Just removes pre-release version if present.
+ expect(new Version.parse('1.2.4-dev').nextPatch, equals(v124));
+
+ // Strips build suffix.
+ expect(new Version.parse('1.2.3+patch').nextPatch, equals(v124));
+ });
+
test('parse()', () {
expect(new Version.parse('0.0.0'), equals(new Version(0, 0, 0)));
expect(new Version.parse('12.34.56'), equals(new Version(12, 34, 56)));
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 7b77f8b..18ff654 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -130,6 +130,16 @@
/** Whether there are currently one or more subscribers. */
bool get hasListener => !_isEmpty;
+ /**
+ * Test whether the stream has exactly one listener.
+ *
+ * Assumes that the stream has a listener (not [_isEmpty]).
+ */
+ bool get _hasOneListener {
+ assert(!_isEmpty);
+ return identical(_next._next, this);
+ }
+
/** Whether an event is being fired (sent to some, but not all, listeners). */
bool get _isFiring => (_state & _STATE_FIRING) != 0;
@@ -321,6 +331,16 @@
void _sendData(T data) {
if (_isEmpty) return;
+ if (_hasOneListener) {
+ _state |= _BroadcastStreamController._STATE_FIRING;
+ _BroadcastSubscription subscription = _next;
+ subscription._add(data);
+ _state &= ~_BroadcastStreamController._STATE_FIRING;
+ if (_isEmpty) {
+ _callOnCancel();
+ }
+ return;
+ }
_forEachListener((_BufferingStreamSubscription<T> subscription) {
subscription._add(data);
});
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index db26cee..f18cb1dd 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -422,19 +422,28 @@
* If `onTimeout` is omitted, a timeout will cause the returned future to
* complete with a [TimeoutException].
*/
- Future timeout(Duration timeLimit, [void onTimeout()]);
+ Future timeout(Duration timeLimit, {void onTimeout()});
}
/**
* Thrown when a scheduled timeout happens while waiting for an async result.
*/
class TimeoutException implements Exception {
- /** The duration that was exceeded without a result. */
+ /** Description of the cause of the timeout. */
+ final String message;
+ /** The duration that was exceeded. */
final Duration duration;
- TimeoutException(this.duration);
+ TimeoutException(this.message, [this.duration]);
- String toString() => "Timeout after $duration";
+ String toString() {
+ if (message != null) {
+ if (duration != null) return "TimeoutException after $duration: $message";
+ return "TimeoutException: $message";
+ }
+ if (duration != null) return "TimeoutException after $duration";
+ return "TimeoutException";
+ }
}
/**
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index fb1280c..114614c 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -538,13 +538,14 @@
}
}
- Future timeout(Duration timeLimit, [void onTimeout()]) {
+ Future timeout(Duration timeLimit, {void onTimeout()}) {
if (_isComplete) return new _Future.immediate(this);
_Future result = new _Future();
Timer timer;
if (onTimeout == null) {
timer = new Timer(timeLimit, () {
- result._completeError(new TimeoutException(timeLimit));
+ result._completeError(new TimeoutException("Future not completed",
+ timeLimit));
});
} else {
Zone zone = Zone.current;
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 58bb090..957ca2e 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -649,7 +649,7 @@
* as [test] returns [:true:] for the event data. The stream is done
* when either this stream is done, or when this stream first provides
* a value that [test] doesn't accept.
- *
+ *
* Stops listening to the stream after the accepted elements.
*
* Internally the method cancels its subscription after these elements. This
@@ -960,6 +960,88 @@
cancelOnError: true);
return future;
}
+
+ /**
+ * Creates a new stream with the same events as this stream.
+ *
+ * Whenever more than [timeLimit] passes between two events from this stream,
+ * the [onTimeout] function is called.
+ *
+ * The countdown doesn't start until the returned stream is listened to.
+ * The countdown is reset every time an event is forwarded from this stream,
+ * or when the stream is paused and resumed.
+ *
+ * The [onTimeout] function is called with one argument: an
+ * [EventSink] that allows putting events into the returned stream.
+ * This `EventSink` is only valid during the call to `onTimeout`.
+ *
+ * If `onTimeout` is omitted, a timeout will just put a [TimeoutException]
+ * into the error channel of the returned stream.
+ */
+ Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) {
+ StreamSubscription<T> subscription;
+ _StreamController controller;
+ // The following variables are set on listen.
+ Timer timer;
+ Zone zone;
+ Function timeout;
+
+ void onData(T event) {
+ timer.cancel();
+ controller.add(event);
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+ void onError(error, StackTrace stackTrace) {
+ timer.cancel();
+ controller.addError(error, stackTrace);
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+ void onDone() {
+ timer.cancel();
+ controller.close();
+ }
+ controller = new _SyncStreamController(
+ () {
+ // This is the onListen callback for of controller.
+ // It runs in the same zone that the subscription was created in.
+ // Use that zone for creating timers and running the onTimeout
+ // callback.
+ zone = Zone.current;
+ if (onTimeout == null) {
+ timeout = () {
+ controller.addError(new TimeoutException("No stream event",
+ timeLimit));
+ };
+ } else {
+ onTimeout = zone.registerUnaryCallback(onTimeout);
+ _ControllerEventSinkWrapper wrapper =
+ new _ControllerEventSinkWrapper(null);
+ timeout = () {
+ wrapper._sink = controller; // Only valid during call.
+ zone.runUnaryGuarded(onTimeout, wrapper);
+ wrapper._sink = null;
+ };
+ }
+
+ subscription = this.listen(onData, onError: onError, onDone: onDone);
+ timer = zone.createTimer(timeLimit, timeout);
+ },
+ () {
+ timer.cancel();
+ subscription.pause();
+ },
+ () {
+ subscription.resume();
+ timer = zone.createTimer(timeLimit, timeout);
+ },
+ () {
+ timer.cancel();
+ Future result = subscription.cancel();
+ subscription = null;
+ return result;
+ });
+ return controller.stream;
+ }
}
/**
@@ -1282,3 +1364,18 @@
*/
Future cancel();
}
+
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _ControllerEventSinkWrapper<T> implements EventSink<T> {
+ EventSink _sink;
+ _ControllerEventSinkWrapper(this._sink);
+
+ void add(T data) { _sink.add(data); }
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+ void close() { _sink.close(); }
+}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index fd104b0..3d7a2b3 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -144,17 +144,17 @@
void onData(void handleData(T event)) {
if (handleData == null) handleData = _nullDataHandler;
- _onData = Zone.current.registerUnaryCallback(handleData);
+ _onData = _zone.registerUnaryCallback(handleData);
}
void onError(Function handleError) {
if (handleError == null) handleError = _nullErrorHandler;
- _onError = _registerErrorHandler(handleError, Zone.current);
+ _onError = _registerErrorHandler(handleError, _zone);
}
void onDone(void handleDone()) {
if (handleDone == null) handleDone = _nullDoneHandler;
- _onDone = Zone.current.registerCallback(handleDone);
+ _onDone = _zone.registerCallback(handleDone);
}
void pause([Future resumeSignal]) {
diff --git a/sdk/lib/core/annotations.dart b/sdk/lib/core/annotations.dart
index 68ba572..7b8462f 100644
--- a/sdk/lib/core/annotations.dart
+++ b/sdk/lib/core/annotations.dart
@@ -113,21 +113,30 @@
}
/**
- * The annotation `@proxy` marks a class as implementing members through
- * `noSuchMethod`.
+ * The annotation `@proxy` marks a class as implementing interfaces and members
+ * dynamically through `noSuchMethod`.
*
- * The annotation applies to concrete classes. It is not inherited by
- * subclasses.
+ * The annotation applies to any class. It is inherited by subclasses from both
+ * superclass and interfaces.
*
- * The marked class is considerer to implement any method, getter or setter
- * declared by its interface, even if there is no implementation in the
- * class. It will not generate the warning that is otherwise specified for an
- * unimplemented method in a non-abstract class.
+ * If a class is annotated with `@proxy`, or it implements any class that is
+ * annotated, then the class is considered to implement any interface and
+ * any member with regard to static type analysis. As such, it is not a static
+ * type warning to assign the object to a variable of any type, and it is not
+ * a static type warning to access any member of the object.
+ *
+ * This only applies to static type warnings. The runtime type of the object
+ * is unaffected. It is not considered to implement any special interfaces at
+ * runtime, so assigning it to a typed variable may fail in checked mode, and
+ * testing it with the `is` operator will not work for any type except the
+ * ones it actually implements.
*
* Tools that understand `@proxy` should tell the user if a class using `@proxy`
* does not override the `noSuchMethod` declared on [Object].
*
- * The intent of the `@proxy` notation is to avoid irrelevant warnings when
- * a class implements its interface through `noSuchMethod`.
+ * The intent of the `@proxy` notation is to create objects that implement a
+ * type (or multiple types) that are not known at compile time. If the types
+ * are known at compile time, a class can be written that implements these
+ * types.
*/
const Object proxy = const _Proxy();
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 8b27a25..65f888e 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -155,7 +155,7 @@
import "dart:collection";
import "dart:_collection-dev" hide Symbol;
import "dart:_collection-dev" as _collection_dev;
-import "dart:convert" show UTF8, Encoding;
+import "dart:convert" show UTF8, LATIN1, Encoding;
import "dart:math" show Random; // Used by List.shuffle.
part "annotations.dart";
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index c6bb4f8..7e4bf45 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -124,9 +124,9 @@
/**
* Returns the remainder of the truncating division of `this` by [other].
*
- * The result `r` of this operation satisfies: `this == this ~/ other + r`.
- * As a consequence the remainder `r` has the same sign as the dividend
- * `this`.
+ * The result `r` of this operation satisfies:
+ * `this == (this ~/ other) * other + r`.
+ * As a consequence the remainder `r` has the same sign as the divider `this`.
*/
num remainder(num other);
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index f645d2c..d2e2a7a 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -681,7 +681,7 @@
while (index < length) {
- // Normalize percent encoding to uppercase and don't encode
+ // Normalize percent-encoding to uppercase and don't encode
// unreserved characters.
if (component.codeUnitAt(index) == _PERCENT) {
if (length < index + 2) {
@@ -1114,11 +1114,23 @@
* for encoding the posting of a HTML form as a query string
* component.
*
- * Spaces will be replaced with plus and all characters except for
- * uppercase and lowercase letters, decimal digits and the
- * characters `-._~`. Note that the set of characters encoded is a
- * superset of what HTML 4.01 says as it refers to RFC 1738 for
- * reserved characters.
+ * Encode the string [component] according to the HTML 4.01 rules
+ * for encoding the posting of a HTML form as a query string
+ * component.
+
+ * The component is first encoded to bytes using [encoding].
+ * The default is to use [UTF8] encoding, which preserves all
+ * the characters that don't need encoding.
+
+ * Then the resulting bytes are "percent-encoded". This transforms
+ * spaces (U+0020) to a plus sign ('+') and all bytes that are not
+ * the ASCII decimal digits, letters or one of '-._~' are written as
+ * a percent sign '%' followed by the two-digit hexadecimal
+ * representation of the byte.
+
+ * Note that the set of characters which are percent-encoded is a
+ * superset of what HTML 4.01 requires, since it refers to RFC 1738
+ * for reserved characters.
*
* When manually encoding query components remember to encode each
* part separately before building the query string.
@@ -1130,8 +1142,10 @@
* See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
* details.
*/
- static String encodeQueryComponent(String component) {
- return _uriEncode(_unreservedTable, component, spaceToPlus: true);
+ static String encodeQueryComponent(String component,
+ {Encoding encoding: UTF8}) {
+ return _uriEncode(
+ _unreservedTable, component, encoding: encoding, spaceToPlus: true);
}
/**
@@ -1353,6 +1367,7 @@
}
// Frequently used character codes.
+ static const int _SPACE = 0x20;
static const int _DOUBLE_QUOTE = 0x22;
static const int _PERCENT = 0x25;
static const int _ASTERISK = 0x2A;
@@ -1382,36 +1397,29 @@
* that appear in [canonicalTable], and returns the escaped string.
*/
static String _uriEncode(List<int> canonicalTable,
- String text,
- {bool spaceToPlus: false}) {
- byteToHex(int v) {
- final String hex = '0123456789ABCDEF';
- return '%${hex[v >> 4]}${hex[v & 0x0f]}';
+ String text,
+ {Encoding encoding: UTF8,
+ bool spaceToPlus: false}) {
+ byteToHex(byte, buffer) {
+ const String hex = '0123456789ABCDEF';
+ buffer.writeCharCode(hex.codeUnitAt(byte >> 4));
+ buffer.writeCharCode(hex.codeUnitAt(byte & 0x0f));
}
+ // Encode the string into bytes then generate an ASCII only string
+ // by percent encoding selected bytes.
StringBuffer result = new StringBuffer();
- for (int i = 0; i < text.length; i++) {
- int ch = text.codeUnitAt(i);
- if (ch < 128 && ((canonicalTable[ch >> 4] & (1 << (ch & 0x0f))) != 0)) {
- result.write(text[i]);
- } else if (spaceToPlus && text[i] == " ") {
- result.write("+");
+ var bytes = encoding.encode(text);
+ for (int i = 0; i < bytes.length; i++) {
+ int byte = bytes[i];
+ if (byte < 128 &&
+ ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+ result.writeCharCode(byte);
+ } else if (spaceToPlus && byte == _SPACE) {
+ result.writeCharCode(_PLUS);
} else {
- if (ch >= 0xD800 && ch < 0xDC00) {
- // Low surrogate. We expect a next char high surrogate.
- ++i;
- int nextCh = text.length == i ? 0 : text.codeUnitAt(i);
- if (nextCh >= 0xDC00 && nextCh < 0xE000) {
- // convert the pair to a U+10000 codepoint
- ch = 0x10000 + ((ch - 0xD800) << 10) + (nextCh - 0xDC00);
- } else {
- throw new ArgumentError('Malformed URI');
- }
- }
- // TODO(floitsch): don't allocate a new string.
- for (int codepoint in UTF8.encode(new String.fromCharCode(ch))) {
- result.write(byteToHex(codepoint));
- }
+ result.writeCharCode(_PERCENT);
+ byteToHex(byte, result);
}
}
return result.toString();
@@ -1455,32 +1463,40 @@
static String _uriDecode(String text,
{bool plusToSpace: false,
Encoding encoding: UTF8}) {
- StringBuffer result = new StringBuffer();
- List<int> codepoints = new List<int>();
- for (int i = 0; i < text.length;) {
- int ch = text.codeUnitAt(i);
- if (ch != _PERCENT) {
- if (plusToSpace && ch == _PLUS) {
- result.write(" ");
- } else {
- result.writeCharCode(ch);
- }
- i++;
+ // First check whether there is any characters which need special handling.
+ bool simple = true;
+ for (int i = 0; i < text.length && simple; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ simple = codeUnit != _PERCENT && codeUnit != _PLUS;
+ }
+ List<int> bytes;
+ if (simple) {
+ if (encoding == UTF8 || encoding == LATIN1) {
+ return text;
} else {
- codepoints.clear();
- while (ch == _PERCENT) {
- if (++i > text.length - 2) {
+ bytes = text.codeUnits;
+ }
+ } else {
+ bytes = new List();
+ for (int i = 0; i < text.length; i++) {
+ var codeUnit = text.codeUnitAt(i);
+ if (codeUnit > 127) {
+ throw new ArgumentError("Illegal percent encoding in URI");
+ }
+ if (codeUnit == _PERCENT) {
+ if (i + 3 > text.length) {
throw new ArgumentError('Truncated URI');
}
- codepoints.add(_hexCharPairToByte(text, i));
+ bytes.add(_hexCharPairToByte(text, i + 1));
i += 2;
- if (i == text.length) break;
- ch = text.codeUnitAt(i);
+ } else if (plusToSpace && codeUnit == _PLUS) {
+ bytes.add(_SPACE);
+ } else {
+ bytes.add(codeUnit);
}
- result.write(encoding.decode(codepoints));
}
}
- return result.toString();
+ return encoding.decode(bytes);
}
static bool _isAlphabeticCharacter(int codeUnit)
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 944d6e6..a5c5443 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -34418,10 +34418,8 @@
var options = JS('=Object', '{prototype: #}', proto);
- if (baseClassName != 'HTMLElement') {
- if (extendsTagName != null) {
- JS('=Object', '#.extends = #', options, extendsTagName);
- }
+ if (extendsTagName != null) {
+ JS('=Object', '#.extends = #', options, extendsTagName);
}
JS('void', '#.register(#, #)', document, tag, options);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 18735d0..29a417a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -27945,13 +27945,13 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _createObjectURL_1(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
return _createObjectURL_2(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_3(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
+ if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_4(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -36918,7 +36918,7 @@
throw new UnsupportedError("Invalid custom element from $libName.");
}
var className = MirrorSystem.getName(cls.simpleName);
- var createdConstructor = cls.constructors[new Symbol('$className.created')];
+ var createdConstructor = cls.declarations[new Symbol('$className.created')];
if (createdConstructor == null ||
createdConstructor is! MethodMirror ||
!createdConstructor.isConstructor) {
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 896ef26..0a8d230 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -370,9 +370,9 @@
*/
Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL,
bool recursive: false})
- => new _FileSystemWatcher(_trimTrailingPathSeparators(path),
- events,
- recursive).stream;
+ => _FileSystemWatcher.watch(_trimTrailingPathSeparators(path),
+ events,
+ recursive);
Future<FileSystemEntity> _delete({bool recursive: false});
void _deleteSync({bool recursive: false});
@@ -741,9 +741,8 @@
}
-abstract class _FileSystemWatcher {
- external factory _FileSystemWatcher(String path, int events, bool recursive);
+class _FileSystemWatcher {
+ external static Stream<FileSystemEvent> watch(
+ String path, int events, bool recursive);
external static bool get isSupported;
-
- Stream<FileSystemEvent> get stream;
}
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 7a4f917..3c0f0fe 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -14,16 +14,37 @@
}
/**
- * Exit the Dart VM process immediately with the given [status] code.
+ * Exit the Dart VM process immediately with the given exit code.
*
* This does not wait for any asynchronous operations to terminate. Using
* [exit] is therefore very likely to lose data.
+ *
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and Mac OS 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
+ * result in an actual exit code of 255 being reported.
+ *
+ * On Windows the exit code can be set to any 32-bit value. However
+ * some of these values are reserved for reporting system errors like
+ * crashes.
+ *
+ * Besides this the Dart executable itself uses an exit code of `254`
+ * for reporting compile time errors and an exit code of `255` for
+ * reporting runtime error (unhandled exception).
+ *
+ * Due to these facts it is recommended to only use exit codes in the
+ * range [0..127] for communicating the result of running a Dart
+ * program to the surrounding environment. This will avoid any
+ * cross-platform issues.
*/
-void exit(int status) {
- if (status is !int) {
- throw new ArgumentError("exit: int status expected");
+void exit(int code) {
+ if (code is !int) {
+ throw new ArgumentError("Integer value for exit code expected");
}
- _ProcessUtils._exit(status);
+ _ProcessUtils._exit(code);
}
/**
@@ -32,12 +53,15 @@
* The exit code is global for the Dart VM and the last assignment to
* exitCode from any isolate determines the exit code of the Dart VM
* on normal termination.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
*/
-set exitCode(int status) {
- if (status is !int) {
- throw new ArgumentError("setExitCode: int status expected");
+set exitCode(int code) {
+ if (code is !int) {
+ throw new ArgumentError("Integer value for exit code expected");
}
- _ProcessUtils._setExitCode(status);
+ _ProcessUtils._setExitCode(code);
}
/**
@@ -185,25 +209,16 @@
/**
* Returns the standard output stream of the process as a [:Stream:].
- *
- * Throws an [UnsupportedError] if the process is
- * non-interactive.
*/
Stream<List<int>> get stdout;
/**
* Returns the standard error stream of the process as a [:Stream:].
- *
- * Throws an [UnsupportedError] if the process is
- * non-interactive.
*/
Stream<List<int>> get stderr;
/**
* Returns the standard input stream of the process as an [IOSink].
- *
- * Throws an [UnsupportedError] if the process is
- * non-interactive.
*/
IOSink get stdin;
@@ -216,8 +231,24 @@
* Returns a [:Future:] which completes with the exit code of the process
* when the process completes.
*
- * Throws an [UnsupportedError] if the process is
- * non-interactive.
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and Mac 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..0[,
+ * where the absolute value of the exit code is the signal
+ * number. For example, if a process crashes due to a segmentation
+ * violation the exit code will be -11, as the signal SIGSEGV has the
+ * number 11.
+ *
+ * On Windows a process can report any 32-bit value as an exit
+ * code. When returning the exit code this exit code is turned into
+ * a signed value. Some special values are used to report
+ * termination due to some system event. E.g. if a process crashes
+ * due to an access violation the 32-bit exit code is `0xc0000005`,
+ * which will be returned as the negative number `-1073741819`. To
+ * get the original 32-bit value use `(0x100000000 + exitCode) &
+ * 0xffffffff`.
*/
Future<int> exitCode;
@@ -245,6 +276,9 @@
abstract class ProcessResult {
/**
* Exit code for the process.
+ *
+ * See [Process.exitCode] for more information in the exit code
+ * value.
*/
int get exitCode;
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index f1ceec5..2f78958 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -145,6 +145,11 @@
String get name;
/**
+ * Get the index of the [NetworkInterface].
+ */
+ String get index;
+
+ /**
* Get a list of [InternetAddress]s currently bound to this
* [NetworkInterface].
*/
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 1d7b277..f03b618 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -29,7 +29,10 @@
}
timer._milliSeconds = repeating ? milliSeconds : -1;
timer._addTimerToList();
- timer._notifyEventHandler();
+ if (identical(timer, _timers.first)) {
+ // The new timer is the first in queue. Update event handler.
+ timer._notifyEventHandler();
+ }
return timer;
}
@@ -72,9 +75,8 @@
_wakeupTime += _milliSeconds;
}
- // Adds a timer to the timer list and resets the native timer if it is the
- // earliest timer in the list. Timers with the same wakeup time are enqueued
- // in order and notified in FIFO order.
+ // Adds a timer to the timer list. Timers with the same wakeup time are
+ // enqueued in order and notified in FIFO order.
void _addTimerToList() {
_Timer entry = _timers.isEmpty ? null : _timers.first;
while (entry != null) {
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index ce9c8e7..28d7174 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -1104,7 +1104,7 @@
}
/**
- * EXPERIMENTAL API: Description of how "dart:mirrors" is used.
+ * Annotation describing how "dart:mirrors" is used (EXPERIMENTAL).
*
* When used as metadata on an import of "dart:mirrors" in library *L*, this
* class describes how "dart:mirrors" is used by library *L* unless overridden.
@@ -1124,7 +1124,7 @@
*
* class Foo {
* noSuchMethod(Invocation invocation) {
- * print(Mirrors.getName(invocation.memberName));
+ * print(MirrorSystem.getName(invocation.memberName));
* }
* }
*
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 6a4e0f1..83044ce 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -456,16 +456,78 @@
JS('ByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
}
+
+// TODO(sra): Move this type to a public name in a private library so that other
+// platform libraries like dart:html and dart:webaudio can tell a native array
+// from a list that implements the implicit interface.
+abstract class _NativeTypedArray extends TypedData
+ implements JavaScriptIndexingBehavior {
+ int get length => JS("JSUInt32", '#.length', this);
+
+ bool _setRangeFast(int start, int end,
+ _NativeTypedArray source, int skipCount) {
+ int targetLength = this.length;
+ _checkIndex(start, targetLength + 1);
+ _checkIndex(end, targetLength + 1);
+ if (start > end) throw new RangeError.range(start, 0, end);
+ int count = end - start;
+
+ if (skipCount < 0) throw new ArgumentError(skipCount);
+
+ int sourceLength = source.length;
+ if (sourceLength - skipCount < count) {
+ throw new StateError("Not enough elements");
+ }
+
+ if (skipCount != 0 || sourceLength != count) {
+ // Create a view of the exact subrange that is copied from the source.
+ source = JS('', '#.subarray(#, #)',
+ source, skipCount, skipCount + count);
+ }
+ JS('void', '#.set(#, #)', this, source, start);
+ }
+}
+
+// TODO(sra): Move to private library, like [_NativeTypedArray].
+abstract class _NativeTypedArrayOfDouble
+ extends _NativeTypedArray
+ with ListMixin<double>, FixedLengthListMixin<double>
+ implements List<double> {
+
+ void setRange(int start, int end, Iterable<double> iterable,
+ [int skipCount = 0]) {
+ if (iterable is _NativeTypedArrayOfDouble) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+// TODO(sra): Move to private library, like [_NativeTypedArray].
+abstract class _NativeTypedArrayOfInt
+ extends _NativeTypedArray
+ with ListMixin<int>, FixedLengthListMixin<int>
+ implements List<int> {
+
+ void setRange(int start, int end, Iterable<int> iterable,
+ [int skipCount = 0]) {
+ if (iterable is _NativeTypedArrayOfInt) {
+ _setRangeFast(start, end, iterable, skipCount);
+ return;
+ }
+ super.setRange(start, end, iterable, skipCount);
+ }
+}
+
+
/**
* A fixed-length list of IEEE 754 single-precision binary floating-point
* numbers that is viewable as a [TypedData]. For long lists, this
* implementation can be considerably more space- and time-efficient than
* the default [List] implementation.
*/
-class Float32List
- extends TypedData with ListMixin<double>, FixedLengthListMixin<double>
- implements JavaScriptIndexingBehavior, List<double>
- native "Float32Array" {
+class Float32List extends _NativeTypedArrayOfDouble native "Float32Array" {
/**
* Creates a [Float32List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -502,8 +564,6 @@
static const int BYTES_PER_ELEMENT = 4;
- int get length => JS("JSUInt32", '#.length', this);
-
num operator[](int index) {
_checkIndex(index, length);
return JS("num", "#[#]", this, index);
@@ -537,10 +597,7 @@
* implementation can be considerably more space- and time-efficient than
* the default [List] implementation.
*/
-class Float64List
- extends TypedData with ListMixin<double>, FixedLengthListMixin<double>
- implements JavaScriptIndexingBehavior, List<double>
- native "Float64Array" {
+class Float64List extends _NativeTypedArrayOfDouble native "Float64Array" {
/**
* Creates a [Float64List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -577,8 +634,6 @@
static const int BYTES_PER_ELEMENT = 8;
- int get length => JS("JSUInt32", '#.length', this);
-
num operator[](int index) {
_checkIndex(index, length);
return JS("num", "#[#]", this, index);
@@ -614,10 +669,7 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Int16List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
- native "Int16Array" {
+class Int16List extends _NativeTypedArrayOfInt native "Int16Array" {
/**
* Creates an [Int16List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -653,8 +705,6 @@
static const int BYTES_PER_ELEMENT = 2;
- int get length => JS("JSUInt32", '#.length', this);
-
int operator[](int index) {
_checkIndex(index, length);
return JS("int", "#[#]", this, index);
@@ -687,10 +737,7 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Int32List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
- native "Int32Array" {
+class Int32List extends _NativeTypedArrayOfInt native "Int32Array" {
/**
* Creates an [Int32List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -726,8 +773,6 @@
static const int BYTES_PER_ELEMENT = 4;
- int get length => JS("JSUInt32", '#.length', this);
-
int operator[](int index) {
_checkIndex(index, length);
return JS("int", "#[#]", this, index);
@@ -760,10 +805,7 @@
* For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Int8List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
- native "Int8Array" {
+class Int8List extends _NativeTypedArrayOfInt native "Int8Array" {
/**
* Creates an [Int8List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -796,8 +838,6 @@
static const int BYTES_PER_ELEMENT = 1;
- int get length => JS("JSUInt32", '#.length', this);
-
int operator[](int index) {
_checkIndex(index, length);
return JS("int", "#[#]", this, index);
@@ -830,10 +870,7 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Uint16List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
- native "Uint16Array" {
+class Uint16List extends _NativeTypedArrayOfInt native "Uint16Array" {
/**
* Creates a [Uint16List] of the specified length (in elements), all
* of whose elements are initially zero.
@@ -870,8 +907,6 @@
static const int BYTES_PER_ELEMENT = 2;
- int get length => JS("JSUInt32", '#.length', this);
-
int operator[](int index) {
_checkIndex(index, length);
return JS("JSUInt31", "#[#]", this, index);
@@ -904,10 +939,7 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Uint32List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
- native "Uint32Array" {
+class Uint32List extends _NativeTypedArrayOfInt native "Uint32Array" {
/**
* Creates a [Uint32List] of the specified length (in elements), all
* of whose elements are initially zero.
@@ -944,8 +976,6 @@
static const int BYTES_PER_ELEMENT = 4;
- int get length => JS("JSUInt32", '#.length', this);
-
int operator[](int index) {
_checkIndex(index, length);
return JS("JSUInt32", "#[#]", this, index);
@@ -979,8 +1009,7 @@
* more space- and time-efficient than the default [List] implementation.
* Indexed store clamps the value to range 0..0xFF.
*/
-class Uint8ClampedList extends TypedData with ListMixin<int>,
- FixedLengthListMixin<int> implements JavaScriptIndexingBehavior, List<int>
+class Uint8ClampedList extends _NativeTypedArrayOfInt
native "Uint8ClampedArray,CanvasPixelArray" {
/**
* Creates a [Uint8ClampedList] of the specified length (in elements), all of
@@ -1050,9 +1079,7 @@
* For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Uint8List
- extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
- implements JavaScriptIndexingBehavior, List<int>
+class Uint8List extends _NativeTypedArrayOfInt
// On some browsers Uint8ClampedArray is a subtype of Uint8Array. Marking
// Uint8List as !nonleaf ensures that the native dispatch correctly handles
// the potential for Uint8ClampedArray to 'accidentally' pick up the
@@ -1125,7 +1152,8 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Int64List extends TypedData implements JavaScriptIndexingBehavior, List<int> {
+abstract class Int64List extends TypedData
+ implements JavaScriptIndexingBehavior, List<int> {
/**
* Creates an [Int64List] of the specified length (in elements), all of
* whose elements are initially zero.
@@ -1170,7 +1198,8 @@
* [TypedData]. For long lists, this implementation can be considerably
* more space- and time-efficient than the default [List] implementation.
*/
-class Uint64List extends TypedData implements JavaScriptIndexingBehavior, List<int> {
+abstract class Uint64List extends TypedData
+ implements JavaScriptIndexingBehavior, List<int> {
/**
* Creates a [Uint64List] of the specified length (in elements), all
* of whose elements are initially zero.
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 211c085..8196b61 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -131,7 +131,7 @@
Language/07_Classes/10_Superinterfaces_A07_t05: StaticWarning # co19-roll r667: Please triage this failure
LibTest/convert/JsonEncoder/JsonEncoder_A01_t01: StaticWarning # co19-roll r667: Please triage this failure
LibTest/isolate/Isolate/spawnFunction_A02_t02: CompileTimeError # co19-roll r667: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t01: CompileTimeError # co19-roll r667: Please triage this failure
+LibTest/async/Zone/operator_subscript_A01_t01: StaticWarning # co19-roll r672: Please triage this failure
# co19 issue 656
LibTest/typed_data/Uint32x4/*: Skip # co19 issue 656
@@ -142,4 +142,4 @@
LibTest/typed_data/Float32x4/greaterThan_A01_t01: Skip # co19 issue 656
LibTest/typed_data/Float32x4/greaterThanOrEqual_A01_t01: Skip # co19 issue 656
LibTest/typed_data/Float32x4/lessThan_A01_t01: Skip # co19 issue 656
-LibTest/typed_data/Float32x4/lessThanOrEqual_A01_t01: Skip # co19 issue 656
\ No newline at end of file
+LibTest/typed_data/Float32x4/lessThanOrEqual_A01_t01: Skip # co19 issue 656
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index b93b952..184d3aa 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -131,9 +131,7 @@
Language/07_Classes/10_Superinterfaces_A07_t05: StaticWarning # co19-roll r667: Please triage this failure
LibTest/convert/JsonEncoder/JsonEncoder_A01_t01: StaticWarning # co19-roll r667: Please triage this failure
LibTest/isolate/Isolate/spawnFunction_A02_t02: CompileTimeError # co19-roll r667: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t01: CompileTimeError # co19-roll r667: Please triage this failure
-
-
+LibTest/async/Zone/operator_subscript_A01_t01: StaticWarning # co19-roll r672: Please triage this failure
# co19 issue 656
LibTest/typed_data/Uint32x4/*: Skip # co19 issue 656
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 3212583..dfadfa8 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -15,19 +15,11 @@
LibTest/core/Stopwatch/start_A01_t02: PASS, FAIL, OK # co19 issue 657
LibTest/core/Stopwatch/elapsedTicks_A01_t01: PASS, FAIL, OK # co19 issue 657
-LibTest/isolate/Isolate/spawnUri_A01_t01: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t02: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t03: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t04: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t05: Fail, OK # co19 issue 639
LibTest/isolate/Isolate/spawnFunction_A02_t01: Fail, OK # co19 issue 639
LibTest/isolate/Isolate/spawnFunction_A03_t01: Fail, OK # co19 issue 639
LibTest/isolate/Isolate/spawnFunction_A04_t01: Fail, OK # co19 issue 639
LibTest/isolate/Isolate/spawnFunction_A04_t02: Fail, OK # co19 issue 639
LibTest/isolate/Isolate/spawnFunction_A04_t03: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A02_t02: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A02_t03: Fail, OK # co19 issue 639
-
[ $runtime == vm || $runtime == dartium || $compiler == dart2dart || $compiler == dart2js ]
Language/12_Expressions/30_Identifier_Reference_A02_t01: fail, pass, ok # co19 issue 649
@@ -57,6 +49,8 @@
LibTest/collection/ListBase/ListBase_class_A01_t01: Skip, OK # co19 issue 661
LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip, OK # co19 issue 661
+LibTest/isolate/Isolate/spawnUri_A02_t04: Timeout, Fail # co19-roll r672: Please triage this failure
+
[ $runtime == vm || $runtime == dartium || $compiler == dart2js ]
LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
@@ -77,8 +71,6 @@
LibTest/isolate/SendPort/send_A02_t02: SKIP # co19 issue 493
LibTest/isolate/SendPort/send_A02_t03: SKIP # co19 issue 495
-LibTest/typed_data/Int8List/Int8List.fromList_A01_t02: Fail # co19-roll r559: Please triage this failure
-
[ $runtime == vm || $compiler == dart2js ]
Language/07_Classes/6_Constructors_A02_t01: SKIP # co19 issue 415.
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index c03f3c0..74fd8a5 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -115,7 +115,6 @@
Language/07_Classes/6_Constructors/2_Factories_A10_t01: crash # co19-roll r587: Please triage this failure
Language/07_Classes/6_Constructors/2_Factories_A10_t04: crash # co19-roll r587: Please triage this failure
Language/12_Expressions/01_Constants_A20_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings/1_String_Interpolation_A01_t09: fail # co19-roll r546: Please triage this failure
Language/12_Expressions/12_Instance_Creation/1_New_A02_t03: fail # co19-roll r546: Please triage this failure
Language/12_Expressions/12_Instance_Creation/1_New_A02_t05: fail # co19-roll r546: Please triage this failure
Language/12_Expressions/12_Instance_Creation/1_New_A02_t06: fail # co19-roll r546: Please triage this failure
@@ -173,4 +172,4 @@
Language/12_Expressions/32_Type_Test_A02_t04: RuntimeError # co19-roll to r667: Please triage this failure
[ $compiler == dart2dart && $unminified ]
-Language/14_Libraries_and_Scripts/1_Imports_A03_t31: RuntimeError # co19-roll r667: Please triage this failure
\ No newline at end of file
+Language/14_Libraries_and_Scripts/1_Imports_A03_t31: RuntimeError # co19-roll r667: Please triage this failure
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index ce36919..6a983cd 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -7,6 +7,7 @@
LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
[ $compiler == dart2js && $checked && $runtime == ie9 ]
+LibTest/core/Uri/encodeComponent_A01_t02: Pass, Slow
LibTest/core/Uri/encodeFull_A01_t02: Pass, Slow
LibTest/core/Uri/encodeQueryComponent_A01_t02: Pass, Timeout # co19-roll r576: Please triage this failure
@@ -114,7 +115,6 @@
Language/15_Types/2_Dynamic_Type_System_A01_t02: RuntimeError # co19-roll r607: Please triage this failure
Language/15_Types/8_Parameterized_Types_A03_t07: RuntimeError # co19-roll r607: Please triage this failure
Language/15_Types/1_Static_Types_A03_t01: RuntimeError # co19-roll r623: Please triage this failure
-LibTest/typed_data/Float32x4List/reduce_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
[ $compiler == dart2js ]
LibTest/core/int/operator_GT_A01_t01: RuntimeError, OK # co19 issue 200
@@ -151,53 +151,6 @@
LibTest/core/RegExp/Pattern_semantics/firstMatch_Term_A04_t01: RuntimeError, OK # co19 issue 212
-[ $compiler == dart2js || $compiler == dart2dart ]
-
-Language/12_Expressions/05_Strings_A02_t02: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t03: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t04: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t05: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t06: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t07: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t08: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t09: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t10: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t11: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t12: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t13: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t14: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t15: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t16: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t17: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t18: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t19: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t20: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t21: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t22: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t23: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t24: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t25: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t28: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t29: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t32: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t32: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t33: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t34: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t36: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t38: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t40: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t42: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t44: Crash # Issue 15237
-
-
-Language/13_Statements/05_If_A01_t04: Crash # Issue 15237
-Language/13_Statements/07_While_A01_t01: Crash # Issue 15237
-Language/13_Statements/08_Do_A01_t03: Crash # Issue 15237
-Language/13_Statements/09_Switch_A01_t04: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A15_t06: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A22_t06: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A29_t06: Crash # Issue 15237
-
#
# Issues with co19 test suite.
#
@@ -349,7 +302,6 @@
# Missing compile-time errors.
#
[ $compiler == dart2js ]
-Language/12_Expressions/05_Strings/1_String_Interpolation_A01_t09: MissingCompileTimeError # Checks that it is a compile-time error if a string interpolation construct does not start with IDENTIFIER_NO_DOLLAR or opening brace.
Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: MissingCompileTimeError # Checks that other Unicode whitespaces are not allowed: check NO-BREAK SPACE (U+00A0)
Language/16_Reference/1_Lexical_Rules_A02_t06: MissingCompileTimeError # Checks that Unicode whitespaces other than WHITESPACE are not permitted in the source code. Checks symbol U+00a0.
@@ -438,6 +390,43 @@
LibTest/typed_data/ByteData/toString_A01_t01: fail # co19-roll r569: Please triage this failure
LibTest/typed_data/ByteData/elementSizeInBytes_A01_t01: fail # co19-roll r569: Please triage this failure
+LibTest/typed_data/Int32x4/flagW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagW_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagW_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.bool_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.fromFloat32x4Bits_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.fromFloat32x4Bits_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_AND_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_OR_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_XOR_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/select_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/w_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/w_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/x_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/x_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/y_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/y_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/z_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/z_A01_t02: fail # co19-roll r672: Please triage this failure
+
[ $compiler == dart2js ]
Language/03_Overview/1_Scoping_A02_t28: fail # co19-roll r559: Please triage this failure
Language/05_Variables/05_Variables_A05_t01: fail # co19-roll r546: Please triage this failure
@@ -585,6 +574,29 @@
LibTest/async/Timer/isActive_A01_t01: RuntimeError # co19-roll r641: Please triage this failure
LibTest/async/Future/wait_A01_t07: RuntimeError # co19-roll r641: Please triage this failure
LibTest/async/Timer/isActive_A01_t02: RuntimeError # co19-roll r641: Please triage this failure
+LibTest/async/Zone/createPeriodicTimer_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/async/Zone/createTimer_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_OR_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+
+[ $compiler == dart2js && $runtime == d8 ]
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
[ $compiler == dart2js && $minified ]
Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail # co19-roll r559: Please triage this failure
@@ -622,6 +634,13 @@
Language/14_Libraries_and_Scripts/2_Exports_A05_t03: MissingCompileTimeError # co19-roll r623: Please triage this failure
Language/15_Types/4_Interface_Types_A11_t04: fail # Issue 14654
LibTest/core/Symbol/Symbol_A01_t02: CompileTimeError # co19-roll r607: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t01: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t02: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t03: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t04: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t05: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t02: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t03: Fail # co19-roll r672: Please triage this failure
[ $compiler == dart2js ]
LibTest/core/List/List_class_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 554f5ae..c60ac8c 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -10,13 +10,21 @@
Language/14_Libraries_and_Scripts/3_Parts_A02_t02: Pass, Timeout # Issue 13719: Please triage this failure.
Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: Pass # Issue 14478: This should break.
LibTest/async/Completer/completeError_A02_t01: Pass, Fail # Issue 13719: Please triage this failure.
-LibTest/async/Future/Future_A01_t03: Fail # co19-roll r641: Please triage this failure
LibTest/core/int/operator_left_shift_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
LibTest/isolate/ReceivePort/toSendPort_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
LibTest/isolate/SendPort/send_A02_t01: Fail # Issue 13921
LibTest/isolate/SendPort/send_A02_t04: Fail # Issue 13921
LibTest/isolate/SendPort/send_A02_t05: Fail # Issue 13921
LibTest/isolate/SendPort/send_A02_t06: Fail # Issue 13921
+LibTest/isolate/Isolate/spawnUri_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t02: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t03: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t04: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t05: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
Language/12_Expressions/13_Spawning_an_Isolate_A01_t01: RuntimeError # co19-roll r667: Please triage this failure
@@ -26,7 +34,6 @@
LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # co19-roll r667: Please triage this failure
LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
-
[ $compiler == none && $runtime == dartium && $checked ]
Language/13_Statements/09_Switch_A09_t01: Fail # Please triage this failure (enabled checked mode tests on dartium)
-LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
\ No newline at end of file
+LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index df0e9c9..1e73cf2 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -36,6 +36,9 @@
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # VM triage, check spec.
LibTest/isolate/SendPort/send_A01_t01: fail # co19-roll r546: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t02: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t03: Timeout # co19-roll r672: Please triage this failure
+
LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # co19-roll r607: Please triage this failure
LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # co19-roll r607: Please triage this failure
@@ -89,3 +92,6 @@
[ $compiler == none && $runtime == vm && $system == windows && $mode == debug ]
Language/15_Types/4_Interface_Types_A11_t01: pass, timeout # Issue 13349
Language/15_Types/4_Interface_Types_A11_t02: pass, timeout # Issue 13349
+
+[ $runtime == vm ]
+LibTest/isolate/Isolate/spawn_A02_t01: Timeout # co19-roll r672: Please triage this failure
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index de48a2e..8965a92 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -20,6 +20,29 @@
// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
// values.
const Map<String, List<String>> WHITE_LIST = const {
+ // The following notices go away when bugs 15417 is fixed.
+ "sdk/lib/core/map.dart": const [
+ "Info: This is the method declaration."],
+
+ // Bug 15417.
+ "sdk/lib/html/dart2js/html_dart2js.dart": const ["""
+Warning: '_DataAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: '_NamespacedAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: '_ElementAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: 'Window' doesn't implement 'clearInterval'.
+Try adding an implementation of 'clearInterval'.""", """
+Warning: 'Window' doesn't implement 'clearTimeout'.
+Try adding an implementation of 'clearTimeout'.""", """
+Warning: 'Window' doesn't implement 'setInterval'.
+Try adding an implementation of 'setInterval'.""", """
+Warning: 'Window' doesn't implement 'setTimeout'.
+Try adding an implementation of 'setTimeout'.""", """
+Warning: 'Storage' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""",
+"Info: This is the method declaration."],
};
void main() {
diff --git a/tests/compiler/dart2js/analyze_dart2js_test.dart b/tests/compiler/dart2js/analyze_dart2js_test.dart
index 9508083..ccd379e 100644
--- a/tests/compiler/dart2js/analyze_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_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.
-library analyze_api;
+library analyze_dart2js;
import "package:expect/expect.dart";
import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
diff --git a/tests/compiler/dart2js/analyze_helper.dart b/tests/compiler/dart2js/analyze_helper.dart
index adb0673..2c2c02d 100644
--- a/tests/compiler/dart2js/analyze_helper.dart
+++ b/tests/compiler/dart2js/analyze_helper.dart
@@ -123,20 +123,29 @@
}
}
-Future analyze(List<Uri> uriList, Map<String, List<String>> whiteList) {
+Future analyze(List<Uri> uriList,
+ Map<String, List<String>> whiteList,
+ {bool analyzeAll: true}) {
var libraryRoot = currentDirectory.resolve('sdk/');
var provider = new CompilerSourceFileProvider();
var handler = new CollectingDiagnosticHandler(whiteList, provider);
+ var options = <String>['--analyze-only', '--categories=Client,Server'];
+ if (analyzeAll) options.add('--analyze-all');
var compiler = new Compiler(
provider.readStringFromUri,
null,
handler.diagnosticHandler,
libraryRoot, libraryRoot,
- <String>['--analyze-only', '--analyze-all',
- '--categories=Client,Server'],
+ options,
{});
- compiler.librariesToAnalyzeWhenRun = uriList;
- return compiler.run(null).then((_) {
- handler.checkResults();
- });
+ if (analyzeAll) {
+ compiler.librariesToAnalyzeWhenRun = uriList;
+ return compiler.run(null).then((_) {
+ handler.checkResults();
+ });
+ } else {
+ return compiler.run(uriList.single).then((_) {
+ handler.checkResults();
+ });
+ }
}
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
new file mode 100644
index 0000000..03d08e6
--- /dev/null
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -0,0 +1,18 @@
+// 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 analyze_unused_dart2js;
+
+import 'package:async_helper/async_helper.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
+
+import 'analyze_helper.dart';
+
+void main() {
+ var uri = currentDirectory.resolve(
+ 'sdk/lib/_internal/compiler/implementation/use_unused_api.dart');
+ asyncTest(
+ () => analyze([uri], {}, analyzeAll: false));
+}
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 68cfa76..c74f6f5 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -195,6 +195,10 @@
}
void main() {
+ bool isCheckedMode = false;
+ assert(isCheckedMode = true);
+ Expect.isTrue(isCheckedMode, 'This test must be run in checked mode.');
+
const beforeRun = const {
'': 0,
'NoSuchMethodError': 253,
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 414e5cd..9366565 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -74,6 +74,9 @@
return handler;
}
+Expando<MemorySourceFileProvider> expando =
+ new Expando<MemorySourceFileProvider>();
+
Compiler compilerFor(Map<String,String> memorySourceFiles,
{DiagnosticHandler diagnosticHandler,
List<String> options: const [],
@@ -83,7 +86,24 @@
Uri libraryRoot = script.resolve('../../../sdk/');
Uri packageRoot = script.resolve('./packages/');
- var provider = new MemorySourceFileProvider(memorySourceFiles);
+ MemorySourceFileProvider provider;
+ var readStringFromUri;
+ if (cachedCompiler == null) {
+ provider = new MemorySourceFileProvider(memorySourceFiles);
+ readStringFromUri = provider.readStringFromUri;
+ // Saving the provider in case we need it later for a cached compiler.
+ expando[readStringFromUri] = provider;
+ } else {
+ // When using a cached compiler, it has read a number of files from disk
+ // already (and will not attemp to read them again due to caching). These
+ // files must be available to the new diagnostic handler.
+ provider = expando[cachedCompiler.provider];
+ readStringFromUri = cachedCompiler.provider;
+ provider.memorySourceFiles.clear();
+ memorySourceFiles.forEach((key, value) {
+ provider.memorySourceFiles[key] = value;
+ });
+ }
var handler =
createDiagnosticHandler(diagnosticHandler, provider, showDiagnostics);
@@ -92,7 +112,7 @@
return new NullSink('$name.$extension');
}
- Compiler compiler = new Compiler(provider.readStringFromUri,
+ Compiler compiler = new Compiler(readStringFromUri,
outputProvider,
handler,
libraryRoot,
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 37e0729..1eb5892 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -58,7 +58,7 @@
// 2. Some code was refactored, and there are more methods.
// Either situation could be problematic, but in situation 2, it is often
// acceptable to increase [expectedMethodCount] a little.
- int expectedMethodCount = 344;
+ int expectedMethodCount = 346;
Expect.isTrue(
generatedCode.length <= expectedMethodCount,
'Too many compiled methods: '
@@ -123,7 +123,9 @@
const MEMORY_SOURCE_FILES = const <String, String> {
'main.dart': """
-@MirrorsUsed(targets: const [Foo], override: '*')
+// The repeated constant value for symbols and targets used to crash dart2js in
+// host-checked mode, and could potentially lead to other problems.
+@MirrorsUsed(symbols: 'Foo', targets: 'Foo', override: '*')
import 'dart:mirrors';
import 'library.dart';
diff --git a/tests/compiler/dart2js/mixin_typevariable_test.dart b/tests/compiler/dart2js/mixin_typevariable_test.dart
new file mode 100644
index 0000000..9e9f8fb
--- /dev/null
+++ b/tests/compiler/dart2js/mixin_typevariable_test.dart
@@ -0,0 +1,158 @@
+// 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 mixin_typevariable_test;
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'type_test_helper.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
+import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart"
+ show Element, ClassElement;
+
+void main() {
+ testMixinSupertypes();
+ testNonTrivialSubstitutions();
+}
+
+void testMixinSupertypes() {
+ asyncTest(() => TypeEnvironment.create(r"""
+ class S<S_T> {}
+ class M1<M1_T> {}
+ class M2<M2_T> {}
+ class M3<M3_T> {}
+
+ class C1<C1_T> extends S<C1_T> with M1<C1_T>, M2<C1_T>, M3<C1_T> {}
+ class C2<C2_T> = S<C2_T> with M1<C2_T>, M2<C2_T>, M3<C2_T>;
+ """, expectNoWarningsOrErrors: true).then((env) {
+
+ ClassElement Object = env.getElement('Object');
+ ClassElement S = env.getElement('S');
+ ClassElement M1 = env.getElement('M1');
+ ClassElement M2 = env.getElement('M2');
+ ClassElement M3 = env.getElement('M3');
+ ClassElement C1 = env.getElement('C1');
+ ClassElement C2 = env.getElement('C2');
+
+ ClassElement C1_S_M1_M2_M3 = C1.superclass;
+ ClassElement C1_S_M1_M2 = C1_S_M1_M2_M3.superclass;
+ ClassElement C1_S_M1 = C1_S_M1_M2.superclass;
+
+ ClassElement C2_S_M1_M2 = C2.superclass;
+ ClassElement C2_S_M1 = C2_S_M1_M2.superclass;
+
+ void testSupertypes(ClassElement element) {
+ if (element != Object) {
+ Expect.isTrue(element.typeVariables.slowLength() == 1);
+ Expect.equals(element,
+ element.typeVariables.head.element.enclosingElement);
+ }
+ for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
+ if (!supertype.typeArguments.isEmpty) {
+ Expect.equals(element.typeVariables, supertype.typeArguments,
+ "Type argument mismatch on supertype $supertype of $element.");
+ } else {
+ Expect.equals(Object, supertype.element);
+ }
+ }
+ }
+
+ testSupertypes(Object);
+ testSupertypes(S);
+ testSupertypes(M1);
+ testSupertypes(M2);
+ testSupertypes(C1_S_M1);
+ testSupertypes(C1_S_M1_M2);
+ testSupertypes(C1_S_M1_M2_M3);
+ testSupertypes(C1);
+ testSupertypes(C2_S_M1);
+ testSupertypes(C2_S_M1_M2);
+ testSupertypes(C2);
+ }));
+}
+
+void testNonTrivialSubstitutions() {
+ asyncTest(() => TypeEnvironment.create(r"""
+ class _ {}
+ class A<A_T> {}
+ class B<B_T, B_S> {}
+
+ class C1<C1_T> extends A with B {}
+ class C2<C2_T> = A with B;
+
+ class D1<D1_T> extends A<D1_T> with B<D1_T, A<D1_T>> {}
+ class D2<D2_T> = A<D2_T> with B<D2_T, A<D2_T>>;
+
+ class E1<E1_T> extends A<_> with B<_, A<_>> {}
+ class E2<E2_T> = A<_> with B<_, A<_>>;
+
+ class F1<F1_T> extends A<_> with B<_, B<F1_T, _>> {}
+ class F2<F2_T> = A<_> with B<_, B<F2_T, _>>;
+ """, expectNoWarningsOrErrors: true).then((env) {
+ DartType _dynamic = env['dynamic'];
+ DartType _ = env['_'];
+
+ ClassElement Object = env.getElement('Object');
+ ClassElement A = env.getElement('A');
+ ClassElement B = env.getElement('B');
+ ClassElement C1 = env.getElement('C1');
+ ClassElement C2 = env.getElement('C2');
+ ClassElement D1 = env.getElement('D1');
+ ClassElement D2 = env.getElement('D2');
+ ClassElement E1 = env.getElement('E1');
+ ClassElement E2 = env.getElement('E2');
+ ClassElement F1 = env.getElement('F1');
+ ClassElement F2 = env.getElement('F2');
+
+ ClassElement C1_A_B = C1.superclass;
+ ClassElement D1_A_B = D1.superclass;
+ ClassElement E1_A_B = E1.superclass;
+ ClassElement F1_A_B = F1.superclass;
+
+ void testSupertypes(ClassElement element,
+ Map<ClassElement, List<DartType>> typeArguments) {
+ if (element != Object) {
+ Expect.isTrue(element.typeVariables.slowLength() == 1);
+ Expect.equals(element,
+ element.typeVariables.head.element.enclosingElement);
+ }
+ for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
+ if (typeArguments.containsKey(supertype.element)) {
+ Expect.listEquals(typeArguments[supertype.element],
+ supertype.typeArguments.toList(),
+ "Type argument mismatch on supertype $supertype of $element.");
+ } else if (!supertype.typeArguments.isEmpty) {
+ Expect.equals(element.typeVariables, supertype.typeArguments,
+ "Type argument mismatch on supertype $supertype of $element.");
+ } else {
+ Expect.equals(Object, supertype.element);
+ }
+ }
+ }
+
+ testSupertypes(C1, {A: [_dynamic], B: [_dynamic, _dynamic]});
+ testSupertypes(C1.superclass, {A: [_dynamic], B: [_dynamic, _dynamic]});
+ testSupertypes(C2, {A: [_dynamic], B: [_dynamic, _dynamic]});
+
+ DartType D1_T = D1.typeVariables.head;
+ testSupertypes(D1, {A: [D1_T], B: [D1_T, instantiate(A, [D1_T])]});
+ DartType D1_superclass_T = D1.superclass.typeVariables.head;
+ testSupertypes(D1.superclass,
+ {A: [D1_superclass_T],
+ B: [D1_superclass_T, instantiate(A, [D1_superclass_T])]});
+ DartType D2_T = D2.typeVariables.head;
+ testSupertypes(D2, {A: [D2_T], B: [D2_T, instantiate(A, [D2_T])]});
+
+ testSupertypes(E1, {A: [_], B: [_, instantiate(A, [_])]});
+ testSupertypes(E1.superclass, {A: [_], B: [_, instantiate(A, [_])]});
+ testSupertypes(E2, {A: [_], B: [_, instantiate(A, [_])]});
+
+ DartType F1_T = F1.typeVariables.head;
+ testSupertypes(F1, {A: [_], B: [_, instantiate(B, [F1_T, _])]});
+ DartType F1_superclass_T = F1.superclass.typeVariables.head;
+ testSupertypes(F1.superclass, {A: [_], B: [_, instantiate(B, [F1_superclass_T, _])]});
+ DartType F2_T = F2.typeVariables.head;
+ testSupertypes(F2, {A: [_], B: [_, instantiate(B, [F2_T, _])]});
+ }));
+}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 8269768..b24b0f2 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -19,7 +19,8 @@
import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
show ElementX,
LibraryElementX,
- ErroneousElementX;
+ ErroneousElementX,
+ FunctionElementX;
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
hide TreeElementMapping;
@@ -394,7 +395,8 @@
resolverVisitor() {
Element mockElement =
- new ElementX('', ElementKind.FUNCTION, mainApp.entryCompilationUnit);
+ new FunctionElementX('', ElementKind.FUNCTION, Modifiers.EMPTY,
+ mainApp.entryCompilationUnit, false);
ResolverVisitor visitor =
new ResolverVisitor(this, mockElement,
new CollectingTreeElements(mockElement));
@@ -437,25 +439,62 @@
}
}
-void compareWarningKinds(String text, expectedWarnings, foundWarnings) {
+/// A function the checks [message]. If the check fails or if [message] is
+/// `null`, an error string is returned. Otherwise `null` is returned.
+typedef String CheckMessage(Message message);
+
+CheckMessage checkMessage(MessageKind kind, Map arguments) {
+ return (Message message) {
+ if (message == null) return '$kind';
+ if (message.kind != kind) return 'Expected message $kind, found $message.';
+ for (var key in arguments.keys) {
+ if (!message.arguments.containsKey(key)) {
+ return 'Expected argument $key not found in $message.kind.';
+ }
+ String expectedValue = '${arguments[key]}';
+ String foundValue = '${message.arguments[key]}';
+ if (expectedValue != foundValue) {
+ return 'Expected argument $key with value $expectedValue, '
+ 'found $foundValue.';
+ }
+ }
+ return null;
+ };
+}
+
+/// [expectedWarnings] must be a list of either [MessageKind] or [CheckMessage].
+void compareWarningKinds(String text,
+ List expectedWarnings,
+ List<WarningMessage> foundWarnings) {
var fail = (message) => Expect.fail('$text: $message');
- HasNextIterator<MessageKind> expected =
+ HasNextIterator expectedIterator =
new HasNextIterator(expectedWarnings.iterator);
- HasNextIterator<WarningMessage> found =
+ HasNextIterator<WarningMessage> foundIterator =
new HasNextIterator(foundWarnings.iterator);
- while (expected.hasNext && found.hasNext) {
- Expect.equals(expected.next(), found.next().message.kind);
+ while (expectedIterator.hasNext && foundIterator.hasNext) {
+ var expected = expectedIterator.next();
+ var found = foundIterator.next();
+ if (expected is MessageKind) {
+ Expect.equals(expected, found.message.kind);
+ } else if (expected is CheckMessage) {
+ String error = expected(found.message);
+ Expect.isNull(error, error);
+ } else {
+ Expect.fail("Unexpected expectedWarnings value: $expected.");
+ }
}
- if (expected.hasNext) {
+ if (expectedIterator.hasNext) {
do {
- print('Expected warning "${expected.next()}" did not occur');
- } while (expected.hasNext);
+ var expected = expectedIterator.next();
+ if (expected is CheckMessage) expected = expected(null);
+ print('Expected warning "${expected}" did not occur');
+ } while (expectedIterator.hasNext);
fail('Too few warnings');
}
- if (found.hasNext) {
+ if (foundIterator.hasNext) {
do {
- print('Additional warning "${found.next()}"');
- } while (found.hasNext);
+ print('Additional warning "${foundIterator.next()}"');
+ } while (foundIterator.hasNext);
fail('Too many warnings');
}
}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 8ca53a8..02f1b6b 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -11,7 +11,7 @@
import 'parser_helper.dart';
import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
- show ElementX, CompilationUnitElementX;
+ show ElementX, CompilationUnitElementX, FunctionElementX;
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart';
@@ -1518,6 +1518,12 @@
class E<T> extends D<T> {
T e;
}
+ class F<S, U> extends E<S> {
+ S f;
+ }
+ class G<V> extends F<V, V> {
+ V g;
+ }
''');
check(String text, {warnings, hints, infos}) {
@@ -1530,7 +1536,7 @@
var x = a.c;
}''',
warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
- hints: [MessageKind.NOT_MORE_SPECIFIC],
+ hints: [MessageKind.NOT_MORE_SPECIFIC_SUBTYPE],
infos: []);
check(r'''
@@ -1540,7 +1546,7 @@
}''',
warnings: [MessageKind.MEMBER_NOT_FOUND.warning,
MessageKind.MEMBER_NOT_FOUND.warning],
- hints: [MessageKind.NOT_MORE_SPECIFIC],
+ hints: [MessageKind.NOT_MORE_SPECIFIC_SUBTYPE],
infos: []);
check(r'''
@@ -1555,10 +1561,40 @@
check('''
D<int> d = new E();
- if (d is E) {
+ if (d is E) { // Suggest E<int>.
var x = d.e;
}''',
warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+ hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ {'shownTypeSuggestion': 'E<int>'})],
+ infos: []);
+
+ check('''
+ D<int> d = new F();
+ if (d is F) { // Suggest F<int, dynamic>.
+ var x = d.f;
+ }''',
+ warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+ hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ {'shownTypeSuggestion': 'F<int, dynamic>'})],
+ infos: []);
+
+ check('''
+ D<int> d = new G();
+ if (d is G) { // Suggest G<int>.
+ var x = d.f;
+ }''',
+ warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+ hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+ {'shownTypeSuggestion': 'G<int>'})],
+ infos: []);
+
+ check('''
+ F<double, int> f = new G();
+ if (f is G) { // Cannot suggest a more specific type.
+ var x = f.g;
+ }''',
+ warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
hints: [MessageKind.NOT_MORE_SPECIFIC],
infos: []);
@@ -1803,8 +1839,8 @@
Node node = listener.popNode();
Element compilationUnit =
new CompilationUnitElementX(new Script(null, null), compiler.mainApp);
- Element function = new ElementX(
- '', ElementKind.FUNCTION, compilationUnit);
+ Element function = new FunctionElementX(
+ '', ElementKind.FUNCTION, Modifiers.EMPTY, compilationUnit, false);
TreeElements elements = compiler.resolveNodeStatement(node, function);
TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
types);
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index d616835..01e8c16 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -22,7 +22,9 @@
class TypeEnvironment {
final MockCompiler compiler;
- static Future<TypeEnvironment> create(String source) {
+ static Future<TypeEnvironment> create(
+ String source, {bool expectNoErrors: false,
+ bool expectNoWarningsOrErrors: false}) {
var uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor('''
main() {}
@@ -31,6 +33,14 @@
analyzeAll: true,
analyzeOnly: true);
return compiler.runCompiler(uri).then((_) {
+ if (expectNoErrors || expectNoWarningsOrErrors) {
+ Expect.isTrue(compiler.errors.isEmpty,
+ 'Unexpected errors: ${compiler.errors}');
+ }
+ if (expectNoWarningsOrErrors) {
+ Expect.isTrue(compiler.warnings.isEmpty,
+ 'Unexpected warnings: ${compiler.warnings}');
+ }
return new TypeEnvironment._(compiler);
});
}
diff --git a/tests/compiler/dart2js_extra/mirror_printer_test.dart b/tests/compiler/dart2js_extra/mirror_printer_test.dart
index 63c1d12..72e4878 100644
--- a/tests/compiler/dart2js_extra/mirror_printer_test.dart
+++ b/tests/compiler/dart2js_extra/mirror_printer_test.dart
@@ -56,12 +56,14 @@
return '$reflectee';
}
StringBuffer buffer = new StringBuffer();
- Map<Symbol, VariableMirror> variables = mirror.type.variables;
+ Map<Symbol, DeclarationMirror> declarations = mirror.type.declarations;
buffer
..write(n(mirror.type.simpleName))
..write('(');
bool first = true;
- variables.forEach((Symbol name, VariableMirror variable) {
+ declarations.forEach((Symbol name, DeclarationMirror declaration) {
+ if (declaration is! VariableMirror) return;
+ VariableMirror variable = declaration;
if (variable.isStatic) return;
// TODO(ahe): Include superclasses.
if (first) {
@@ -130,7 +132,7 @@
w(' {');
bool first = true;
indented(() {
- for (DeclarationMirror declaration in mirror.members.values) {
+ for (DeclarationMirror declaration in mirror.declarations.values) {
if (first) {
first = false;
} else {
@@ -165,7 +167,9 @@
writeLibrary(LibraryMirror library) {
w('library ${n(library.simpleName)};\n\n');
- library.members.values.forEach(writeDeclaration);
+ library.declarations.values
+ .where((d)=> d is! TypeMirror)
+ .forEach(writeDeclaration);
w('\n');
}
diff --git a/tests/corelib/uri_test.dart b/tests/corelib/uri_test.dart
index 351c3b9..3e66ac9 100644
--- a/tests/corelib/uri_test.dart
+++ b/tests/corelib/uri_test.dart
@@ -30,11 +30,35 @@
Expect.stringEquals(orig, d);
}
-testEncodeDecodeQueryComponent(String orig, String encoded) {
- var e = Uri.encodeQueryComponent(orig);
- Expect.stringEquals(encoded, e);
- var d = Uri.decodeQueryComponent(encoded);
+testEncodeDecodeQueryComponent(String orig,
+ String encodedUTF8,
+ String encodedLatin1,
+ String encodedAscii) {
+ var e, d;
+ e = Uri.encodeQueryComponent(orig);
+ Expect.stringEquals(encodedUTF8, e);
+ d = Uri.decodeQueryComponent(encodedUTF8);
Expect.stringEquals(orig, d);
+
+ e = Uri.encodeQueryComponent(orig, encoding: UTF8);
+ Expect.stringEquals(encodedUTF8, e);
+ d = Uri.decodeQueryComponent(encodedUTF8, encoding: UTF8);
+ Expect.stringEquals(orig, d);
+
+ e = Uri.encodeQueryComponent(orig, encoding: LATIN1);
+ Expect.stringEquals(encodedLatin1, e);
+ d = Uri.decodeQueryComponent(encodedLatin1, encoding: LATIN1);
+ Expect.stringEquals(orig, d);
+
+ if (encodedAscii != null) {
+ e = Uri.encodeQueryComponent(orig, encoding: ASCII);
+ Expect.stringEquals(encodedAscii, e);
+ d = Uri.decodeQueryComponent(encodedAscii, encoding: ASCII);
+ Expect.stringEquals(orig, d);
+ } else {
+ Expect.throws(() => Uri.encodeQueryComponent(orig, encoding: ASCII),
+ (e) => e is ArgumentError);
+ }
}
testUriPerRFCs(Uri base) {
@@ -229,5 +253,7 @@
testEncodeDecodeComponent("\u0800", "%E0%A0%80");
testEncodeDecodeComponent(":/@',;?&=+\$", "%3A%2F%40'%2C%3B%3F%26%3D%2B%24");
testEncodeDecodeComponent(s, "%F0%90%80%80");
- testEncodeDecodeQueryComponent("A + B", "A+%2B+B");
+ testEncodeDecodeQueryComponent("A + B", "A+%2B+B", "A+%2B+B", "A+%2B+B");
+ testEncodeDecodeQueryComponent(
+ "æ ø å", "%C3%A6+%C3%B8+%C3%A5", "%E6+%F8+%E5", null);
}
diff --git a/tests/html/custom/constructor_calls_created_synchronously_test.dart b/tests/html/custom/constructor_calls_created_synchronously_test.dart
index f9f242d..d2bc3af 100644
--- a/tests/html/custom/constructor_calls_created_synchronously_test.dart
+++ b/tests/html/custom/constructor_calls_created_synchronously_test.dart
@@ -49,4 +49,18 @@
expect(A.ncallbacks, 2);
expect(b is A, isTrue);
});
+
+ test("can extend elements that don't have special prototypes", () {
+ document.register('fancy-section', FancySection, extendsTag: 'section');
+ var fancy = document.createElement('section', 'fancy-section');
+ expect(fancy is FancySection, true, reason: 'fancy-section was registered');
+ expect(fancy.wasCreated, true, reason: 'FancySection ctor was called');
+ });
+}
+
+class FancySection extends HtmlElement {
+ bool wasCreated = false;
+ FancySection.created() : super.created() {
+ wasCreated = true;
+ }
}
diff --git a/tests/html/html.status b/tests/html/html.status
index 4117007..bda8941 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -102,6 +102,7 @@
[ $compiler == none && ($runtime == drt || $runtime == dartium) && $mode == debug]
websql_test: Fail, Pass # Issue 4941: stderr contains a backtrace.
+native_gc_test: Pass, Slow
[ $compiler == dart2js && $runtime == drt && $system == macos]
audiobuffersourcenode_test: Pass, Fail
diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart
index 20e4802..e43dc4a 100644
--- a/tests/language/arithmetic_test.dart
+++ b/tests/language/arithmetic_test.dart
@@ -432,6 +432,17 @@
var b = -1;
for (var i = 0; i < 10; i++) Expect.equals(0x40000000, divMod(a, b));
}
+
+ static double sinCosSub(double a) => sin(a) - cos(a);
+
+ static void testSinCos() {
+ var e = sin(1.234) - cos(1.234);
+ for (var i = 0; i < 20; i++) {
+ Expect.approxEquals(e, sinCosSub(1.234));
+ }
+ Expect.approxEquals(1.0, sinCosSub(3.14159265));
+ Expect.approxEquals(1.0, sinCosSub(3.14159265 / 2.0));
+ }
static mySqrt(var x) => sqrt(x);
@@ -460,6 +471,7 @@
testSmiDivModDeopt();
testSqrtDeopt();
testDoubleEquality();
+ testSinCos();
}
}
}
diff --git a/tests/language/assignable_expression_test.dart b/tests/language/assignable_expression_test.dart
new file mode 100644
index 0000000..c29e366
--- /dev/null
+++ b/tests/language/assignable_expression_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+// Test to detect syntactically illegal left-hand-side (assignable)
+// expressions.
+
+class C {
+ static var static_field = 0;
+}
+
+var tl_static_var = 0;
+
+main() {
+ tl_static_var = 0;
+ (tl_static_var) = 0; /// 01: compile-time error
+ (tl_static_var)++; /// 02: compile-time error
+ ++(tl_static_var); /// 03: compile-time error
+
+ C.static_field = 0;
+ (C.static_field) = 0; /// 11: compile-time error
+ (C.static_field)++; /// 12: compile-time error
+ ++(C.static_field); /// 13: compile-time error
+
+ tl_static_var = [1, 2, 3];
+ tl_static_var[0] = 0;
+ (tl_static_var)[0] = 0;
+ (tl_static_var[0]) = 0; /// 21: compile-time error
+ (tl_static_var[0])++; /// 22: compile-time error
+ ++(tl_static_var[0]); /// 23: compile-time error
+
+ C.static_field = [1, 2, 3];
+ (C.static_field[0]) = 0; /// 31: compile-time error
+ (C.static_field[0])++; /// 32: compile-time error
+ ++(C.static_field[0]); /// 33: compile-time error
+
+ var a = 0;
+ (a) = 0; /// 41: compile-time error
+ (a)++; /// 42: compile-time error
+ ++(a); /// 43: compile-time error
+
+ // Neat palindrome expression. x is assignable, ((x)) is not.
+ var funcnuf = (x) => ((x))=((x)) <= (x); /// 50: compile-time error
+}
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index aecedf1..98fc880 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -18,6 +18,12 @@
override_field_test/03: fail
method_override7_test/03: Fail # Issue 11496
+assignable_expression_test/02: Fail # Issue 15471
+assignable_expression_test/12: Fail # Issue 15471
+assignable_expression_test/22: Fail # Issue 15471
+assignable_expression_test/32: Fail # Issue 15471
+assignable_expression_test/42: Fail # Issue 15471
+
# Please add new failing tests before this line.
# Section below is for invalid tests.
#
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 11c06e8..7f9c48b 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -9,11 +9,10 @@
# Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
built_in_identifier_prefix_test: CompileTimeError # Issue 12694
-# TBD: these look like bad tests, no issue number
+# Issue 15315
class_literal_test: fail
constructor_call_as_function_test/01: fail
-
-function_type_alias9_test/00: crash # Issue 11987
+call_type_literal_test/01: fail
# TBF: we should check conflicts not only for methods, but for accessors too
override_field_test/03: fail
@@ -153,8 +152,22 @@
# test issue 14736, It is a static warning if a class C declares an instance method named n and has a setter named n=.
setter4_test: StaticWarning
-
-
+# test issue 15060
+least_upper_bound_test/23: StaticWarning # Issue 15060
+least_upper_bound_test/24: StaticWarning # Issue 15060
+least_upper_bound_test/25: MissingStaticWarning # Issue 15060
+least_upper_bound_test/26: MissingStaticWarning # Issue 15060
+least_upper_bound_test/29: StaticWarning # Issue 15060
+least_upper_bound_test/30: StaticWarning # Issue 15060
+least_upper_bound_test/31: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/02: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/04: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/05: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/06: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/08: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/10: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/11: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/12: MissingStaticWarning # Issue 15060
abstract_exact_selector_test: StaticWarning
abstract_getter_test: StaticWarning
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 408d7a0..70f90358 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -157,12 +157,6 @@
[ $compiler == dart2js || $compiler == dart2dart ]
function_type_alias9_test/00: Crash # Issue 15237
-string_interpolation9_test/11: Crash # Issue 15237
-string_interpolation9_test/12: Crash # Issue 15237
-string_interpolation9_test/13: Crash # Issue 15237
-string_interpolation9_test/16: Crash # Issue 15237
-string_interpolation9_test/17: Crash # Issue 15237
-string_interpolation9_test/18: Crash # Issue 15237
mixin_invalid_inheritance2_test/03: Crash # Issue 15237
[ ($compiler == dart2js || $compiler == dart2dart) && $checked ]
diff --git a/tests/language/typed_message_test.dart b/tests/language/typed_message_test.dart
index e034d3e..d098c5c 100644
--- a/tests/language/typed_message_test.dart
+++ b/tests/language/typed_message_test.dart
@@ -8,6 +8,7 @@
library TypedMessageTest;
import "dart:async";
import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
import "dart:isolate";
void logMessages(SendPort replyTo) {
@@ -29,6 +30,7 @@
}
main() {
+ asyncStart();
ReceivePort receivePort = new ReceivePort();
Future<Isolate> remote = Isolate.spawn(logMessages, receivePort.sendPort);
List<int> msg = new List<int>(5);
@@ -43,5 +45,6 @@
}).then((b) {
Expect.equals(1, iterator.current);
receivePort.close();
+ asyncEnd();
});
}
diff --git a/tests/language/vm/optimized_guarded_field_test.dart b/tests/language/vm/optimized_guarded_field_test.dart
index c6aea4d..aefdace 100644
--- a/tests/language/vm/optimized_guarded_field_test.dart
+++ b/tests/language/vm/optimized_guarded_field_test.dart
@@ -6,6 +6,7 @@
// VMOptions=--optimization_counter_threshold=10
import "package:expect/expect.dart";
+import "dart:typed_data";
class A {
var foo;
@@ -52,6 +53,24 @@
}
+class D {
+ final List f;
+ final Uint8List g;
+ D(this.f, this.g);
+ D.named(this.f, this.g);
+}
+
+
+test_guarded_length() {
+ var a = new D(new List(5), new Uint8List(5));
+ var b = new D.named(new List(5), new Uint8List(5));
+ Expect.equals(5, a.f.length);
+ Expect.equals(5, b.f.length);
+ Expect.equals(5, a.g.length);
+ Expect.equals(5, b.g.length);
+}
+
+
main() {
var a = new A();
var b = new B();
@@ -76,4 +95,7 @@
// Regression test for fields initialized in native code (Error._stackTrace).
test_stacktrace();
+
+ // Test guarded list length.
+ for (var i = 0; i < 20; i++) test_guarded_length();
}
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index d0eed98..d05992f 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -16,7 +16,6 @@
lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError
lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError
lib/_internal/compiler/samples/darttags/darttags: CompileTimeError
-lib/_internal/compiler/samples/jsonify/jsonify: CompileTimeError
lib/_internal/compiler/samples/leap/leap: CompileTimeError
lib/_internal/compiler/samples/leap/leap_leg: CompileTimeError
lib/_internal/compiler/samples/leap/request_cache: CompileTimeError
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 20ae1c5..ad6830a 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -808,8 +808,8 @@
Future catchError(Function onError, {bool test(e)}) =>
_realFuture.catchError(onError, test: test);
Future whenComplete(action()) => _realFuture.whenComplete(action);
- Future timeout(Duration timeLimit, [void onTimeout()]) =>
- _realFuture.timeout(timeLimit, onTimeout);
+ Future timeout(Duration timeLimit, {void onTimeout()}) =>
+ _realFuture.timeout(timeLimit, onTimeout: onTimeout);
Stream asStream() => _realFuture.asStream();
String toString() => "CustomFuture@${_realFuture.hashCode}";
int get hashCode => _realFuture.hashCode;
diff --git a/tests/lib/async/future_timeout_test.dart b/tests/lib/async/future_timeout_test.dart
index f123118..cd30645 100644
--- a/tests/lib/async/future_timeout_test.dart
+++ b/tests/lib/async/future_timeout_test.dart
@@ -11,7 +11,7 @@
test("timeoutNoComplete", () {
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => 42);
+ const Duration(milliseconds: 5), onTimeout: () => 42);
timedOut.then(expectAsync1((v) {
expect(v, 42);
}));
@@ -20,7 +20,7 @@
test("timeoutCompleteAfterTimeout", () {
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => 42);
+ const Duration(milliseconds: 5), onTimeout: () => 42);
Timer timer = new Timer(const Duration(seconds: 1), () {
completer.complete(-1);
});
@@ -35,7 +35,7 @@
completer.complete(42);
});
Future timedOut = completer.future.timeout(
- const Duration(seconds: 1), () => -1);
+ const Duration(seconds: 1), onTimeout: () => -1);
timedOut.then(expectAsync1((v) {
expect(v, 42);
}));
@@ -45,7 +45,7 @@
Completer completer = new Completer.sync();
completer.complete(42);
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => -1);
+ const Duration(milliseconds: 5), onTimeout: () => -1);
timedOut.then(expectAsync1((v) {
expect(v, 42);
}));
@@ -54,7 +54,7 @@
test("timeoutThrows", () {
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () { throw "EXN1"; });
+ const Duration(milliseconds: 5), onTimeout: () { throw "EXN1"; });
timedOut.catchError(expectAsync2((e, s) {
expect(e, "EXN1");
}));
@@ -63,7 +63,7 @@
test("timeoutThrowAfterTimeout", () {
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => 42);
+ const Duration(milliseconds: 5), onTimeout: () => 42);
Timer timer = new Timer(const Duration(seconds: 1), () {
completer.completeError("EXN2");
});
@@ -78,7 +78,7 @@
completer.completeError("EXN3");
});
Future timedOut = completer.future.timeout(
- const Duration(seconds: 1), () => -1);
+ const Duration(seconds: 1), onTimeout: () => -1);
timedOut.catchError(expectAsync2((e, s) {
expect(e, "EXN3");
}));
@@ -89,7 +89,7 @@
Completer completer = new Completer.sync()..future.catchError((e){});
completer.completeError("EXN4");
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => -1);
+ const Duration(milliseconds: 5), onTimeout: () => -1);
timedOut.catchError(expectAsync2((e, s) {
expect(e, "EXN4");
}));
@@ -99,7 +99,7 @@
Future result = new Future.value(42);
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => result);
+ const Duration(milliseconds: 5), onTimeout: () => result);
timedOut.then(expectAsync1((v) {
expect(v, 42);
}));
@@ -109,7 +109,7 @@
Future result = new Future.error("EXN5")..catchError((e){});
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () => result);
+ const Duration(milliseconds: 5), onTimeout: () => result);
timedOut.catchError(expectAsync2((e, s) {
expect(e, "EXN5");
}));
@@ -119,7 +119,7 @@
Completer result = new Completer();
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () {
+ const Duration(milliseconds: 5), onTimeout: () {
result.complete(42);
return result.future;
});
@@ -132,7 +132,7 @@
Completer result = new Completer();
Completer completer = new Completer();
Future timedOut = completer.future.timeout(
- const Duration(milliseconds: 5), () {
+ const Duration(milliseconds: 5), onTimeout: () {
result.completeError("EXN6");
return result.future;
});
@@ -164,7 +164,7 @@
Future timedOut;
forked.run(() {
timedOut = completer.future.timeout(const Duration(milliseconds: 5),
- callback);
+ onTimeout: callback);
});
timedOut.then(expectAsync1((v) {
expect(callbackCalled, true);
diff --git a/tests/lib/async/future_value_chain4_test.dart b/tests/lib/async/future_value_chain4_test.dart
index 926e1b4..2c909cf 100644
--- a/tests/lib/async/future_value_chain4_test.dart
+++ b/tests/lib/async/future_value_chain4_test.dart
@@ -13,7 +13,7 @@
catchError(_, {test}) => null;
whenComplete(_) => null;
asStream() => null;
- timeout(Duration timeLimit, [void onTimeout()]) => null;
+ timeout(Duration timeLimit, {void onTimeout()}) => null;
}
main() {
diff --git a/tests/lib/async/stream_listen_zone_test.dart b/tests/lib/async/stream_listen_zone_test.dart
new file mode 100644
index 0000000..3ac944b
--- /dev/null
+++ b/tests/lib/async/stream_listen_zone_test.dart
@@ -0,0 +1,148 @@
+// 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 stream_listen_zeno_test;
+
+import "dart:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+main() {
+ asyncStart();
+ var controller;
+ for (bool overrideDone in [false, true]) {
+ for (bool sync in [false, true]) {
+ var mode = "${sync ? "-sync" : ""}${overrideDone ? "-od": ""}";
+ controller = new StreamController(sync: sync);
+ testStream("SC$mode", controller, controller.stream, overrideDone);
+ controller = new StreamController.broadcast(sync: sync);
+ testStream("BSC$mode", controller, controller.stream, overrideDone);
+ controller = new StreamController(sync: sync);
+ testStream("SCAB$mode", controller, controller.stream.asBroadcastStream(),
+ overrideDone, 3);
+ controller = new StreamController(sync: sync);
+ testStream("SCMap$mode", controller, controller.stream.map((x) => x),
+ overrideDone, 3);
+ }
+ }
+ asyncEnd();
+}
+
+void testStream(String name, StreamController controller, Stream stream,
+ bool overrideDone, [int registerExpect = 0]) {
+ asyncStart();
+ StreamSubscription sub;
+ Zone zone;
+ int registerCount = 0;
+ int callbackBits = 0;
+ int stepCount = 0;
+ Function step;
+ void nextStep() { Zone.ROOT.scheduleMicrotask(step); }
+ runZoned(() {
+ zone = Zone.current;
+ sub = stream.listen((v) {
+ Expect.identical(zone, Zone.current, name);
+ Expect.equals(42, v, name);
+ callbackBits |= 1;
+ nextStep();
+ }, onError: (e, s) {
+ Expect.identical(zone, Zone.current, name);
+ Expect.equals("ERROR", e, name);
+ callbackBits |= 2;
+ nextStep();
+ }, onDone: () {
+ Expect.identical(zone, Zone.current, name);
+ if (overrideDone) throw "RUNNING WRONG ONDONE";
+ callbackBits |= 4;
+ nextStep();
+ });
+ registerExpect += 3;
+ Expect.equals(registerExpect, registerCount, name);
+ }, zoneSpecification: new ZoneSpecification(
+ registerCallback: (self, p, z, callback()) {
+ Expect.identical(zone, self, name);
+ registerCount++;
+ return () {
+ Expect.identical(zone, Zone.current, name);
+ callback();
+ };
+ },
+ registerUnaryCallback: (self, p, z, callback(a)) {
+ Expect.identical(zone, self, name);
+ registerCount++;
+ return (a) {
+ Expect.identical(zone, Zone.current, name);
+ callback(a);
+ };
+ },
+ registerBinaryCallback: (self, package, z, callback(a, b)) {
+ Expect.identical(zone, self, name);
+ registerCount++;
+ return (a, b) {
+ Expect.identical(zone, Zone.current, name);
+ callback(a, b);
+ };
+ }
+ ));
+
+ int expectedBits = 0;
+ step = () {
+ var stepName = "$name-$stepCount";
+ Expect.identical(Zone.ROOT, Zone.current, stepName);
+ Expect.equals(expectedBits, callbackBits, stepName);
+ switch (stepCount++) {
+ case 0:
+ expectedBits |= 1;
+ controller.add(42);
+ break;
+ case 1:
+ expectedBits |= 2;
+ controller.addError("ERROR", null);
+ break;
+ case 2:
+ Expect.equals(registerExpect, registerCount, stepName);
+ sub.onData((v) {
+ Expect.identical(zone, Zone.current, stepName);
+ Expect.equals(37, v);
+ callbackBits |= 8;
+ nextStep();
+ });
+ Expect.equals(++registerExpect, registerCount, stepName);
+ expectedBits |= 8;
+ controller.add(37);
+ break;
+ case 3:
+ Expect.equals(registerExpect, registerCount, stepName);
+ sub.onError((e, s) {
+ Expect.identical(zone, Zone.current);
+ Expect.equals("BAD", e);
+ callbackBits |= 16;
+ nextStep();
+ });
+ Expect.equals(++registerExpect, registerCount, stepName);
+ expectedBits |= 16;
+ controller.addError("BAD", null);
+ break;
+ case 4:
+ Expect.equals(registerExpect, registerCount, stepName);
+ if (overrideDone) {
+ sub.onDone(() {
+ Expect.identical(zone, Zone.current);
+ callbackBits |= 32;
+ nextStep();
+ });
+ registerExpect++;
+ expectedBits |= 32;
+ } else {
+ expectedBits |= 4;
+ }
+ Expect.equals(registerExpect, registerCount, stepName);
+ controller.close();
+ break;
+ case 5:
+ asyncEnd();
+ }
+ };
+ step();
+}
diff --git a/tests/lib/async/stream_timeout_test.dart b/tests/lib/async/stream_timeout_test.dart
new file mode 100644
index 0000000..ffd25d8
--- /dev/null
+++ b/tests/lib/async/stream_timeout_test.dart
@@ -0,0 +1,171 @@
+// 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.
+
+import "dart:async";
+import "package:unittest/unittest.dart";
+
+main() {
+ const ms5 = const Duration(milliseconds: 5);
+ const halfSec = const Duration(milliseconds: 500);
+
+ test("stream timeout", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(ms5);
+ expect(tos.isBroadcast, false);
+ tos.handleError(expectAsync2((e, s) {
+ expect(e, new isInstanceOf<TimeoutException>());
+ expect(s, null);
+ })).listen((v){ fail("Unexpected event"); });
+ });
+
+ test("stream timeout add events", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(ms5, onTimeout: (sink) {
+ sink.add(42);
+ sink.addError("ERROR");
+ sink.close();
+ });
+ expect(tos.isBroadcast, false);
+ tos.listen(expectAsync1((v) { expect(v, 42); }),
+ onError: expectAsync2((e, s) { expect(e, "ERROR"); }),
+ onDone: expectAsync0((){}));
+ });
+
+ test("stream no timeout", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(halfSec);
+ int ctr = 0;
+ tos.listen((v) {
+ expect(v, 42);
+ ctr++;
+ },
+ onError: (e, s) { fail("No error expected"); },
+ onDone: expectAsync0(() {
+ expect(ctr, 2);
+ }));
+ expect(tos.isBroadcast, false);
+ c..add(42)..add(42)..close(); // Faster than a timeout!
+ });
+
+ test("stream timeout after events", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(halfSec);
+ expect(tos.isBroadcast, false);
+ int ctr = 0;
+ tos.listen((v) {
+ expect(v, 42);
+ ctr++;
+ },
+ onError: expectAsync2((e, s) {
+ expect(ctr, 2);
+ expect(e, new isInstanceOf<TimeoutException>());
+ }));
+ c..add(42)..add(42); // No close, timeout after two events.
+ });
+
+ test("broadcast stream timeout", () {
+ StreamController c = new StreamController.broadcast();
+ Stream tos = c.stream.timeout(ms5);
+ expect(tos.isBroadcast, false);
+ tos.handleError(expectAsync2((e, s) {
+ expect(e, new isInstanceOf<TimeoutException>());
+ expect(s, null);
+ })).listen((v){ fail("Unexpected event"); });
+ });
+
+ test("asBroadcast stream timeout", () {
+ StreamController c = new StreamController.broadcast();
+ Stream tos = c.stream.asBroadcastStream().timeout(ms5);
+ expect(tos.isBroadcast, false);
+ tos.handleError(expectAsync2((e, s) {
+ expect(e, new isInstanceOf<TimeoutException>());
+ expect(s, null);
+ })).listen((v){ fail("Unexpected event"); });
+ });
+
+ test("mapped stream timeout", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.map((x) => 2 * x).timeout(ms5);
+ expect(tos.isBroadcast, false);
+ tos.handleError(expectAsync2((e, s) {
+ expect(e, new isInstanceOf<TimeoutException>());
+ expect(s, null);
+ })).listen((v){ fail("Unexpected event"); });
+ });
+
+ test("events prevent timeout", () {
+ Stopwatch sw = new Stopwatch();
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+ int elapsed = sw.elapsedMilliseconds;
+ if (elapsed > 250) {
+ // This should not happen.
+ print("Periodic timer of 5 ms delayed $elapsed ms.");
+ }
+ fail("Timeout not prevented by events");
+ throw "ERROR";
+ });
+ tos.listen((v) { expect(v, 42);}, onDone: expectAsync0((){}));
+ int ctr = 200; // send this many events at 5ms intervals. Then close.
+ new Timer.periodic(ms5, (timer) {
+ sw.reset();
+ c.add(42);
+ if (--ctr == 0) {
+ timer.cancel();
+ c.close();
+ }
+ });
+ sw.start();
+ });
+
+ test("errors prevent timeout", () {
+ Stopwatch sw = new Stopwatch();
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+ int elapsed = sw.elapsedMilliseconds;
+ if (elapsed > 250) {
+ // This should not happen.
+ print("Periodic timer of 5 ms delayed $elapsed ms.");
+ }
+ fail("Timeout not prevented by errors");
+ });
+ tos.listen((_) {},
+ onError: (e, s) {
+ expect(e, "ERROR");
+ },
+ onDone: expectAsync0((){}));
+ int ctr = 200; // send this many error events at 5ms intervals. Then close.
+ new Timer.periodic(ms5, (timer) {
+ sw.reset();
+ c.addError("ERROR");
+ if (--ctr == 0) {
+ timer.cancel();
+ c.close();
+ }
+ });
+ sw.start();
+ });
+
+ test("closing prevents timeout", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+ fail("Timeout not prevented by close");
+ });
+ tos.listen((_) {}, onDone: expectAsync0((){}));
+ c.close();
+ });
+
+ test("pausing prevents timeout", () {
+ StreamController c = new StreamController();
+ Stream tos = c.stream.timeout(ms5, onTimeout: (_) {
+ fail("Timeout not prevented by close");
+ });
+ var subscription = tos.listen((_) {}, onDone: expectAsync0((){}));
+ subscription.pause();
+ new Timer(halfSec, () {
+ c.close();
+ subscription.resume();
+ });
+ });
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index d0c4728..7567494 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -10,14 +10,13 @@
math/double_pow_test: RuntimeError
math/low_test: RuntimeError
-math/random_test: RuntimeError
mirrors/basic_types_in_dart_core_test: RuntimeError # Issue 14025
mirrors/class_declarations_test/none: RuntimeError # Issue 13440
mirrors/closures_test/none: RuntimeError # Issue 6490
mirrors/constructor_kinds_test: RuntimeError # Issue 13799
mirrors/constructor_private_name_test: CompileTimeError # Issue 13597
-mirrors/equality_test/02: RuntimeError # Issue 12333
+mirrors/equality_test/02: RuntimeError # Issue 12785
mirrors/fake_function_with_call_test: RuntimeError # Issue 11612
mirrors/fake_function_without_call_test: RuntimeError # Issue 11612
mirrors/find_in_context_test: Fail # Issue 6490
@@ -30,8 +29,7 @@
mirrors/generic_local_function_test: RuntimeError # Issue 12333
mirrors/generic_mixin_test: RuntimeError # Issue 12333
mirrors/generic_mixin_applications_test: RuntimeError # Issue 12333
-mirrors/generics_substitution_test/01: RuntimeError # Issue 12087
-mirrors/hierarchy_invariants_test: RuntimeError # Issue 11863
+mirrors/hierarchy_invariants_test: RuntimeError # Issue 15262
mirrors/immutable_collections_test: RuntimeError # Issue 14030
mirrors/initializing_formals_test/01: RuntimeError # Issue 6490
mirrors/initializing_formals_test/03: CompileTimeError # Issue 12164
@@ -71,11 +69,9 @@
mirrors/redirecting_factory_test/02: RuntimeError # Issue 6490
mirrors/reflected_type_test: RuntimeError # Issue 12607
mirrors/repeated_private_anon_mixin_app_test: RuntimeError # Issue 14670
-mirrors/removed_api_test: RuntimeError # Issue 14878
mirrors/static_members_test: CompileTimeError # Issue 14633, Issue 12164
mirrors/symbol_validation_test: RuntimeError # Issue 13597
mirrors/toplevel_members_test: CompileTimeError # Issue 14633, Issue 12164
-mirrors/type_argument_is_type_variable_test: RuntimeError # Issue 12333
mirrors/typedef_test/none: RuntimeError # http://dartbug.com/6490
mirrors/typedef_metadata_test: RuntimeError # Issue 12785
mirrors/typevariable_mirror_metadata_test: CompileTimeError # Issue 10905
@@ -85,6 +81,8 @@
[ $runtime == safari ]
mirrors/return_type_test: Pass, Timeout # Issue 12858
+typed_data/setRange_2_test: Fail # Safari doesn't fully implement spec for TypedArray.set
+typed_data/setRange_3_test: Fail # Safari doesn't fully implement spec for TypedArray.set
[ $compiler == dart2js && $runtime != jsshell && $runtime != safari && $runtime != ff && $runtime != ie9 && $runtime != ie10]
math/math_test: RuntimeError
@@ -128,6 +126,7 @@
async/run_zoned8_test: Fail # Timer interface not supported: dartbug.com/7728.
async/zone_bind_test: Fail # Timer interface not supported: dartbug.com/7728.
async/future_timeout_test: Fail # Timer interface not supported: dartbug.com/7728.
+async/stream_timeout_test: Fail # Timer interface not supported: dartbug.com/7728.
[ $compiler == dart2js && $checked ]
convert/utf85_test: Pass, Slow # Issue 12029.
@@ -179,6 +178,9 @@
[ $runtime == vm ]
async/timer_not_available_test: Fail, OK
mirrors/native_class_test: Fail, OK # This test is meant to run in a browser.
+typed_data/setRange_1_test: Fail # Issue 15413
+typed_data/setRange_2_test: Fail # Issue 15413
+typed_data/setRange_3_test: Fail # Issue 15413
[ $compiler == none ]
mirrors/hierarchy_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
@@ -192,8 +194,6 @@
mirrors/symbol_validation_test: RuntimeError # Issue 13596
-mirrors/removed_api_test: RuntimeError # Issue 14931
-
mirrors/static_members_test: RuntimeError # Issue 14632
mirrors/toplevel_members_test: RuntimeError # Issue 14632
mirrors/instance_members_test: RuntimeError # Issue 14632
@@ -207,6 +207,9 @@
mirrors/immutable_collections_test: Fail # Issue 11857, Issue 14321
mirrors/library_uri_io_test: Skip # Not intended for drt as it uses dart:io.
mirrors/local_isolate_test: Skip # http://dartbug.com/12188
+typed_data/setRange_1_test: Fail # Issue 15413
+typed_data/setRange_2_test: Fail # Issue 15413
+typed_data/setRange_3_test: Fail # Issue 15413
[ $compiler == none && $runtime == drt && $system == windows ]
async/multiple_timer_test: Fail, Pass # See Issue 10982
@@ -231,8 +234,8 @@
# Issue 13921: spawnFunction is not allowed on Dartium's DOM thread.
async/timer_isolate_test: Fail
-[ ($compiler != none && $runtime != none) || ($compiler == none && ($runtime != dartium && $runtime != drt)) ]
-async/schedule_microtask_test: Fail # Issue 9001, Issue 9002
+[ $compiler == dart2js ]
+async/schedule_microtask_test: Fail # Issue 9002
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
mirrors/generic_f_bounded_mixin_application_test: CompileTimeError # Issue 14116
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
index bb3b347..28cf084 100644
--- a/tests/lib/math/random_test.dart
+++ b/tests/lib/math/random_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.
-// Test that a coin toss with Random.nextBool() is fair.
+// Test that rnd.nextInt with a seed generates the same sequence each time.
// Library tag to allow Dartium to run the test.
library random_test;
@@ -13,42 +13,44 @@
main() {
var rnd = new Random(20130307);
// Make sure we do not break the random number generation.
- var i = 0;
- Expect.equals( 1, rnd.nextInt(1 << ++i));
- Expect.equals( 1, rnd.nextInt(1 << ++i));
- Expect.equals( 7, rnd.nextInt(1 << ++i));
- Expect.equals( 6, rnd.nextInt(1 << ++i));
- Expect.equals( 6, rnd.nextInt(1 << ++i));
- Expect.equals( 59, rnd.nextInt(1 << ++i));
- Expect.equals( 11, rnd.nextInt(1 << ++i));
- Expect.equals( 212, rnd.nextInt(1 << ++i));
- Expect.equals( 17, rnd.nextInt(1 << ++i));
- Expect.equals( 507, rnd.nextInt(1 << ++i));
- Expect.equals( 1060, rnd.nextInt(1 << ++i));
- Expect.equals( 891, rnd.nextInt(1 << ++i));
- Expect.equals( 1534, rnd.nextInt(1 << ++i));
- Expect.equals( 8404, rnd.nextInt(1 << ++i));
- Expect.equals( 13839, rnd.nextInt(1 << ++i));
- Expect.equals( 23298, rnd.nextInt(1 << ++i));
- Expect.equals( 53622, rnd.nextInt(1 << ++i));
- Expect.equals( 205997, rnd.nextInt(1 << ++i));
- Expect.equals( 393823, rnd.nextInt(1 << ++i));
- Expect.equals( 514614, rnd.nextInt(1 << ++i));
- Expect.equals( 233715, rnd.nextInt(1 << ++i));
- Expect.equals( 895357, rnd.nextInt(1 << ++i));
- Expect.equals( 4726185, rnd.nextInt(1 << ++i));
- Expect.equals( 7976427, rnd.nextInt(1 << ++i));
- Expect.equals( 31792146, rnd.nextInt(1 << ++i));
- Expect.equals( 35563210, rnd.nextInt(1 << ++i));
- Expect.equals( 113261265, rnd.nextInt(1 << ++i));
- Expect.equals( 205117298, rnd.nextInt(1 << ++i));
- Expect.equals( 447729735, rnd.nextInt(1 << ++i));
- Expect.equals(1072507596, rnd.nextInt(1 << ++i));
- Expect.equals(2134030067, rnd.nextInt(1 << ++i));
- Expect.equals(721180690, rnd.nextInt(1 << ++i));
- Expect.equals(32, i);
+ // If the random algorithm changes, make sure both the VM and dart2js
+ // generate the same new sequence.
+ var i = 1;
+ Expect.equals( 1, rnd.nextInt(i *= 2));
+ Expect.equals( 1, rnd.nextInt(i *= 2));
+ Expect.equals( 7, rnd.nextInt(i *= 2));
+ Expect.equals( 6, rnd.nextInt(i *= 2));
+ Expect.equals( 6, rnd.nextInt(i *= 2));
+ Expect.equals( 59, rnd.nextInt(i *= 2));
+ Expect.equals( 11, rnd.nextInt(i *= 2));
+ Expect.equals( 212, rnd.nextInt(i *= 2));
+ Expect.equals( 17, rnd.nextInt(i *= 2));
+ Expect.equals( 507, rnd.nextInt(i *= 2));
+ Expect.equals( 1060, rnd.nextInt(i *= 2));
+ Expect.equals( 891, rnd.nextInt(i *= 2));
+ Expect.equals( 1534, rnd.nextInt(i *= 2));
+ Expect.equals( 8404, rnd.nextInt(i *= 2));
+ Expect.equals( 13839, rnd.nextInt(i *= 2));
+ Expect.equals( 23298, rnd.nextInt(i *= 2));
+ Expect.equals( 53622, rnd.nextInt(i *= 2));
+ Expect.equals( 205997, rnd.nextInt(i *= 2));
+ Expect.equals( 393823, rnd.nextInt(i *= 2));
+ Expect.equals( 514614, rnd.nextInt(i *= 2));
+ Expect.equals( 233715, rnd.nextInt(i *= 2));
+ Expect.equals( 895357, rnd.nextInt(i *= 2));
+ Expect.equals( 4726185, rnd.nextInt(i *= 2));
+ Expect.equals( 7976427, rnd.nextInt(i *= 2));
+ Expect.equals( 31792146, rnd.nextInt(i *= 2));
+ Expect.equals( 35563210, rnd.nextInt(i *= 2));
+ Expect.equals( 113261265, rnd.nextInt(i *= 2));
+ Expect.equals( 205117298, rnd.nextInt(i *= 2));
+ Expect.equals( 447729735, rnd.nextInt(i *= 2));
+ Expect.equals(1072507596, rnd.nextInt(i *= 2));
+ Expect.equals(2134030067, rnd.nextInt(i *= 2));
+ Expect.equals( 721180690, rnd.nextInt(i *= 2));
+ Expect.equals(0x100000000, i);
// If max is too large expect an ArgumentError.
- Expect.throws(() => rnd.nextInt((1 << i)+1), (e) => e is ArgumentError);
+ Expect.throws(() => rnd.nextInt(i + 1), (e) => e is ArgumentError);
rnd = new Random(6790);
Expect.approxEquals(0.7360144236, rnd.nextDouble());
diff --git a/tests/lib/mirrors/equality_test.dart b/tests/lib/mirrors/equality_test.dart
index b99c311..af15ca9 100644
--- a/tests/lib/mirrors/equality_test.dart
+++ b/tests/lib/mirrors/equality_test.dart
@@ -32,7 +32,7 @@
equivalenceClass.forEach((name, member) {
equivalenceClass.forEach((otherName, otherMember) {
// Reflexivity, symmetry and transitivity.
- Expect.equals(member,
+ Expect.equals(member,
otherMember,
"$name == $otherName");
Expect.equals(member.hashCode,
@@ -112,27 +112,29 @@
'reflect(new A<int>()).type.originalDeclaration' :
reflect(new A<int>()).type.originalDeclaration},
- {'reflectClass(B).superclass' : reflectClass(B).superclass, /// 02: ok
- 'reflect(new A<int>()).type' : reflect(new A<int>()).type}, /// 02: ok
+ {'reflectClass(B).superclass' : reflectClass(B).superclass,
+ 'reflect(new A<int>()).type' : reflect(new A<int>()).type},
{'reflectClass(B)' : reflectClass(B),
'thisLibrary.declarations[#B]' : thisLibrary.declarations[#B],
'reflect(new B()).type' : reflect(new B()).type},
- {'reflectClass(BadEqualityHash).declarations[#==]' /// 02: ok
- : reflectClass(BadEqualityHash).declarations[#==], /// 02: ok
- 'reflect(new BadEqualityHash()).type.declarations[#==]' /// 02: ok
- : reflect(new BadEqualityHash()).type.declarations[#==]}, /// 02: ok
+ {'reflectClass(BadEqualityHash).declarations[#==]'
+ : reflectClass(BadEqualityHash).declarations[#==],
+ 'reflect(new BadEqualityHash()).type.declarations[#==]'
+ : reflect(new BadEqualityHash()).type.declarations[#==]},
- {'reflectClass(BadEqualityHash).declarations[#==].parameters[0]' /// 02: ok
- : (reflectClass(BadEqualityHash).declarations[#==] as MethodMirror).parameters[0], /// 02: ok
- 'reflect(new BadEqualityHash()).type.declarations[#==].parameters[0]' /// 02: ok
- : (reflect(new BadEqualityHash()).type.declarations[#==] as MethodMirror).parameters[0]}, /// 02: ok
+ {'reflectClass(BadEqualityHash).declarations[#==].parameters[0]'
+ : (reflectClass(BadEqualityHash).
+ declarations[#==] as MethodMirror).parameters[0],
+ 'reflect(new BadEqualityHash()).type.declarations[#==].parameters[0]'
+ : (reflect(new BadEqualityHash()).type.
+ declarations[#==] as MethodMirror).parameters[0]},
- {'reflectClass(BadEqualityHash).declarations[#count]' /// 02: ok
- : reflectClass(BadEqualityHash).declarations[#count], /// 02: ok
- 'reflect(new BadEqualityHash()).type.declarations[#count]' /// 02: ok
- : reflect(new BadEqualityHash()).type.declarations[#count]}, /// 02: ok
+ {'reflectClass(BadEqualityHash).declarations[#count]'
+ : reflectClass(BadEqualityHash).declarations[#count],
+ 'reflect(new BadEqualityHash()).type.declarations[#count]'
+ : reflect(new BadEqualityHash()).type.declarations[#count]},
{'reflectType(Predicate)' : reflectType(Predicate), /// 02: ok
'thisLibrary.declarations[#somePredicate].type' /// 02: ok
@@ -142,10 +144,10 @@
'thisLibrary.declarations[#somePredicate].type.referent' /// 02: ok
: ((thisLibrary.declarations[#somePredicate] as VariableMirror).type as TypedefMirror).referent}, /// 02: ok
- {'reflectClass(A).typeVariables.single' /// 02: ok
- : reflectClass(A).typeVariables.single, /// 02: ok
- 'reflect(new A<int>()).type.originalDeclaration.typeVariables.single' /// 02: ok
- : reflect(new A<int>()).type.originalDeclaration.typeVariables.single}, /// 02: ok
+ {'reflectClass(A).typeVariables.single'
+ : reflectClass(A).typeVariables.single,
+ 'reflect(new A<int>()).type.originalDeclaration.typeVariables.single'
+ : reflect(new A<int>()).type.originalDeclaration.typeVariables.single},
{'currentMirrorSystem()' : currentMirrorSystem()},
diff --git a/tests/lib/mirrors/generics_substitution_test.dart b/tests/lib/mirrors/generics_substitution_test.dart
index 58a0269..de13f2e 100644
--- a/tests/lib/mirrors/generics_substitution_test.dart
+++ b/tests/lib/mirrors/generics_substitution_test.dart
@@ -36,20 +36,20 @@
Symbol t(ClassMirror cm) =>
(cm.declarations[#t] as MethodMirror).returnType.simpleName;
- Expect.equals(#T, r(genericDecl.superclass)); /// 01: ok
+ Expect.equals(#T, r(genericDecl.superclass));
Expect.equals(#int, s(genericDecl.superclass));
Expect.equals(#T, t(genericDecl));
- Expect.equals(#String, r(genericOfString.superclass)); /// 01: ok
+ Expect.equals(#String, r(genericOfString.superclass));
Expect.equals(#int, s(genericOfString.superclass));
Expect.equals(#String, t(genericOfString));
- Expect.equals(#R, r(superGenericDecl)); /// 01: ok
+ Expect.equals(#R, r(superGenericDecl));
Expect.equals(#S, s(superGenericDecl));
- Expect.equals(#T, r(superOfTAndInt)); /// 01: ok
+ Expect.equals(#T, r(superOfTAndInt));
Expect.equals(#int, s(superOfTAndInt));
- Expect.equals(#String, r(superOfStringAndInt)); /// 01: ok
+ Expect.equals(#String, r(superOfStringAndInt));
Expect.equals(#int, s(superOfStringAndInt));
}
diff --git a/tests/lib/typed_data/setRange_1_test.dart b/tests/lib/typed_data/setRange_1_test.dart
new file mode 100644
index 0000000..ea7d6dc
--- /dev/null
+++ b/tests/lib/typed_data/setRange_1_test.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.
+
+import 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+sameTypeTest() {
+ checkSameSize(makeInt16List, makeInt16View, makeInt16View);
+ checkSameSize(makeUint16List, makeUint16View, makeUint16View);
+}
+
+main() {
+ sameTypeTest();
+}
diff --git a/tests/lib/typed_data/setRange_2_test.dart b/tests/lib/typed_data/setRange_2_test.dart
new file mode 100644
index 0000000..83abbba
--- /dev/null
+++ b/tests/lib/typed_data/setRange_2_test.dart
@@ -0,0 +1,17 @@
+// 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.
+
+import 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+sameElementSizeTest() {
+ // Views of elements with the same size but different 'types'.
+ checkSameSize(makeInt16List, makeInt16View, makeUint16View);
+ checkSameSize(makeInt16List, makeUint16View, makeInt16View);
+}
+
+main() {
+ sameElementSizeTest();
+}
diff --git a/tests/lib/typed_data/setRange_3_test.dart b/tests/lib/typed_data/setRange_3_test.dart
new file mode 100644
index 0000000..9774811
--- /dev/null
+++ b/tests/lib/typed_data/setRange_3_test.dart
@@ -0,0 +1,35 @@
+// 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.
+
+import 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+expandContractTest() {
+ // Copying between views that have different element sizes can't be done with
+ // a single scan-up or scan-down.
+ //
+ // Typed lists a1 and a2 share a buffer as follows:
+ //
+ // a1: aaaabbbbccccddddeeeeffffgggghhhh
+ // a2: abcdefgh
+
+ var a1 = new Int32List(8);
+ var buffer = a1.buffer;
+ var a2 = new Int8List.view(buffer, 12, 8);
+
+ initialize(a2);
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a2');
+ a1.setRange(0, 8, a2);
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a1');
+
+ initialize(a1);
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a1');
+ a2.setRange(0, 8, a1);
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a2');
+}
+
+main() {
+ expandContractTest();
+}
diff --git a/tests/lib/typed_data/setRange_lib.dart b/tests/lib/typed_data/setRange_lib.dart
new file mode 100644
index 0000000..bcdd302
--- /dev/null
+++ b/tests/lib/typed_data/setRange_lib.dart
@@ -0,0 +1,65 @@
+// 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 setRange_lib;
+
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+initialize(a) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i + 1;
+ }
+}
+
+makeInt16View(buffer, byteOffset, length) =>
+ new Int16List.view(buffer, byteOffset, length);
+
+makeUint16View(buffer, byteOffset, length) =>
+ new Uint16List.view(buffer, byteOffset, length);
+
+makeInt16List(length) => new Int16List(length);
+makeUint16List(length) => new Uint16List(length);
+
+checkSameSize(constructor0, constructor1, constructor2) {
+ // Typed lists a1 and a2 share a buffer as follows (bytes):
+ //
+ // a0: aabbccddeeffgghhii
+ // a1: aabbccddeeffgg
+ // a2: aabbccddeeffgg
+
+ var a0 = constructor0(9);
+ var buffer = a0.buffer;
+ var a1 = constructor1(buffer, 0, 7);
+ var a2 = constructor2(buffer, 2 * a0.elementSizeInBytes, 7);
+
+ initialize(a0);
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8, 9]', '$a0');
+ Expect.equals('[1, 2, 3, 4, 5, 6, 7]', '$a1');
+ Expect.equals('[3, 4, 5, 6, 7, 8, 9]', '$a2');
+
+ initialize(a0);
+ a1.setRange(0, 7, a2);
+ Expect.equals('[3, 4, 5, 6, 7, 8, 9, 8, 9]', '$a0');
+
+ initialize(a0);
+ a2.setRange(0, 7, a1);
+ Expect.equals('[1, 2, 1, 2, 3, 4, 5, 6, 7]', '$a0');
+
+ initialize(a0);
+ a1.setRange(1, 7, a2);
+ Expect.equals('[1, 3, 4, 5, 6, 7, 8, 8, 9]', '$a0');
+
+ initialize(a0);
+ a2.setRange(1, 7, a1);
+ Expect.equals('[1, 2, 3, 1, 2, 3, 4, 5, 6]', '$a0');
+
+ initialize(a0);
+ a1.setRange(0, 6, a2, 1);
+ Expect.equals('[4, 5, 6, 7, 8, 9, 7, 8, 9]', '$a0');
+
+ initialize(a0);
+ a2.setRange(0, 6, a1, 1);
+ Expect.equals('[1, 2, 2, 3, 4, 5, 6, 7, 9]', '$a0');
+}
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
index f813e3b..075115e 100644
--- a/tests/standalone/debugger/debug_lib.dart
+++ b/tests/standalone/debugger/debug_lib.dart
@@ -184,8 +184,9 @@
class FrameMatcher extends Command {
int frameIndex;
List<String> functionNames;
+ bool exactMatch;
- FrameMatcher(this.frameIndex, this.functionNames) {
+ FrameMatcher(this.frameIndex, this.functionNames, this.exactMatch) {
template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
}
@@ -211,7 +212,9 @@
var idx = i + frameIndex;
var name = frames[idx]["functionName"];
assert(name != null);
- if (name != functionNames[i]) {
+ bool isMatch = exactMatch ? name == functionNames[i]
+ : name.contains(functionNames[i]);
+ if (!isMatch) {
debugger.error("Error: call frame $idx: "
"expected function name '${functionNames[i]}' but found '$name'");
return;
@@ -221,12 +224,12 @@
}
-MatchFrame(int frameIndex, String functionName) {
- return new FrameMatcher(frameIndex, [ functionName ]);
+MatchFrame(int frameIndex, String functionName, {exactMatch: false}) {
+ return new FrameMatcher(frameIndex, [functionName], exactMatch);
}
-MatchFrames(List<String> functionNames) {
- return new FrameMatcher(0, functionNames);
+MatchFrames(List<String> functionNames, {exactMatch: false}) {
+ return new FrameMatcher(0, functionNames, exactMatch);
}
diff --git a/tests/standalone/debugger/mixin_closure_debugger_test.dart b/tests/standalone/debugger/mixin_closure_debugger_test.dart
new file mode 100644
index 0000000..5e6fd5e
--- /dev/null
+++ b/tests/standalone/debugger/mixin_closure_debugger_test.dart
@@ -0,0 +1,54 @@
+// 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.
+
+// This test forks a second vm process that runs this dart script as
+// a debug target.
+// Run this test with option --wire to see the json messages sent
+// between the processes.
+// Run this test with option --verbose to see the stdout and stderr output
+// of the debug target process.
+
+// This test checks that a breakpoint can be set and is hit in a closure
+// inside a mixin function. Regression test for issue 15325.
+
+import "debug_lib.dart";
+
+class S { }
+
+class M {
+ m() {
+ var sum = 0;
+ [1,2,3].forEach((e) {
+ sum += e; // Breakpoint here.
+ });
+ return sum;
+ }
+}
+
+class A = S with M;
+
+main(List<String> arguments) {
+ if (RunScript(testScript, arguments)) return;
+ var a = new A();
+ print(a.m());
+}
+
+// Expected debugger events and commands.
+var testScript = [
+ MatchFrame(0, "main"), // Top frame in trace is function "main".
+ SetBreakpoint(23), // Set breakpoint inside the forEach closure.
+ Resume(),
+ MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+ exactMatch: false), // First iteration.
+ MatchLocals({"e": "1"}),
+ Resume(),
+ MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+ exactMatch: false), // Second iteration.
+ MatchLocals({"e": "2"}),
+ Resume(),
+ MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+ exactMatch: false), // Third iteration.
+ MatchLocals({"e": "3"}),
+ Resume(),
+];
diff --git a/tests/standalone/io/http_server_test.dart b/tests/standalone/io/http_server_test.dart
index 00dc5cd..b406f7f 100644
--- a/tests/standalone/io/http_server_test.dart
+++ b/tests/standalone/io/http_server_test.dart
@@ -60,6 +60,57 @@
});
}
+
+void testHttpServerZone() {
+ asyncStart();
+ Expect.equals(Zone.ROOT, Zone.current);
+ runZoned(() {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ server.listen((request) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ request.response.close();
+ server.close();
+ });
+ new HttpClient().get("127.0.0.1", server.port, '/')
+ .then((request) => request.close())
+ .then((response) => response.drain())
+ .then((_) => asyncEnd());
+ });
+ });
+}
+
+
+void testHttpServerZoneError() {
+ asyncStart();
+ Expect.equals(Zone.ROOT, Zone.current);
+ runZoned(() {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ server.listen((request) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ request.listen((_) {}, onError: (error) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ server.close();
+ throw error;
+ });
+ });
+ Socket.connect("127.0.0.1", server.port).then((socket) {
+ socket.write('GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n');
+ socket.write('some body');
+ socket.close();
+ });
+ });
+ }, onError: (e) {
+ asyncEnd();
+ });
+}
+
+
void main() {
testListenOn();
+ testHttpServerZone();
+ testHttpServerZoneError();
}
diff --git a/tests/standalone/io/network_interface_test.dart b/tests/standalone/io/network_interface_test.dart
index ee6a25e..2d49ce0 100644
--- a/tests/standalone/io/network_interface_test.dart
+++ b/tests/standalone/io/network_interface_test.dart
@@ -33,7 +33,21 @@
}
+void testListIndex() {
+ var set = new Set();
+ NetworkInterface.list(includeLoopback: true).then((list) {
+ for (var i in list) {
+ Expect.isNotNull(i.index);
+ Expect.isFalse(set.contains(i.index));
+ set.add(i.index);
+ Expect.isTrue(set.contains(i.index));
+ }
+ });
+}
+
+
void main() {
testListLoopback();
testListLinkLocal();
+ testListIndex();
}
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
index 53a5e02..ddf5611 100644
--- a/tests/standalone/io/raw_socket_test.dart
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -376,6 +376,63 @@
});
}
+void testSocketZone() {
+ asyncStart();
+ Expect.equals(Zone.ROOT, Zone.current);
+ runZoned(() {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ server.listen((socket) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ socket.close();
+ server.close();
+ });
+ RawSocket.connect("127.0.0.1", server.port).then((socket) {
+ socket.listen((event) {
+ if (event == RawSocketEvent.READ_CLOSED) {
+ socket.close();
+ asyncEnd();
+ }
+ });
+ });
+ });
+ });
+}
+
+void testSocketZoneError() {
+ asyncStart();
+ Expect.equals(Zone.ROOT, Zone.current);
+ runZoned(() {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ server.listen((socket) {
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ var timer;
+ void write() {
+ socket.write(const [0]);
+ timer = new Timer(const Duration(milliseconds: 5), write);
+ }
+ write();
+ socket.listen((_) {
+ }, onError: (error) {
+ timer.cancel();
+ Expect.notEquals(Zone.ROOT, Zone.current);
+ socket.close();
+ server.close();
+ throw error;
+ });
+ });
+ RawSocket.connect("127.0.0.1", server.port).then((socket) {
+ socket.close();
+ });
+ });
+ }, onError: (e) {
+ asyncEnd();
+ });
+}
+
main() {
asyncStart();
testArguments();
@@ -389,5 +446,7 @@
testSimpleReadWrite(dropReads: true);
testPauseServerSocket();
testPauseSocket();
+ testSocketZone();
+ testSocketZoneError();
asyncEnd();
}
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index b66f951..c9a30bc 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -54,7 +54,7 @@
get hashCode => throw 'Interceptor.hashCode not implemented.';
}
class JSIndexable {
- get length;
+ get length {}
}
class JSMutableIndexable {}
class JSArray<E> implements JSIndexable {
diff --git a/tools/VERSION b/tools/VERSION
index ef56901..0795e2b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,5 +1,5 @@
CHANNEL dev
MAJOR 1
MINOR 0
-BUILD 2
-PATCH 1
+BUILD 3
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 0ed83e6..f54685e 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -144,7 +144,8 @@
'--time',
'--use-sdk',
'--report',
- '--write-debug-log'])
+ '--write-debug-log',
+ '--write-test-outcome-log'])
if user_test == 'yes':
cmd.append('--progress=color')
diff --git a/tools/bots/cross-vm.py b/tools/bots/cross-vm.py
index 08ae335..691544c 100644
--- a/tools/bots/cross-vm.py
+++ b/tools/bots/cross-vm.py
@@ -70,7 +70,7 @@
test_py = os.path.join('tools', 'test.py')
test_args = [sys.executable, test_py, '--progress=line', '--report',
'--time', '--compiler=none', '--runtime=vm', '--write-debug-log',
- '--mode=' + mode, '--arch=' + arch]
+ '--write-test-outcome-log', '--mode=' + mode, '--arch=' + arch]
revision = int(os.environ['BUILDBOT_GOT_REVISION'])
tarball = tarball_name(arch, mode, revision)
@@ -87,7 +87,7 @@
run(test_args)
with bot.BuildStep('execute checked_tests'):
- run(test_args + ['--checked'])
+ run(test_args + ['--checked', '--append_logs'])
finally:
for path in temporary_files:
if os.path.exists(path):
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
index 4248459..918218f 100644
--- a/tools/ddbg.dart
+++ b/tools/ddbg.dart
@@ -8,6 +8,7 @@
import "dart:convert";
import "dart:io";
import "dart:async";
+import "dart:math";
import "ddbg/lib/commando.dart";
@@ -26,11 +27,14 @@
Socket vmSock;
String vmData;
+var cmdSubscription;
Commando cmdo;
var vmSubscription;
int seqNum = 0;
-Process targetProcess;
+bool isDebugging = false;
+Process targetProcess = null;
+bool suppressNextExitCode = false;
final verbose = false;
final printMessages = false;
@@ -38,38 +42,7 @@
TargetIsolate currentIsolate;
TargetIsolate mainIsolate;
-
-void printHelp() {
- print("""
- q Quit debugger shell
- bt Show backtrace
- r Resume execution
- s Single step
- so Step over
- si Step into
- sbp [<file>] <line> Set breakpoint
- rbp <id> Remove breakpoint with given id
- po <id> Print object info for given id
- eval obj <id> <expr> Evaluate expr on object id
- eval cls <id> <expr> Evaluate expr on class id
- eval lib <id> <expr> Evaluate expr in toplevel of library id
- pl <id> <idx> [<len>] Print list element/slice
- pc <id> Print class info for given id
- ll List loaded libraries
- plib <id> Print library info for given library id
- slib <id> <true|false> Set library id debuggable
- pg <id> Print all global variables visible within given library id
- ls <lib_id> List loaded scripts in library
- gs <lib_id> <script_url> Get source text of script in library
- tok <lib_id> <script_url> Get line and token table of script in library
- epi <none|all|unhandled> Set exception pause info
- li List ids of all isolates in the VM
- sci <id> Set current target isolate
- i <id> Interrupt execution of given isolate id
- h Print help
-""");
-}
-
+int debugPort = 5858;
String formatLocation(Map location) {
if (location == null) return "";
@@ -78,13 +51,6 @@
}
-void quitShell() {
- vmSubscription.cancel();
- vmSock.close();
- cmdo.done();
-}
-
-
Future sendCmd(Map<String, dynamic> cmd) {
var completer = new Completer.sync();
int id = cmd["id"];
@@ -113,23 +79,427 @@
return false;
}
+// These settings are allowed in the 'set' and 'show' debugger commands.
+var validSettings = ['vm', 'vmargs', 'script', 'args'];
+
+// The current values for all settings.
+var settings = new Map();
+
+// Generates a string of 'count' spaces.
+String _spaces(int count) {
+ return new List.filled(count, ' ').join('');
+}
+
+// TODO(turnidge): Move all commands here.
+List<Command> commandList =
+ [ new HelpCommand(),
+ new QuitCommand(),
+ new RunCommand(),
+ new KillCommand(),
+ new ConnectCommand(),
+ new DisconnectCommand(),
+ new SetCommand(),
+ new ShowCommand() ];
+
+
+Command matchCommand(String commandName, bool exactMatchWins) {
+ List matches = [];
+ for (var command in commandList) {
+ if (command.name.startsWith(commandName)) {
+ if (exactMatchWins && command.name == commandName) {
+ // Exact match
+ return [command];
+ } else {
+ matches.add(command);
+ }
+ }
+ }
+ return matches;
+}
+
+abstract class Command {
+ String get name;
+ Future run(List<String> args);
+}
+
+class HelpCommand extends Command {
+ final name = 'help';
+ final helpShort = 'Show a list of debugger commands';
+ final helpLong ="""
+Show a list of debugger commands or get more information about a
+particular command.
+
+Usage:
+ help
+ help <command>
+""";
+
+ Future run(List<String> args) {
+ if (args.length == 1) {
+ print("Debugger commands:\n");
+ for (var command in commandList) {
+ const tabStop = 12;
+ var spaces = _spaces(max(1, (tabStop - command.name.length)));
+ print(' ${command.name}${spaces}${command.helpShort}');
+ }
+
+ // TODO(turnidge): Convert all commands to use the Command class.
+ print("""
+ bt Show backtrace
+ r Resume execution
+ s Single step
+ so Step over
+ si Step into
+ sbp [<file>] <line> Set breakpoint
+ rbp <id> Remove breakpoint with given id
+ po <id> Print object info for given id
+ eval obj <id> <expr> Evaluate expr on object id
+ eval cls <id> <expr> Evaluate expr on class id
+ eval lib <id> <expr> Evaluate expr in toplevel of library id
+ pl <id> <idx> [<len>] Print list element/slice
+ pc <id> Print class info for given id
+ ll List loaded libraries
+ plib <id> Print library info for given library id
+ slib <id> <true|false> Set library id debuggable
+ pg <id> Print all global variables visible within given library id
+ ls <lib_id> List loaded scripts in library
+ gs <lib_id> <script_url> Get source text of script in library
+ tok <lib_id> <script_url> Get line and token table of script in library
+ epi <none|all|unhandled> Set exception pause info
+ li List ids of all isolates in the VM
+ sci <id> Set current target isolate
+ i <id> Interrupt execution of given isolate id
+""");
+
+ print("For more information about a particular command, type:\n\n"
+ " help <command>\n");
+
+ print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
+ } else if (args.length == 2) {
+ var commandName = args[1];
+ var matches = matchCommand(commandName, true);
+ if (matches.length == 0) {
+ print("Command '$commandName' not recognized. "
+ "Try 'help' for a list of commands.");
+ } else {
+ for (var command in matches) {
+ print("---- ${command.name} ----\n${command.helpLong}");
+ }
+ }
+ } else {
+ print("Command '$command' not recognized. "
+ "Try 'help' for a list of commands.");
+ }
+
+ return new Future.value();
+ }
+}
+
+
+class QuitCommand extends Command {
+ final name = 'quit';
+ final helpShort = 'Quit the debugger.';
+ final helpLong ="""
+Quit the debugger.
+
+Usage:
+ quit
+""";
+
+ Future run(List<String> args) {
+ if (args.length > 1) {
+ print("Unexpected arguments to $name command.");
+ return new Future.value();
+ }
+ return debuggerQuit();
+ }
+}
+
+class SetCommand extends Command {
+ final name = 'set';
+ final helpShort = 'Change the value of a debugger setting.';
+ final helpLong ="""
+Change the value of a debugger setting.
+
+Usage:
+ set <setting> <value>
+
+Valid settings are:
+ ${validSettings.join('\n ')}.
+
+See also 'help show'.
+""";
+
+ Future run(List<String> args) {
+ if (args.length < 3 || !validSettings.contains(args[1])) {
+ print("Undefined $name command. Try 'help $name'.");
+ return new Future.value();
+ }
+ var option = args[1];
+ var value = args.getRange(2, args.length).join(' ');
+ settings[option] = value;
+ return new Future.value();
+ }
+}
+
+class ShowCommand extends Command {
+ final name = 'show';
+ final helpShort = 'Show the current value of a debugger setting.';
+ final helpLong ="""
+Show the current value of a debugger setting.
+
+Usage:
+ show
+ show <setting>
+
+If no <setting> is specified, all current settings are shown.
+
+Valid settings are:
+ ${validSettings.join('\n ')}.
+
+See also 'help set'.
+""";
+
+ Future run(List<String> args) {
+ if (args.length == 1) {
+ for (var option in validSettings) {
+ var value = settings[option];
+ print("$option = '$value'");
+ }
+ } else if (args.length == 2 && validSettings.contains(args[1])) {
+ var option = args[1];
+ var value = settings[option];
+ if (value == null) {
+ print('$option has not been set.');
+ } else {
+ print("$option = '$value'");
+ }
+ return new Future.value();
+ } else {
+ print("Undefined $name command. Try 'help $name'.");
+ }
+ return new Future.value();
+ }
+}
+
+class RunCommand extends Command {
+ final name = 'run';
+ final helpShort = "Run the currrent script.";
+ final helpLong ="""
+Runs the current script.
+
+Usage:
+ run
+ run <args>
+
+The current script will be run on the current vm. The 'vm' and
+'vmargs' settings are used to specify the current vm and vm arguments.
+The 'script' and 'args' settings are used to specify the current
+script and script arguments.
+
+For more information on settings type 'help show' or 'help set'.
+
+If <args> are provided to the run command, it is the same as typing
+'set args <args>' followed by 'run'.
+""";
+
+ Future run(List<String> cmdArgs) {
+ if (isDebugging) {
+ // TODO(turnidge): Implement modal y/n dialog to stop running script.
+ print("There is already a running dart process. "
+ "Try 'kill'.");
+ return new Future.value();
+ }
+ assert(targetProcess == null);
+ if (settings['script'] == null) {
+ print("There is no script specified. "
+ "Use 'set script' to set the current script.");
+ return new Future.value();
+ }
+ if (cmdArgs.length > 1) {
+ settings['args'] = cmdArgs.getRange(1, cmdArgs.length);
+ }
+
+ // Build the process arguments.
+ var processArgs = ['--debug:$debugPort'];
+ if (verbose) {
+ processArgs.add('--verbose_debug');
+ }
+ if (settings['vmargs'] != null) {
+ processArgs.addAll(settings['vmargs'].split(' '));
+ }
+ processArgs.add(settings['script']);
+ if (settings['args'] != null) {
+ processArgs.addAll(settings['args'].split(' '));
+ }
+ String vm = settings['vm'];
+
+ isDebugging = true;
+ cmdo.hide();
+ return Process.start(vm, processArgs).then((Process process) {
+ print("Started process ${process.pid} '$vm ${processArgs.join(' ')}'");
+ targetProcess = process;
+ process.stdin.close();
+
+ // TODO(turnidge): For now we only show full lines of output
+ // from the debugged process. Should show each character.
+ process.stdout
+ .transform(UTF8.decoder)
+ .transform(new LineSplitter())
+ .listen((String line) {
+ cmdo.hide();
+ // TODO(turnidge): Escape output in any way?
+ print(line);
+ cmdo.show();
+ });
+
+ process.stderr
+ .transform(UTF8.decoder)
+ .transform(new LineSplitter())
+ .listen((String line) {
+ cmdo.hide();
+ print(line);
+ cmdo.show();
+ });
+
+ process.exitCode.then((int exitCode) {
+ cmdo.hide();
+ if (suppressNextExitCode) {
+ suppressNextExitCode = false;
+ } else {
+ if (exitCode == 0) {
+ print('Process exited normally.');
+ } else {
+ print('Process exited with code $exitCode.');
+ }
+ }
+ targetProcess = null;
+ cmdo.show();
+ });
+
+ // Wait for the vm to open the debugging port.
+ return openVmSocket(0);
+ });
+ }
+}
+
+class KillCommand extends Command {
+ final name = 'kill';
+ final helpShort = 'Kill the currently executing script.';
+ final helpLong ="""
+Kill the currently executing script.
+
+Usage:
+ kill
+""";
+
+ Future run(List<String> cmdArgs) {
+ if (!isDebugging) {
+ print('There is no running script.');
+ return new Future.value();
+ }
+ if (targetProcess == null) {
+ print("The active dart process was not started with 'run'. "
+ "Try 'disconnect' instead.");
+ return new Future.value();
+ }
+ assert(targetProcess != null);
+ bool result = targetProcess.kill();
+ if (result) {
+ print('Process killed.');
+ suppressNextExitCode = true;
+ } else {
+ print('Unable to kill process ${targetProcess.pid}');
+ }
+ return new Future.value();
+ }
+}
+
+class ConnectCommand extends Command {
+ final name = 'connect';
+ final helpShort = "Connect to a running dart script.";
+ final helpLong ="""
+Connect to a running dart script.
+
+Usage:
+ connect
+ connect <port>
+
+The debugger will connect to a dart script which has already been
+started with the --debug option. If no port is provided, the debugger
+will attempt to connect on the default debugger port.
+""";
+
+ Future run(List<String> cmdArgs) {
+ if (cmdArgs.length > 2) {
+ print("Too many arguments to 'connect'.");
+ }
+ if (isDebugging) {
+ // TODO(turnidge): Implement modal y/n dialog to stop running script.
+ print("There is already a running dart process. "
+ "Try 'kill'.");
+ return new Future.value();
+ }
+ assert(targetProcess == null);
+ if (cmdArgs.length == 2) {
+ debugPort = int.parse(cmdArgs[1]);
+ }
+
+ isDebugging = true;
+ cmdo.hide();
+ return openVmSocket(0);
+ }
+}
+
+class DisconnectCommand extends Command {
+ final name = 'disconnect';
+ final helpShort = "Disconnect from a running dart script.";
+ final helpLong ="""
+Disconnect from a running dart script.
+
+Usage:
+ disconnect
+
+The debugger will disconnect from a dart script's debugging port. The
+script must have been connected to earlier with the 'connect' command.
+""";
+
+ Future run(List<String> cmdArgs) {
+ if (cmdArgs.length > 1) {
+ print("Too many arguments to 'disconnect'.");
+ }
+ if (!isDebugging) {
+ // TODO(turnidge): Implement modal y/n dialog to stop running script.
+ print("There is no active dart process. "
+ "Try 'connect'.");
+ return new Future.value();
+ }
+ if (targetProcess != null) {
+ print("The active dart process was started with 'run'. "
+ "Try 'kill'.");
+ }
+
+ cmdo.hide();
+ return closeVmSocket();
+ }
+}
+
typedef void HandlerType(Map response);
HandlerType showPromptAfter(void handler(Map response)) {
- // Hide the command prompt immediately.
return (response) {
handler(response);
cmdo.show();
};
}
-
void processCommand(String cmdLine) {
void huh() {
- print("'$cmdLine' not understood, try h for help");
+ print("'$cmdLine' not understood, try 'help' for help.");
}
+ cmdo.hide();
seqNum++;
cmdLine = cmdLine.trim();
var args = cmdLine.split(' ');
@@ -137,6 +507,7 @@
return;
}
var command = args[0];
+
var resume_commands =
{ 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
if (resume_commands[command] != null) {
@@ -144,19 +515,16 @@
var cmd = { "id": seqNum,
"command": resume_commands[command],
"params": { "isolateId" : currentIsolate.id } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
} else if (command == "bt") {
var cmd = { "id": seqNum,
"command": "getStackTrace",
"params": { "isolateId" : currentIsolate.id } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
} else if (command == "ll") {
var cmd = { "id": seqNum,
"command": "getLibraries",
"params": { "isolateId" : currentIsolate.id } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
} else if (command == "sbp" && args.length >= 2) {
var url, line;
@@ -173,21 +541,18 @@
"params": { "isolateId" : currentIsolate.id,
"url": url,
"line": line }};
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
} else if (command == "rbp" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "removeBreakpoint",
"params": { "isolateId" : currentIsolate.id,
"breakpointId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
} else if (command == "ls" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getScriptURLs",
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
} else if (command == "eval" && args.length > 3) {
var expr = args.getRange(3, args.length).join(" ");
@@ -207,14 +572,12 @@
"params": { "isolateId": currentIsolate.id,
target: int.parse(args[2]),
"expression": expr } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
} else if (command == "po" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getObjectProperties",
"params": { "isolateId" : currentIsolate.id,
"objectId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
} else if (command == "pl" && args.length >= 3) {
var cmd;
@@ -232,21 +595,18 @@
"index": int.parse(args[2]),
"length": int.parse(args[3]) } };
}
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
} else if (command == "pc" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getClassProperties",
"params": { "isolateId" : currentIsolate.id,
"classId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
} else if (command == "plib" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getLibraryProperties",
"params": {"isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
} else if (command == "slib" && args.length == 3) {
var cmd = { "id": seqNum,
@@ -254,14 +614,12 @@
"params": {"isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]),
"debuggingEnabled": args[2] } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
} else if (command == "pg" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "getGlobalVariables",
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
} else if (command == "gs" && args.length == 3) {
var cmd = { "id": seqNum,
@@ -269,7 +627,6 @@
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]),
"url": args[2] } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
} else if (command == "tok" && args.length == 3) {
var cmd = { "id": seqNum,
@@ -277,18 +634,15 @@
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]),
"url": args[2] } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
} else if (command == "epi" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "setPauseOnException",
"params": { "isolateId" : currentIsolate.id,
"exceptions": args[1] } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
} else if (command == "li") {
var cmd = { "id": seqNum, "command": "getIsolateIds" };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
} else if (command == "sci" && args.length == 2) {
var id = int.parse(args[1]);
@@ -298,22 +652,46 @@
} else {
print("$id is not a valid isolate id");
}
+ cmdo.show();
} else if (command == "i" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "interrupt",
"params": { "isolateId": int.parse(args[1]) } };
- cmdo.hide();
sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command == "q") {
- quitShell();
- } else if (command == "h") {
- printHelp();
- } else {
+ } else if (command.length == 0) {
huh();
+ cmdo.show();
+ } else {
+ // TODO(turnidge): Use this for all commands.
+ var matches = matchCommand(command, true);
+ if (matches.length == 0) {
+ huh();
+ cmdo.show();
+ } else if (matches.length == 1) {
+ matches[0].run(args).then((_) {
+ cmdo.show();
+ });
+ } else {
+ var matchNames = matches.map((handler) => handler.name);
+ print("Ambigous command '$command' : ${matchNames.toList()}");
+ cmdo.show();
+ }
}
}
+void processError(error, trace) {
+ cmdo.hide();
+ print("\nInternal error:\n$error\n$trace");
+ cmdo.show();
+}
+
+
+void processDone() {
+ debuggerQuit();
+}
+
+
String remoteObject(value) {
var kind = value["kind"];
var text = value["text"];
@@ -762,85 +1140,169 @@
// we hardcode the list here.
//
// TODO(turnidge): Implement completion for arguments as well.
- List<String> allCommands = ['q', 'bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
+ List<String> oldCommands = ['bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib',
- 'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i', 'h'];
+ 'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i' ];
// Completion of first word in the command.
if (commandParts.length == 1) {
String prefix = commandParts.last;
- for (String command in allCommands) {
+ for (var command in oldCommands) {
if (command.startsWith(prefix)) {
completions.add(command);
}
- }
+ }
+ for (var command in commandList) {
+ if (command.name.startsWith(prefix)) {
+ completions.add(command.name);
+ }
+ }
}
return completions;
}
-void debuggerMain() {
+Future closeCommando() {
+ var subscription = cmdSubscription;
+ cmdSubscription = null;
+ cmdo = null;
+
+ var future = subscription.cancel();
+ if (future != null) {
+ return future;
+ } else {
+ return new Future.value();
+ }
+}
+
+
+Future openVmSocket(int attempt) {
+ return Socket.connect("127.0.0.1", debugPort).then(
+ setupVmSocket,
+ onError: (e) {
+ // We were unable to connect to the debugger's port. Try again.
+ retryOpenVmSocket(e, attempt);
+ });
+}
+
+
+void setupVmSocket(Socket s) {
+ vmSock = s;
+ vmSock.setOption(SocketOption.TCP_NODELAY, true);
+ var stringStream = vmSock.transform(UTF8.decoder);
outstandingCommands = new Map<int, Completer>();
- Socket.connect("127.0.0.1", 5858).then((s) {
- vmSock = s;
- vmSock.setOption(SocketOption.TCP_NODELAY, true);
- var stringStream = vmSock.transform(UTF8.decoder);
- vmSubscription = stringStream.listen(
- (String data) {
- processVmData(data);
- },
- onDone: () {
+ vmSubscription = stringStream.listen(
+ (String data) {
+ processVmData(data);
+ },
+ onDone: () {
+ cmdo.hide();
+ if (verbose) {
print("VM debugger connection closed");
- quitShell();
- },
- onError: (err) {
- print("Error in debug connection: $err");
- // TODO(floitsch): do we want to print the stack trace?
- quitShell();
- });
- cmdo = new Commando(stdin, stdout, processCommand,
- completer : debuggerCommandCompleter);
- });
+ }
+ closeVmSocket().then((_) {
+ cmdo.show();
+ });
+ },
+ onError: (err) {
+ cmdo.hide();
+ // TODO(floitsch): do we want to print the stack trace?
+ print("Error in debug connection: $err");
+
+ // TODO(turnidge): Kill the debugged process here?
+ closeVmSocket().then((_) {
+ cmdo.show();
+ });
+ });
+}
+
+
+Future retryOpenVmSocket(error, int attempt) {
+ var delay;
+ if (attempt < 10) {
+ delay = new Duration(milliseconds:10);
+ } else if (attempt < 20) {
+ delay = new Duration(seconds:1);
+ } else {
+ // Too many retries. Give up.
+ //
+ // TODO(turnidge): Kill the debugged process here?
+ print('Timed out waiting for debugger to start.\nError: $e');
+ return closeVmSocket();
+ }
+
+ // Wait and retry.
+ return new Future.delayed(delay, () {
+ openVmSocket(attempt + 1);
+ });
+}
+
+
+Future closeVmSocket() {
+ if (vmSubscription == null) {
+ // Already closed, nothing to do.
+ assert(vmSock == null);
+ return new Future.value();
+ }
+
+ isDebugging = false;
+ var subscription = vmSubscription;
+ var sock = vmSock;
+
+ // Wait for the socket to close and the subscription to be
+ // cancelled. Perhaps overkill, but it means we know these will be
+ // done.
+ //
+ // This is uglier than it needs to be since cancel can return null.
+ var cleanupFutures = [sock.close()];
+ var future = subscription.cancel();
+ if (future != null) {
+ cleanupFutures.add(future);
+ }
+
+ vmSubscription = null;
+ vmSock = null;
+ outstandingCommands = null;
+
+ return Future.wait(cleanupFutures);
+}
+
+Future debuggerQuit() {
+ // Kill target process, if any.
+ if (targetProcess != null) {
+ if (!targetProcess.kill()) {
+ print('Unable to kill process ${targetProcess.pid}');
+ }
+ }
+
+ // Restore terminal settings, close connections.
+ return Future.wait([closeCommando(), closeVmSocket()]).then((_) {
+ exit(0);
+
+ // Unreachable.
+ return new Future.value();
+ });
+}
+
+
+void parseArgs(List<String> args) {
+ int pos = 0;
+ settings['vm'] = Platform.executable;
+ while (pos < args.length && args[pos].startsWith('-')) {
+ pos++;
+ }
+ if (pos < args.length) {
+ settings['vmargs'] = args.getRange(0, pos).join(' ');
+ settings['script'] = args[pos];
+ settings['args'] = args.getRange(pos + 1, args.length).join(' ');
+ }
}
void main(List<String> args) {
- if (args.length > 0) {
- if (verbose) {
- args = <String>['--debug', '--verbose_debug']..addAll(args);
- } else {
- args = <String>['--debug']..addAll(args);
- }
- Process.start(Platform.executable, args).then((Process process) {
- targetProcess = process;
- process.stdin.close();
+ parseArgs(args);
- // TODO(turnidge): For now we only show full lines of output
- // from the debugged process. Should show each character.
- process.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter())
- .listen((String line) {
- // Hide/show command prompt across asynchronous output.
- if (cmdo != null) {
- cmdo.hide();
- }
- print("$line");
- if (cmdo != null) {
- cmdo.show();
- }
- });
-
- process.exitCode.then((int exitCode) {
- if (exitCode == 0) {
- print('Program exited normally.');
- } else {
- print('Program exited with code $exitCode.');
- }
- });
-
- debuggerMain();
- });
- } else {
- debuggerMain();
- }
+ cmdo = new Commando(completer: debuggerCommandCompleter);
+ cmdSubscription = cmdo.commands.listen(processCommand,
+ onError: processError,
+ onDone: processDone);
}
diff --git a/tools/ddbg/lib/commando.dart b/tools/ddbg/lib/commando.dart
index cb1fef2..f3ff3ea 100644
--- a/tools/ddbg/lib/commando.dart
+++ b/tools/ddbg/lib/commando.dart
@@ -30,18 +30,45 @@
static const runeSpace = 0x20;
static const runeDEL = 0x7F;
- Commando(this._stdin,
- this._stdout,
- this._handleCommand,
- {this.prompt : '> ', this.completer : null}) {
+ StreamController<String> _commandController;
+
+ Stream get commands => _commandController.stream;
+
+ Commando({consoleIn,
+ consoleOut,
+ this.prompt : '> ',
+ this.completer : null}) {
+ _stdin = (consoleIn != null ? consoleIn : stdin);
+ _stdout = (consoleOut != null ? consoleOut : stdout);
+ _commandController = new StreamController<String>(
+ onCancel: _onCancel);
_stdin.echoMode = false;
_stdin.lineMode = false;
_screenWidth = _term.cols - 1;
_writePrompt();
+ // TODO(turnidge): Handle errors in _stdin here.
_stdinSubscription =
- _stdin.transform(UTF8.decoder).listen(_handleText, onDone:done);
+ _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
}
+ Future _onCancel() {
+ _stdin.echoMode = true;
+ _stdin.lineMode = true;
+ var future = _stdinSubscription.cancel();
+ if (future != null) {
+ return future;
+ } else {
+ return new Future.value();
+ }
+ }
+
+ // Before terminating, call close() to restore terminal settings.
+ void _done() {
+ _onCancel().then((_) {
+ _commandController.close();
+ });
+ }
+
void _handleText(String text) {
try {
if (!_promptShown) {
@@ -79,11 +106,7 @@
}
}
} catch(e, trace) {
- stderr.writeln('\nUnexpected exception: $e');
- stderr.writeln(trace);
- stderr.close().then((_) {
- done();
- });
+ _commandController.addError(e, trace);
}
}
@@ -102,8 +125,8 @@
case runeCtrlD:
if (_currentLine.length == 0) {
// ^D on an empty line means quit.
- _stdout.writeln();
- done();
+ _stdout.writeln("^D");
+ _done();
} else {
_delete();
}
@@ -207,12 +230,6 @@
return (char >= 0x00 && char < 0x20) || (char == 0x7f);
}
- void done() {
- _stdin.echoMode = true;
- _stdin.lineMode = true;
- _stdinSubscription.cancel();
- }
-
void _writePromptAndLine() {
_writePrompt();
var pos = _writeRange(_currentLine, 0, _currentLine.length);
@@ -263,6 +280,8 @@
void _clearScreen() {
_stdout.write(_term.clear);
+ _term.resize();
+ _screenWidth = _term.cols - 1;
_writePromptAndLine();
}
@@ -368,11 +387,10 @@
_stdout.writeln();
// Call the user's command handler.
- _handleCommand(new String.fromCharCodes(_currentLine));
+ _commandController.add(new String.fromCharCodes(_currentLine));
_currentLine = [];
_cursorPos = 0;
- _linePos = _lines.length;
if (_promptShown) {
_writePrompt();
}
@@ -593,7 +611,6 @@
int _nextMargin(int pos) {
var truePos = pos + prompt.length;
- var curLine = _getLine(pos);
return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
}
@@ -610,14 +627,12 @@
Stdin _stdin;
StreamSubscription _stdinSubscription;
IOSink _stdout;
- final _handleCommand;
final String prompt;
bool _promptShown = true;
final CommandCompleter completer;
TermInfo _term = new TermInfo();
- // TODO(turnidge): Update screenwidth when we clear the screen. See
- // if we can get screen resize events too.
+ // TODO(turnidge): See if we can get screen resize events.
int _screenWidth;
List<int> _currentLine = []; // A list of runes.
StringBuffer _bufferedInput = new StringBuffer();
@@ -676,8 +691,11 @@
void _handleCommand(String rawCommand) {
String command = rawCommand.trim();
+ cmdo.hide();
if (command == 'quit') {
- cmdo.done();
+ cmdo.close().then((_) {
+ print('Exiting');
+ });
} else if (command == 'help') {
switch (_helpCount) {
case 0:
@@ -702,11 +720,12 @@
} else {
print('Received command($command)');
}
+ cmdo.show();
}
void main() {
- stdout.writeln('[Commando demo]');
- cmd = new Commando(stdin, stdout, _handleCommand,
- completer:_myCompleter);
+ print('[Commando demo]');
+ cmdo = new Commando(completer:_myCompleter);
+ cmdo.commands.listen(_handleCommand);
}
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index f38bae1..665cd5e 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -113,10 +113,8 @@
var options = JS('=Object', '{prototype: #}', proto);
- if (baseClassName != 'HTMLElement') {
- if (extendsTagName != null) {
- JS('=Object', '#.extends = #', options, extendsTagName);
- }
+ if (extendsTagName != null) {
+ JS('=Object', '#.extends = #', options, extendsTagName);
}
JS('void', '#.register(#, #)', document, tag, options);
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 75c699c..e54cc11 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -409,7 +409,7 @@
throw new UnsupportedError("Invalid custom element from $libName.");
}
var className = MirrorSystem.getName(cls.simpleName);
- var createdConstructor = cls.constructors[new Symbol('$className.created')];
+ var createdConstructor = cls.declarations[new Symbol('$className.created')];
if (createdConstructor == null ||
createdConstructor is! MethodMirror ||
!createdConstructor.isConstructor) {
diff --git a/tools/publish_barback.py b/tools/publish_barback.py
deleted file mode 100755
index 87752b0..0000000
--- a/tools/publish_barback.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-#
-# Script to push the barback package to pub. Barback is treated specially
-# because it is tightly coupled to the SDK. Pub includes its own copy of
-# barback but also includes code that is run against the user's copy of barback.
-# To ensure that those are in sync, each version of the SDK has a single
-# version of barback that it works with.
-#
-# We enforce this by placing a narrow SDK constraint in each version of barback.
-# This ensures the only barback that will be selected is the one that works
-# with the user's SDK. Once barback is more stable, we can loosen this.
-#
-# Usage: publish_barback.py
-#
-# "pub" must be in PATH.
-
-import os
-import os.path
-import shutil
-import sys
-import subprocess
-import tempfile
-
-import utils
-
-def Main(argv):
- HOME = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
- BARBACK = os.path.join(HOME, 'pkg', 'barback')
-
- (channel, major, minor, service, qualifier) = utils.ReadVersionFile()
- major = int(major)
- minor = int(minor)
- service = int(service)
-
- # The bleeding_edge branch has a fixed version number of 0.1.x.y. Don't allow
- # users to publish packages from there.
- if (major == 0 and minor <= 1) or channel == 'be':
- print 'Error: Do not run this script from a bleeding_edge checkout.'
- #return -1
-
- # Convert the version to semver syntax.
- version = '%d.%d.%d+%s' % (major, minor, service, qualifier)
-
- # Copy the package to a temp directory so we can fill in its pubspec.
- tmpDir = tempfile.mkdtemp()
- shutil.copytree(os.path.join(HOME, BARBACK), os.path.join(tmpDir, 'barback'))
-
- pubspecPath = os.path.join(tmpDir, 'barback', 'pubspec.yaml')
- with open(pubspecPath) as pubspecFile:
- pubspec = pubspecFile.read()
-
- # Fill in the SDK version constraint. It pins barback to the current version
- # of the SDK with a small amount of wiggle room for hotfixes.
- constraint = '>=%d.%d.%d <%d.%d.0' % (major, minor, service, major, minor + 1)
-
- # Fill in the SDK version constraint.
- pubspec = pubspec.replace('$SDK_CONSTRAINT$', constraint)
-
- # Give barback a new version that roughly mirrors the SDK, like so:
- # SDK 1.2.3+4 --> barback 0.12.3+4.
- barback_version = 'version: 0.%d.%d+%s # Set by publish_barback.py.' % (
- 10 + minor, service, qualifier)
- pubspec = pubspec.replace(
- 'version: 0.9.0 # Replaced by publish_barback.py. Do not edit.',
- barback_version)
-
- return
-
- with open(pubspecPath, 'w') as pubspecFile:
- pubspecFile.write(pubspec)
-
- print ('Publishing barback %s with SDK constraint "%s".' %
- (version, constraint))
- subprocess.call(['pub', 'lish'], cwd=os.path.join(tmpDir, 'barback'))
- shutil.rmtree(tmpDir)
-
-if __name__ == '__main__':
- sys.exit(Main(sys.argv))
diff --git a/tools/test.dart b/tools/test.dart
index c96084d..b7afb77 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -99,9 +99,12 @@
}
if (!firstConf['append_logs']) {
- var file = new File(TestUtils.flakyFileName());
- if (file.existsSync()) {
- file.deleteSync();
+ var files = [new File(TestUtils.flakyFileName()),
+ new File(TestUtils.testOutcomeFileName())];
+ for (var file in files) {
+ if (file.existsSync()) {
+ file.deleteSync();
+ }
}
}
@@ -240,6 +243,9 @@
eventListener.add(new SkippedCompilationsPrinter());
eventListener.add(new LeftOverTempDirPrinter());
}
+ if (firstConf['write_test_outcome_log']) {
+ eventListener.add(new TestOutcomeLogWriter());
+ }
eventListener.add(new ExitCodeSetter());
void startProcessQueue() {
diff --git a/tools/testing/dart/co19_test.dart b/tools/testing/dart/co19_test.dart
index dc28b47..e793344 100644
--- a/tools/testing/dart/co19_test.dart
+++ b/tools/testing/dart/co19_test.dart
@@ -42,13 +42,14 @@
'--minified'],
const <String>['-mrelease', '-rd8,jsshell', '-cdart2js', '--use-sdk',
'--checked'],
+ const <String>['-mrelease', '-rdartium', '-cnone', '--use-sdk',
+ '--checked'],
+ const <String>['-mrelease', '-rdartium', '-cnone', '--use-sdk'],
];
-void main() {
- Options options = new Options();
- File scriptFile = new File(options.script);
- Path scriptPath =
- new Path(scriptFile.fullPathSync())
+void main(List<String> args) {
+ File scriptFile = new File(new Path(Platform.script.path).toNativePath());
+ Path scriptPath = new Path(scriptFile.absolute.path)
.directoryPath.directoryPath.directoryPath.append('test.dart');
TestUtils.testScriptPath = scriptPath.toNativePath();
var optionsParser = new TestOptionsParser();
@@ -56,7 +57,7 @@
for (var commandLine in COMMAND_LINES) {
List arguments = <String>[];
arguments.addAll(COMMON_ARGUMENTS);
- arguments.addAll(options.arguments);
+ arguments.addAll(args);
arguments.addAll(commandLine);
configurations.addAll(optionsParser.parse(arguments));
}
diff --git a/tools/testing/dart/test_controller.js b/tools/testing/dart/test_controller.js
index 806a7f9..e0ca295 100644
--- a/tools/testing/dart/test_controller.js
+++ b/tools/testing/dart/test_controller.js
@@ -149,6 +149,9 @@
// messages to the window.opener.
var driver = getDriverWindow();
+ recordEvent('debug', 'Sending events to driver page (isFirstMessage = ' +
+ isFirstMessage + ', isStatusUpdate = ' +
+ isStatusUpdate + ', isDone = ' + isDone + ')');
// Post the DOM and all events that happened.
var events = recordedEventList.slice(0);
events.push(buildDomEvent());
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 48f1310..c0af640 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -301,6 +301,15 @@
'bool'
),
new _TestOptionSpecification(
+ 'write_test_outcome_log',
+ 'Write the outcome of all tests executed to a '
+ '"${TestUtils.flakyFileName()}" file.',
+ ['--write-test-outcome-log'],
+ [],
+ false,
+ 'bool'
+ ),
+ new _TestOptionSpecification(
'clear_safari_cache',
'Clear the safari cache (i.e., delete it).',
['--clear_safari_cache'],
@@ -358,7 +367,7 @@
[],
null),
new _TestOptionSpecification(
- 'vm-options',
+ 'vm_options',
'Extra options to send to the vm when running',
['--vm-options'],
[],
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index ea31bfc..1ebc541 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -7,6 +7,7 @@
import "dart:async";
import "dart:io";
import "dart:io" as io;
+import "dart:convert" show JSON;
import "status_file_parser.dart";
import "test_runner.dart";
import "test_suite.dart";
@@ -189,6 +190,91 @@
}
}
+class TestOutcomeLogWriter extends EventListener {
+ /*
+ * The ".test-outcome.log" file contains one line for every executed test.
+ * Such a line is an encoded JSON data structure of the following form:
+ * The durations are double values in milliseconds.
+ *
+ * {
+ * name: 'co19/LibTest/math/x',
+ * configuration: {
+ * mode : 'release',
+ * compiler : 'dart2js',
+ * ....
+ * },
+ * test_result: {
+ * outcome: 'RuntimeError',
+ * expected_outcomes: ['Pass', 'Fail'],
+ * duration: 2600.64,
+ * command_results: [
+ * {
+ * name: 'dart2js',
+ * duration: 2400.44,
+ * },
+ * {
+ * name: 'ff',
+ * duration: 200.2,
+ * },
+ * ],
+ * }
+ * },
+ */
+
+ static final INTERESTED_CONFIGURATION_PARAMETERS =
+ ['mode', 'arch', 'compiler', 'runtime', 'checked', 'host_checked',
+ 'minified', 'csp', 'system', 'vm_options', 'use_sdk'];
+
+ IOSink _sink;
+
+ void done(TestCase test) {
+ var name = test.displayName;
+ var configuration = {};
+ for (var key in INTERESTED_CONFIGURATION_PARAMETERS) {
+ configuration[key] = test.configuration[key];
+ }
+ var outcome = '${test.lastCommandOutput.result(test)}';
+ var expectations =
+ test.expectedOutcomes.map((expectation) => "$expectation").toList();
+
+ var commandResults = [];
+ double totalDuration = 0.0;
+ for (var command in test.commands) {
+ var output = test.commandOutputs[command];
+ if (output != null) {
+ double duration = output.time.inMicroseconds/1000.0;
+ totalDuration += duration;
+ commandResults.add({
+ 'name': command.displayName,
+ 'duration': duration,
+ });
+ }
+ }
+ _writeTestOutcomeRecord({
+ 'name' : name,
+ 'configuration' : configuration,
+ 'test_result' : {
+ 'outcome' : outcome,
+ 'expected_outcomes' : expectations,
+ 'duration' : totalDuration,
+ 'command_results' : commandResults,
+ },
+ });
+ }
+
+ void allDone() {
+ _sink.close();
+ }
+
+ void _writeTestOutcomeRecord(Map record) {
+ if (_sink == null) {
+ _sink = new File(TestUtils.testOutcomeFileName())
+ .openWrite(mode: FileMode.APPEND);
+ }
+ _sink.write("${JSON.encode(record)}\n");
+ }
+}
+
class SummaryPrinter extends EventListener {
void allTestsKnown() {
if (SummaryReport.total > 0) {
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 867d374..9745387 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1782,6 +1782,12 @@
return ".flaky.log";
}
+ static String testOutcomeFileName() {
+ // If test.py was invoked with '--write-test-outcome-log it will write
+ // test outcomes to this file.
+ return ".test-outcome.log";
+ }
+
static void ensureExists(String filename, Map configuration) {
if (!configuration['list'] && !(new File(filename).existsSync())) {
throw "Executable '$filename' does not exist";
@@ -1917,8 +1923,8 @@
*/
static List<String> getExtraVmOptions(Map configuration) {
var extraVmOptions = [];
- if (configuration['vm-options'] != null) {
- extraVmOptions = configuration['vm-options'].split(" ");
+ if (configuration['vm_options'] != null) {
+ extraVmOptions = configuration['vm_options'].split(" ");
extraVmOptions.removeWhere((s) => s.trim() == "");
}
return extraVmOptions;
diff --git a/utils/apidoc/apidoc.gyp b/utils/apidoc/apidoc.gyp
index 7707557..3c41afe 100644
--- a/utils/apidoc/apidoc.gyp
+++ b/utils/apidoc/apidoc.gyp
@@ -91,7 +91,6 @@
'--exclude-lib=dartdoc',
'--exclude-lib=docgen',
'--exclude-lib=expect',
- '--exclude-lib=http',
'--exclude-lib=oauth2',
'--exclude-lib=scheduled_test',
'--exclude-lib=stack_trace',