Version 0.5.10.0 svn merge -r 22870:23017 https://dart.googlecode.com/svn/branches/bleeding_edge trunk git-svn-id: http://dart.googlecode.com/svn/trunk@23028 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart index be1a6ef..3898b9f 100644 --- a/pkg/args/lib/args.dart +++ b/pkg/args/lib/args.dart
@@ -169,17 +169,46 @@ * option passed to the command. You can add a command like so: * * var parser = new ArgParser(); - * var command = parser.addCommand("commit"); + * var command = parser.addCommand('commit'); + * + * It returns another [ArgParser] which you can then use to define options + * specific to that command. If you already have an [ArgParser] for the + * command's options, you can pass it to [addCommand]: + * + * var parser = new ArgParser(); + * var command = new ArgParser(); + * parser.addCommand('commit', command); + * + * The [ArgParser] for a command can then define whatever options or flags: + * * command.addFlag('all', abbr: 'a'); * - * It returns another [ArgParser] which you can use to define options and - * subcommands on that command. When an argument list is parsed, you can then - * determine which command was entered and what options were provided for it. + * You can add multiple commands to the same parser so that a user can select + * one from a range of possible commands. When an argument list is parsed, + * you can then determine which command was entered and what options were + * provided for it. * * var results = parser.parse(['commit', '-a']); * print(results.command.name); // "commit" * print(results.command['a']); // true * + * Options for a command must appear after the command in the argument list. + * For example, given the above parser, "git -a commit" is *not* valid. The + * parser will try to find the right-most command that accepts an option. For + * example: + * + * var parser = new ArgParser(); + * parser.addFlag('all', abbr: 'a'); + * var command = new ArgParser().addCommand('commit'); + * parser.addFlag('all', abbr: 'a'); + * var results = parser.parse(['commit', '-a']); + * print(results.command['a']); // true + * + * Here, both the top-level parser and the "commit" command can accept a "-a" + * (which is probably a bad command line interface, admittedly). In that case, + * when "-a" appears after "commit", it will be applied to that command. If it + * appears to the left of "commit", it will be given to the top-level parser. + * * ## Displaying usage ## * * This library can also be used to automatically generate nice usage help @@ -248,19 +277,21 @@ ArgParser(); /** - * Defines a command. A command is a named argument which may in turn - * define its own options and subcommands. Returns an [ArgParser] that can - * be used to define the command's options. + * Defines a command. + * + * A command is a named argument which may in turn define its own options and + * subcommands using the given parser. If [parser] is omitted, implicitly + * creates a new one. Returns the parser for the command. */ - ArgParser addCommand(String name) { + ArgParser addCommand(String name, [ArgParser parser]) { // Make sure the name isn't in use. if (commands.containsKey(name)) { throw new ArgumentError('Duplicate command "$name".'); } - var command = new ArgParser(); - commands[name] = command; - return command; + if (parser == null) parser = new ArgParser(); + commands[name] = parser; + return parser; } /**
diff --git a/pkg/args/test/command_test.dart b/pkg/args/test/command_test.dart index 5079425..6115ab1 100644 --- a/pkg/args/test/command_test.dart +++ b/pkg/args/test/command_test.dart
@@ -9,6 +9,21 @@ main() { group('ArgParser.addCommand()', () { + test('creates a new ArgParser if none is given', () { + var parser = new ArgParser(); + var command = parser.addCommand('install'); + expect(parser.commands['install'], equals(command)); + expect(command is ArgParser, isTrue); + }); + + test('uses the command parser if given one', () { + var parser = new ArgParser(); + var command = new ArgParser(); + var result = parser.addCommand('install', command); + expect(parser.commands['install'], equals(command)); + expect(result, equals(command)); + }); + test('throws on a duplicate command name', () { var parser = new ArgParser(); parser.addCommand('install');
diff --git a/pkg/pkg.status b/pkg/pkg.status index 6f9e10e..e4229f4 100644 --- a/pkg/pkg.status +++ b/pkg/pkg.status
@@ -126,6 +126,17 @@ unittest/test/mock_test: Fail unittest/test/mock_regexp_negative_test: Fail +# The unminified unittest tests test that the real names of Dart types are +# printed. Minified versions of these tests exist that test the behavior when +# minified. +unittest/test/*_unminified_test: Skip + +[ $minified == false ] +# The minified unittest tests test that the minified names of Dart types are +# printed. Unminified versions of these tests exist that test the behavior when +# not minified. +unittest/test/*_minified_test: Skip + [ $compiler == none && $runtime == drt ] dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
diff --git a/pkg/scheduled_test/test/descriptor/file_test.dart b/pkg/scheduled_test/test/descriptor/file_test.dart index 5b64577..958f431 100644 --- a/pkg/scheduled_test/test/descriptor/file_test.dart +++ b/pkg/scheduled_test/test/descriptor/file_test.dart
@@ -229,7 +229,7 @@ test('test 2', () { expect(errors, everyElement(new isInstanceOf<ScheduleError>())); expect(errors.map((e) => e.error.message), equals([ - "Expected: contains 'baaz'\n but: was 'barfoobaz'.\n" + "Expected: contains 'baaz'\n But: was 'barfoobaz'.\n" ]), verbose: true); }); }, passing: ['test 2']); @@ -270,7 +270,7 @@ expect(errors, everyElement(new isInstanceOf<ScheduleError>())); expect(errors.map((e) => e.error.message), equals([ "Expected: contains <12>\n" - " but: was <[98, 97, 114, 102, 111, 111, 98, 97, 122]>.\n" + " But: was [98, 97, 114, 102, 111, 111, 98, 97, 122].\n" ]), verbose: true); }); }, passing: ['test 2']);
diff --git a/pkg/unittest/lib/matcher.dart b/pkg/unittest/lib/matcher.dart index fd6412e..1bdb226 100644 --- a/pkg/unittest/lib/matcher.dart +++ b/pkg/unittest/lib/matcher.dart
@@ -29,6 +29,9 @@ import 'dart:async'; +import 'src/pretty_print.dart'; +import 'src/utils.dart'; + part 'src/basematcher.dart'; part 'src/iterable_matchers.dart'; part 'src/core_matchers.dart';
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart index 980e7a0..1c8d2f6 100644 --- a/pkg/unittest/lib/src/core_matchers.dart +++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -173,26 +173,14 @@ } } else { reason = new StringDescription(); - var eType = typeName(expected); - var aType = typeName(actual); - var includeTypes = eType != aType; // If we have recursed, show the expected value too; if not, // expect() will show it for us. if (depth > 0) { reason.add('expected '); - if (includeTypes) { - reason.add(eType).add(':'); - } reason.addDescriptionOf(expected).add(' but '); } reason.add('was '); - if (includeTypes) { - reason.add(aType).add(':'); - } reason.addDescriptionOf(actual); - if (includeTypes && depth == 0) { - reason.add(' (not type ').add(eType).add(')'); - } } } if (reason != null && location.length > 0) { @@ -201,17 +189,6 @@ return reason; } - String typeName(x) { - // dart2js blows up on some objects (e.g. window.navigator). - // So we play safe here. - try { - if (x == null) return "null"; - return x.runtimeType.toString(); - } catch (e) { - return "Unknown"; - } - } - String _match(expected, actual) { Description reason = _recursiveMatch(expected, actual, '', 0); return reason == null ? null : reason.toString(); @@ -583,17 +560,16 @@ Description describeMismatch(item, Description mismatchDescription, MatchState matchState, bool verbose) { - super.describeMismatch(item, mismatchDescription, matchState, verbose); try { // We want to generate a different description if there is no length // property. This is harmless code that will throw if no length property // but subtle enough that an optimizer shouldn't strip it out. if (item.length * item.length >= 0) { - return mismatchDescription.add(' with length of '). + return mismatchDescription.add('had length of '). addDescriptionOf(item.length); } } catch (e) { - return mismatchDescription.add(' has no length property'); + return mismatchDescription.add('had no length property'); } } }
diff --git a/pkg/unittest/lib/src/description.dart b/pkg/unittest/lib/src/description.dart index cdd8193..cde5243 100644 --- a/pkg/unittest/lib/src/description.dart +++ b/pkg/unittest/lib/src/description.dart
@@ -41,23 +41,8 @@ Description addDescriptionOf(value) { if (value is Matcher) { value.describe(this); - } else if (value is String) { - _addEscapedString(value); } else { - String description = (value == null) ? "null" : value.toString(); - if (description.startsWith('<') && description.endsWith('>')) { - add(description); - } else if (description.startsWith("Instance of")) { - add('<'); - add(description); - add(':'); - add(value.hashCode.toString()); - add('>'); - } else { - add('<'); - add(description); - add('>'); - } + add(prettyPrint(value, maxLineLength: 80, maxItems: 25)); } return this; } @@ -85,23 +70,7 @@ /** Escape the control characters in [string] so that they are visible. */ _addEscapedString(String string) { add("'"); - for (var i = 0; i < string.length; i++) { - add(_escape(string[i])); - } + add(escapeString(string)); add("'"); } - - /** Return the escaped form of a character [ch]. */ - _escape(ch) { - if (ch == "'") - return "\'"; - else if (ch == '\n') - return '\\n'; - else if (ch == '\r') - return '\\r'; - else if (ch == '\t') - return '\\t'; - else - return ch; - } }
diff --git a/pkg/unittest/lib/src/expect.dart b/pkg/unittest/lib/src/expect.dart index 3542f7a..f10309d 100644 --- a/pkg/unittest/lib/src/expect.dart +++ b/pkg/unittest/lib/src/expect.dart
@@ -137,28 +137,15 @@ String _defaultErrorFormatter(actual, Matcher matcher, String reason, MatchState matchState, bool verbose) { var description = new StringDescription(); - description.add('Expected: ').addDescriptionOf(matcher). - add('\n but: '); - matcher.describeMismatch(actual, description, matchState, verbose); - description.add('.\n'); - if (verbose) { - if (actual is Iterable) { - description.add('Actual: ').addDescriptionOf(actual).add('\n'); - } else if (actual is Map) { - description.add('Actual: '); - var count = 25; - for (var k in actual.keys) { - if (count == 0) { - description.add('...\n'); - break; - } - description.addDescriptionOf(k); - description.add(' : '); - description.addDescriptionOf(actual[k]); - description.add('\n'); - --count; - } - } + description.add('Expected: ').addDescriptionOf(matcher).add('\n'); + + var mismatchDescription = new StringDescription(); + matcher.describeMismatch(actual, mismatchDescription, matchState, verbose); + description.add(' But: ') + .add(mismatchDescription.toString()).add('.\n'); + + if (!mismatchDescription.toString().startsWith("was ")) { + description.add('Actual: ').addDescriptionOf(actual); } if (reason != null) { description.add(reason).add('\n');
diff --git a/pkg/unittest/lib/src/iterable_matchers.dart b/pkg/unittest/lib/src/iterable_matchers.dart index acf41d0..65bc610 100644 --- a/pkg/unittest/lib/src/iterable_matchers.dart +++ b/pkg/unittest/lib/src/iterable_matchers.dart
@@ -42,8 +42,9 @@ if (matchState.state != null) { var index = matchState.state['index']; var element = matchState.state['element']; + mismatchDescription.add('position $index '); return _matcher.describeMismatch(element, mismatchDescription, - matchState.state['state'], verbose).add(' at position $index'); + matchState.state['state'], verbose); } return super.describeMismatch(item, mismatchDescription, matchState, verbose);
diff --git a/pkg/unittest/lib/src/map_matchers.dart b/pkg/unittest/lib/src/map_matchers.dart index eccc4ec..72984f9 100644 --- a/pkg/unittest/lib/src/map_matchers.dart +++ b/pkg/unittest/lib/src/map_matchers.dart
@@ -44,8 +44,8 @@ Description describeMismatch(item, Description mismatchDescription, MatchState matchState, bool verbose) { if (!item.containsKey(_key)) { - return mismatchDescription.addDescriptionOf(item). - add(" doesn't contain key ").addDescriptionOf(_key); + return mismatchDescription.add(" doesn't contain key ") + .addDescriptionOf(_key); } else { mismatchDescription.add(' contains key ').addDescriptionOf(_key). add(' but with value ');
diff --git a/pkg/unittest/lib/src/numeric_matchers.dart b/pkg/unittest/lib/src/numeric_matchers.dart index e5dd7ef..84afb49 100644 --- a/pkg/unittest/lib/src/numeric_matchers.dart +++ b/pkg/unittest/lib/src/numeric_matchers.dart
@@ -150,14 +150,11 @@ Description describeMismatch(item, Description mismatchDescription, MatchState matchState, bool verbose) { if (item is !num) { - return mismatchDescription. - addDescriptionOf(item). - add(' not numeric'); + return mismatchDescription.add(' not numeric'); } else { var diff = item - _value; if (diff < 0) diff = -diff; return mismatchDescription. - addDescriptionOf(item). add(' differed by '). addDescriptionOf(diff); }
diff --git a/pkg/unittest/lib/src/operator_matchers.dart b/pkg/unittest/lib/src/operator_matchers.dart index d5142be..c7421b7 100644 --- a/pkg/unittest/lib/src/operator_matchers.dart +++ b/pkg/unittest/lib/src/operator_matchers.dart
@@ -94,9 +94,9 @@ Description describeMismatch(item, Description mismatchDescription, MatchState matchState, bool verbose) { var matcher = matchState.state['matcher']; - mismatchDescription.addDescriptionOf(matcher).add(' '); - matcher.describeMismatch(item, mismatchDescription, - matchState.state['state'], verbose); + matcher.describeMismatch(item, mismatchDescription, + matchState.state['state'], verbose); + mismatchDescription.add(" (wasn't ").addDescriptionOf(matcher).add(')'); return mismatchDescription; }
diff --git a/pkg/unittest/lib/src/pretty_print.dart b/pkg/unittest/lib/src/pretty_print.dart new file mode 100644 index 0000000..1608e10 --- /dev/null +++ b/pkg/unittest/lib/src/pretty_print.dart
@@ -0,0 +1,102 @@ +// 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 pretty_print; + +import 'utils.dart'; + +/** + * Returns a pretty-printed representation of [object]. + * + * If [maxLineLength] is passed, this will attempt to ensure that each line is + * no longer than [maxLineLength] characters long. This isn't guaranteed, since + * individual objects may have string representations that are too long, but + * most lines will be less than [maxLineLength] long. + * + * If [maxItems] is passed, [Iterable]s and [Map]s will only print their first + * [maxItems] members or key/value pairs, respectively. + */ +String prettyPrint(object, {int maxLineLength, int maxItems}) { + String _prettyPrint(object, int indent, Set seen, bool top) { + // Avoid looping infinitely on recursively-nested data structures. + if (seen.contains(object)) return "(recursive)"; + seen = seen.union(new Set.from([object])); + String pp(child) => _prettyPrint(child, indent + 2, seen, false); + + if (object is Iterable) { + // Print the type name for non-List iterables. + var type = object is List ? "" : typeName(object) + ":"; + + // Truncate the list of strings if it's longer than [maxItems]. + var strings = object.map(pp).toList(); + if (maxItems != null && strings.length > maxItems) { + strings.replaceRange(maxItems - 1, strings.length, ['...']); + } + + // If the printed string is short and doesn't contain a newline, print it + // as a single line. + var singleLine = "$type[${strings.join(', ')}]"; + if ((maxLineLength == null || + singleLine.length + indent <= maxLineLength) && + !singleLine.contains("\n")) { + return singleLine; + } + + // Otherwise, print each member on its own line. + return "$type[\n" + strings.map((string) { + return _indent(indent + 2) + string; + }).join(",\n") + "\n" + _indent(indent) + "]"; + } else if (object is Map) { + // Convert the contents of the map to string representations. + var strings = object.keys.map((key) { + return '${pp(key)}: ${pp(object[key])}'; + }).toList(); + + // Truncate the list of strings if it's longer than [maxItems]. + if (maxItems != null && strings.length > maxItems) { + strings.replaceRange(maxItems - 1, strings.length, ['...']); + } + + // If the printed string is short and doesn't contain a newline, print it + // as a single line. + var singleLine = "{${strings.join(", ")}}"; + if ((maxLineLength == null || + singleLine.length + indent <= maxLineLength) && + !singleLine.contains("\n")) { + return singleLine; + } + + // Otherwise, print each key/value pair on its own line. + return "{\n" + strings.map((string) { + return _indent(indent + 2) + string; + }).join(",\n") + "\n" + _indent(indent) + "}"; + } else if (object is String) { + // Escape strings and print each line on its own line. + var lines = object.split("\n"); + return "'" + lines.map(escapeString) + .join("\\n'\n${_indent(indent + 2)}'") + "'"; + } else { + var value = object.toString().replaceAll("\n", _indent(indent) + "\n"); + var defaultToString = value.startsWith("Instance of "); + + // If this is the top-level call to [prettyPrint], wrap the value on angle + // brackets to set it apart visually. + if (top) value = "<$value>"; + + // Print the type of objects with custom [toString] methods. Primitive + // objects and objects that don't implement a custom [toString] don't need + // to have their types printed. + if (object is num || object is bool || object is Function || + object == null || defaultToString) { + return value; + } else { + return "${typeName(object)}:$value"; + } + } + } + + return _prettyPrint(object, 0, new Set(), true); +} + +String _indent(int length) => new List.filled(length, ' ').join('');
diff --git a/pkg/unittest/lib/src/utils.dart b/pkg/unittest/lib/src/utils.dart new file mode 100644 index 0000000..6442ac4 --- /dev/null +++ b/pkg/unittest/lib/src/utils.dart
@@ -0,0 +1,48 @@ +// 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 utils; + +/** + * Returns the name of the type of [x], or "Unknown" if the type name can't be + * determined. + */ +String typeName(x) { + // dart2js blows up on some objects (e.g. window.navigator). + // So we play safe here. + try { + if (x == null) return "null"; + var type = x.runtimeType.toString(); + // TODO(nweiz): if the object's type is private, find a public superclass to + // display once there's a portable API to do that. + return type.startsWith("_") ? "?" : type; + } catch (e) { + return "?"; + } +} + +/** + * Returns [source] with any control characters replaced by their escape + * sequences. + * + * This doesn't add quotes to the string, but it does escape single quote + * characters so that single quotes can be applied externally. + */ +String escapeString(String source) => + source.split("").map(_escapeChar).join(""); + +/** Return the escaped form of a character [ch]. */ +String _escapeChar(String ch) { + if (ch == "'") + return "\\'"; + else if (ch == '\n') + return '\\n'; + else if (ch == '\r') + return '\\r'; + else if (ch == '\t') + return '\\t'; + else + return ch; +} +
diff --git a/pkg/unittest/test/instance_test.dart b/pkg/unittest/test/instance_test.dart index deb1c21..bda0561 100644 --- a/pkg/unittest/test/instance_test.dart +++ b/pkg/unittest/test/instance_test.dart
@@ -5,9 +5,7 @@ library unittestTests; import 'package:unittest/unittest.dart'; -part 'test_utils.dart'; - -doesThrow() { throw 'X'; } +import 'test_utils.dart'; main() { initUtils(); @@ -15,15 +13,17 @@ group('Type Matchers', () { test('isInstanceOf', () { shouldFail(0, new isInstanceOf<String>('String'), - "Expected: an instance of String but: was <0>."); + "Expected: an instance of String But: was <0>."); shouldPass('cow', new isInstanceOf<String>('String')); }); test('throwsA', () { shouldPass(doesThrow, throwsA(equals('X'))); shouldFail(doesThrow, throwsA(equals('Y')), - "Expected: throws an exception which matches 'Y' " - "but: exception 'X' does not match 'Y'."); + "Expected: throws an exception which matches 'Y' " + "But: exception 'X' does not match 'Y'. " + "Actual: <Closure: (dynamic) => dynamic " + "from Function 'doesThrow': static.>"); }); }); }
diff --git a/pkg/unittest/test/matchers_minified_test.dart b/pkg/unittest/test/matchers_minified_test.dart new file mode 100644 index 0000000..3fb875d --- /dev/null +++ b/pkg/unittest/test/matchers_minified_test.dart
@@ -0,0 +1,140 @@ +// 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 is for matcher tests that rely on the names of various Dart types. +// These tests normally fail when run in minified dart2js, since the names will +// be mangled. This version of the file is modified to expect minified names. + +import 'package:unittest/unittest.dart'; + +import 'test_common.dart'; +import 'test_utils.dart'; + +// A regexp fragment matching a minified name. +final _minifiedName = r"[A-Za-z0-9]{1,3}"; + +void main() { + initUtils(); + + group('Core matchers', () { + test('throwsFormatException', () { + shouldPass(() { throw new FormatException(''); }, + throwsFormatException); + shouldFail(() { throw new Exception(); }, + throwsFormatException, + matches( + r"Expected: throws an exception which matches FormatException +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match FormatException\." + r"Actual: <Closure>")); + }); + + test('throwsArgumentError', () { + shouldPass(() { throw new ArgumentError(''); }, + throwsArgumentError); + shouldFail(() { throw new Exception(); }, + throwsArgumentError, + matches( + r"Expected: throws an exception which matches ArgumentError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match ArgumentError\." + r"Actual: <Closure>")); + }); + + test('throwsRangeError', () { + shouldPass(() { throw new RangeError(0); }, + throwsRangeError); + shouldFail(() { throw new Exception(); }, + throwsRangeError, + matches( + r"Expected: throws an exception which matches RangeError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match RangeError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsNoSuchMethodError', () { + shouldPass(() { throw new NoSuchMethodError(null, '', null, null); }, + throwsNoSuchMethodError); + shouldFail(() { throw new Exception(); }, + throwsNoSuchMethodError, + matches( + r"Expected: throws an exception which matches NoSuchMethodError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match NoSuchMethodError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsUnimplementedError', () { + shouldPass(() { throw new UnimplementedError(''); }, + throwsUnimplementedError); + shouldFail(() { throw new Exception(); }, + throwsUnimplementedError, + matches( + r"Expected: throws an exception which matches " + r"UnimplementedError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match UnimplementedError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsUnsupportedError', () { + shouldPass(() { throw new UnsupportedError(''); }, + throwsUnsupportedError); + shouldFail(() { throw new Exception(); }, + throwsUnsupportedError, + matches( + r"Expected: throws an exception which matches UnsupportedError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match UnsupportedError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsStateError', () { + shouldPass(() { throw new StateError(''); }, + throwsStateError); + shouldFail(() { throw new Exception(); }, + throwsStateError, + matches( + r"Expected: throws an exception which matches StateError +" + r"But: exception " + _minifiedName + r":<Exception> " + r"does not match StateError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + }); + + group('Iterable Matchers', () { + test('isEmpty', () { + var d = new SimpleIterable(0); + var e = new SimpleIterable(1); + shouldPass(d, isEmpty); + shouldFail(e, isEmpty, + matches(r"Expected: empty +But: was " + _minifiedName + r":\[1\]\.")); + }); + + test('contains', () { + var d = new SimpleIterable(3); + shouldPass(d, contains(2)); + shouldFail(d, contains(5), + matches( + r"Expected: contains <5> +" + r"But: was " + _minifiedName + r":\[3, 2, 1\]\.")); + }); + }); + + group('Feature Matchers', () { + test("Feature Matcher", () { + var w = new Widget(); + w.price = 10; + shouldPass(w, new HasPrice(10)); + shouldPass(w, new HasPrice(greaterThan(0))); + shouldFail(w, new HasPrice(greaterThan(10)), + matches( + r"Expected: Widget with a price that is a value greater than " + r"<10> +" + r"But: price was <10>\." + r"Actual: <Instance of '" + _minifiedName + r"'>")); + }); + }); +}
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart index 10592da..4e53e16 100644 --- a/pkg/unittest/test/matchers_test.dart +++ b/pkg/unittest/test/matchers_test.dart
@@ -2,77 +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. -library unittestTests; -import 'package:unittest/unittest.dart'; import 'dart:async'; import 'dart:collection'; -part 'test_utils.dart'; -doesNotThrow() {} -doesThrow() { throw 'X'; } +import 'package:unittest/unittest.dart'; -class PrefixMatcher extends BaseMatcher { - final String _prefix; - const PrefixMatcher(this._prefix); - bool matches(item, MatchState matchState) { - return item is String && - (collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix)); - } - - Description describe(Description description) => - description.add('a string starting with '). - addDescriptionOf(collapseWhitespace(_prefix)). - add(' ignoring whitespace'); -} - -class Widget { - int price; -} - -class HasPrice extends CustomMatcher { - HasPrice(matcher) : - super("Widget with a price that is", "price", matcher); - featureValueOf(actual) => actual.price; -} - -class SimpleIterable extends IterableBase { - int count; - SimpleIterable(this.count); - - bool contains(int val) => count < val ? false : true; - - bool any(bool f(element)) { - for(var i = 0; i <= count; i++) { - if(f(i)) return true; - } - return false; - } - - String toString() => "<[$count]>"; - - Iterator get iterator { - return new SimpleIterator(count); - } -} - -class SimpleIterator implements Iterator { - int _count; - int _current; - - SimpleIterator(this._count); - - bool moveNext() { - if (_count > 0) { - _current = _count; - _count--; - return true; - } - _current = null; - return false; - } - - get current => _current; -} +import 'test_common.dart'; +import 'test_utils.dart'; void main() { @@ -84,30 +20,30 @@ test('isTrue', () { shouldPass(true, isTrue); - shouldFail(false, isTrue, "Expected: true but: was <false>."); + shouldFail(false, isTrue, "Expected: true But: was <false>."); }); test('isFalse', () { shouldPass(false, isFalse); - shouldFail(10, isFalse, "Expected: false but: was <10>."); - shouldFail(true, isFalse, "Expected: false but: was <true>."); + shouldFail(10, isFalse, "Expected: false But: was <10>."); + shouldFail(true, isFalse, "Expected: false But: was <true>."); }); test('isNull', () { shouldPass(null, isNull); - shouldFail(false, isNull, "Expected: null but: was <false>."); + shouldFail(false, isNull, "Expected: null But: was <false>."); }); test('isNotNull', () { shouldPass(false, isNotNull); - shouldFail(null, isNotNull, "Expected: not null but: was <null>."); + shouldFail(null, isNotNull, "Expected: not null But: was <null>."); }); test('same', () { var a = new Map(); var b = new Map(); shouldPass(a, same(a)); - shouldFail(b, same(a), "Expected: same instance as <{}> but: was <{}>."); + shouldFail(b, same(a), "Expected: same instance as {} But: was {}."); }); test('equals', () { @@ -122,96 +58,38 @@ shouldPass(0, anything); shouldPass(null, anything); shouldPass(a, anything); - shouldFail(a, isNot(anything), "Expected: not anything but: was <{}>."); + shouldFail(a, isNot(anything), "Expected: not anything But: was {}."); }); test('throws', () { shouldFail(doesNotThrow, throws, - "Expected: throws an exception but: no exception."); + matches( + r"Expected: throws an exception +But: no exception\." + r"Actual: <Closure(: \(dynamic\) => dynamic " + r"from Function 'doesNotThrow': static\.)?>")); shouldPass(doesThrow, throws); shouldFail(true, throws, - "Expected: throws an exception but: not a Function or Future."); + "Expected: throws an exception But: not a Function or Future. " + "Actual: <true>"); }); test('throwsA', () { shouldPass(doesThrow, throwsA(equals('X'))); shouldFail(doesThrow, throwsA(equals('Y')), - "Expected: throws an exception which matches 'Y' " - "but: exception 'X' does not match 'Y'."); - }); - - test('throwsFormatException', () { - shouldPass(() { throw new FormatException(''); }, - throwsFormatException); - shouldFail(() { throw new Exception(); }, - throwsFormatException, - "Expected: throws an exception which matches FormatException " - "but: exception <Exception> does not match FormatException."); - }); - - test('throwsArgumentError', () { - shouldPass(() { throw new ArgumentError(''); }, - throwsArgumentError); - shouldFail(() { throw new Exception(); }, - throwsArgumentError, - "Expected: throws an exception which matches ArgumentError " - "but: exception <Exception> does not match " - "ArgumentError."); - }); - - test('throwsRangeError', () { - shouldPass(() { throw new RangeError(0); }, - throwsRangeError); - shouldFail(() { throw new Exception(); }, - throwsRangeError, - "Expected: throws an exception which matches RangeError " - "but: exception <Exception> does not match RangeError."); - }); - - test('throwsNoSuchMethodError', () { - shouldPass(() { throw new NoSuchMethodError(null, '', null, null); }, - throwsNoSuchMethodError); - shouldFail(() { throw new Exception(); }, - throwsNoSuchMethodError, - "Expected: throws an exception which matches NoSuchMethodError " - "but: exception <Exception> does not match " - "NoSuchMethodError."); - }); - - test('throwsUnimplementedError', () { - shouldPass(() { throw new UnimplementedError(''); }, - throwsUnimplementedError); - shouldFail(() { throw new Exception(); }, - throwsUnimplementedError, - "Expected: throws an exception which matches UnimplementedError " - "but: exception <Exception> does not match " - "UnimplementedError."); - }); - - test('throwsUnsupportedError', () { - shouldPass(() { throw new UnsupportedError(''); }, - throwsUnsupportedError); - shouldFail(() { throw new Exception(); }, - throwsUnsupportedError, - "Expected: throws an exception which matches UnsupportedError " - "but: exception <Exception> does not match " - "UnsupportedError."); - }); - - test('throwsStateError', () { - shouldPass(() { throw new StateError(''); }, - throwsStateError); - shouldFail(() { throw new Exception(); }, - throwsStateError, - "Expected: throws an exception which matches StateError " - "but: exception <Exception> does not match " - "StateError."); + matches( + r"Expected: throws an exception which matches 'Y' +" + r"But: exception 'X' does not match 'Y'\." + r"Actual: <Closure(: \(dynamic\) => dynamic " + r"from Function 'doesThrow': static\.)?>")); }); test('returnsNormally', () { shouldPass(doesNotThrow, returnsNormally); shouldFail(doesThrow, returnsNormally, - "Expected: return normally but: threw 'X'."); + matches( + r"Expected: return normally +But: threw 'X'\." + r"Actual: <Closure(: \(dynamic\) => dynamic " + r"from Function 'doesThrow': static\.)?>")); }); test('hasLength', () { @@ -221,41 +99,44 @@ shouldPass(b, hasLength(0)); shouldPass('a', hasLength(1)); shouldFail(0, hasLength(0), new PrefixMatcher( - "Expected: an object with length of <0> " - "but: was <0> has no length property.")); + "Expected: an object with length of <0> " + "But: had no length property." + "Actual: <0>")); b.add(0); shouldPass(b, hasLength(1)); shouldFail(b, hasLength(2), - "Expected: an object with length of <2> " - "but: was <[0]> with length of <1>."); + "Expected: an object with length of <2> " + "But: had length of <1>. " + "Actual: [0]"); b.add(0); shouldFail(b, hasLength(1), - "Expected: an object with length of <1> " - "but: was <[0, 0]> with length of <2>."); + "Expected: an object with length of <1> " + "But: had length of <2>. " + "Actual: [0, 0]"); shouldPass(b, hasLength(2)); }); test('scalar type mismatch', () { shouldFail('error', equals(5.1), - matches("^Expected: <5\.1>" - " but: was .*:'error' \\(not type .*\\)\.\$")); + "Expected: <5.1> " + "But: was 'error'."); }); test('nested type mismatch', () { shouldFail(['error'], equals([5.1]), - matches(r"^Expected: <\[5\.1\]>" - " but: expected double:<5\.1> " - "but was .*:'error' mismatch at position 0\.\$")); + "Expected: [5.1] " + "But: expected <5.1> but was 'error' mismatch at position 0. " + "Actual: ['error']"); }); test('doubly-nested type mismatch', () { shouldFail([['error']], equals([[5.1]]), - matches(r"^Expected: <\[\[5\.1\]\]>" - " but: expected double:<5\.1> " - "but was .*:'error' mismatch at position 0 " - "mismatch at position 0\.\$")); + "Expected: [[5.1]] " + "But: expected <5.1> but was 'error' " + "mismatch at position 0 mismatch at position 0. " + "Actual: [['error']]"); }); }); @@ -264,64 +145,64 @@ test('greaterThan', () { shouldPass(10, greaterThan(9)); shouldFail(9, greaterThan(10), - "Expected: a value greater than <10> but: was <9>."); + "Expected: a value greater than <10> But: was <9>."); }); test('greaterThanOrEqualTo', () { shouldPass(10, greaterThanOrEqualTo(10)); shouldFail(9, greaterThanOrEqualTo(10), - "Expected: a value greater than or equal to <10> but: was <9>."); + "Expected: a value greater than or equal to <10> But: was <9>."); }); test('lessThan', () { shouldFail(10, lessThan(9), "Expected: a value less than <9> " - "but: was <10>."); + "But: was <10>."); shouldPass(9, lessThan(10)); }); test('lessThanOrEqualTo', () { shouldPass(10, lessThanOrEqualTo(10)); shouldFail(11, lessThanOrEqualTo(10), - "Expected: a value less than or equal to <10> but: was <11>."); + "Expected: a value less than or equal to <10> But: was <11>."); }); test('isZero', () { shouldPass(0, isZero); - shouldFail(1, isZero, "Expected: a value equal to <0> but: was <1>."); + shouldFail(1, isZero, "Expected: a value equal to <0> But: was <1>."); }); test('isNonZero', () { shouldFail(0, isNonZero, "Expected: a value not equal to <0> " - "but: was <0>."); + "But: was <0>."); shouldPass(1, isNonZero); }); test('isPositive', () { shouldFail(-1, isPositive, "Expected: a positive value " - "but: was <-1>."); + "But: was <-1>."); shouldFail(0, isPositive, "Expected: a positive value " - "but: was <0>."); + "But: was <0>."); shouldPass(1, isPositive); }); test('isNegative', () { shouldPass(-1, isNegative); shouldFail(0, isNegative, - "Expected: a negative value but: was <0>."); + "Expected: a negative value But: was <0>."); }); test('isNonPositive', () { shouldPass(-1, isNonPositive); shouldPass(0, isNonPositive); shouldFail(1, isNonPositive, - "Expected: a non-positive value but: was <1>."); + "Expected: a non-positive value But: was <1>."); }); test('isNonNegative', () { shouldPass(1, isNonNegative); shouldPass(0, isNonNegative); shouldFail(-1, isNonNegative, - "Expected: a non-negative value but: was <-1>."); + "Expected: a non-negative value But: was <-1>."); }); test('closeTo', () { @@ -330,38 +211,40 @@ shouldPass(1, closeTo(0, 1)); shouldFail(1.001, closeTo(0, 1), "Expected: a numeric value within <1> of <0> " - "but: <1.001> differed by <1.001>."); + "But: differed by <1.001>. " + "Actual: <1.001>"); shouldFail(-1.001, closeTo(0, 1), "Expected: a numeric value within <1> of <0> " - "but: <-1.001> differed by <1.001>."); + "But: differed by <1.001>. " + "Actual: <-1.001>"); }); test('inInclusiveRange', () { shouldFail(-1, inInclusiveRange(0,2), "Expected: be in range from 0 (inclusive) to 2 (inclusive) " - "but: was <-1>."); + "But: was <-1>."); shouldPass(0, inInclusiveRange(0,2)); shouldPass(1, inInclusiveRange(0,2)); shouldPass(2, inInclusiveRange(0,2)); shouldFail(3, inInclusiveRange(0,2), "Expected: be in range from 0 (inclusive) to 2 (inclusive) " - "but: was <3>."); + "But: was <3>."); }); test('inExclusiveRange', () { shouldFail(0, inExclusiveRange(0,2), "Expected: be in range from 0 (exclusive) to 2 (exclusive) " - "but: was <0>."); + "But: was <0>."); shouldPass(1, inExclusiveRange(0,2)); shouldFail(2, inExclusiveRange(0,2), "Expected: be in range from 0 (exclusive) to 2 (exclusive) " - "but: was <2>."); + "But: was <2>."); }); test('inOpenClosedRange', () { shouldFail(0, inOpenClosedRange(0,2), "Expected: be in range from 0 (exclusive) to 2 (inclusive) " - "but: was <0>."); + "But: was <0>."); shouldPass(1, inOpenClosedRange(0,2)); shouldPass(2, inOpenClosedRange(0,2)); }); @@ -371,7 +254,7 @@ shouldPass(1, inClosedOpenRange(0,2)); shouldFail(2, inClosedOpenRange(0,2), "Expected: be in range from 0 (inclusive) to 2 (exclusive) " - "but: was <2>."); + "But: was <2>."); }); }); @@ -380,22 +263,22 @@ test('isEmpty', () { shouldPass('', isEmpty); shouldFail(null, isEmpty, - "Expected: empty but: was <null>."); + "Expected: empty But: was <null>."); shouldFail(0, isEmpty, - "Expected: empty but: was <0>."); - shouldFail('a', isEmpty, "Expected: empty but: was 'a'."); + "Expected: empty But: was <0>."); + shouldFail('a', isEmpty, "Expected: empty But: was 'a'."); }); test('equalsIgnoringCase', () { shouldPass('hello', equalsIgnoringCase('HELLO')); shouldFail('hi', equalsIgnoringCase('HELLO'), - "Expected: 'HELLO' ignoring case but: was 'hi'."); + "Expected: 'HELLO' ignoring case But: was 'hi'."); }); test('equalsIgnoringWhitespace', () { shouldPass(' hello world ', equalsIgnoringWhitespace('hello world')); shouldFail(' helloworld ', equalsIgnoringWhitespace('hello world'), - "Expected: 'hello world' ignoring whitespace but: was 'helloworld'."); + "Expected: 'hello world' ignoring whitespace But: was 'helloworld'."); }); test('startsWith', () { @@ -403,7 +286,7 @@ shouldPass('hello', startsWith('hell')); shouldPass('hello', startsWith('hello')); shouldFail('hello', startsWith('hello '), - "Expected: a string starting with 'hello ' but: was 'hello'."); + "Expected: a string starting with 'hello ' But: was 'hello'."); }); test('endsWith', () { @@ -411,7 +294,7 @@ shouldPass('hello', endsWith('lo')); shouldPass('hello', endsWith('hello')); shouldFail('hello', endsWith(' hello'), - "Expected: a string ending with ' hello' but: was 'hello'."); + "Expected: a string ending with ' hello' But: was 'hello'."); }); test('contains', () { @@ -421,7 +304,7 @@ shouldPass('hello', contains('hell')); shouldPass('hello', contains('hello')); shouldFail('hello', contains(' '), - "Expected: contains ' ' but: was 'hello'."); + "Expected: contains ' ' But: was 'hello'."); }); test('stringContainsInOrder', () { @@ -440,29 +323,14 @@ shouldFail('goodbye cruel world', stringContainsInOrder(['goo', 'cruel', 'bye']), "Expected: a string containing 'goo', 'cruel', 'bye' in order " - "but: was 'goodbye cruel world'."); + "But: was 'goodbye cruel world'."); }); test('matches', () { shouldPass('c0d', matches('[a-z][0-9][a-z]')); shouldPass('c0d', matches(new RegExp('[a-z][0-9][a-z]'))); shouldFail('cOd', matches('[a-z][0-9][a-z]'), - "Expected: match '[a-z][0-9][a-z]' but: was 'cOd'."); - }); - }); - - group('Iterable Matchers', () { - test('isEmpty', () { - var d = new SimpleIterable(0); - var e = new SimpleIterable(1); - shouldPass(d, isEmpty); - shouldFail(e, isEmpty, "Expected: empty but: was <[1]>."); - }); - - test('contains', () { - var d = new SimpleIterable(3); - shouldPass(d, contains(2)); - shouldFail(d, contains(5), "Expected: contains <5> but: was <[3]>."); + "Expected: match '[a-z][0-9][a-z]' But: was 'cOd'."); }); }); @@ -470,26 +338,27 @@ test('isEmpty', () { shouldPass([], isEmpty); - shouldFail([1], isEmpty, "Expected: empty but: was <[1]>."); + shouldFail([1], isEmpty, "Expected: empty But: was [1]."); }); test('contains', () { var d = [1, 2]; shouldPass(d, contains(1)); - shouldFail(d, contains(0), "Expected: contains <0> but: was <[1, 2]>."); + shouldFail(d, contains(0), "Expected: contains <0> But: was [1, 2]."); }); test('isIn', () { var d = [1, 2]; shouldPass(1, isIn(d)); - shouldFail(0, isIn(d), "Expected: is in <[1, 2]> but: was <0>."); + shouldFail(0, isIn(d), "Expected: is in [1, 2] But: was <0>."); }); test('everyElement', () { var d = [1, 2]; var e = [1, 1, 1]; shouldFail(d, everyElement(1), - "Expected: every element <1> but: was <2> at position 1."); + "Expected: every element <1> But: position 1 was <2>. " + "Actual: [1, 2]"); shouldPass(e, everyElement(1)); }); @@ -498,7 +367,7 @@ var e = [1, 1, 1]; shouldPass(d, someElement(2)); shouldFail(e, someElement(2), - "Expected: some element <2> but: was <[1, 1, 1]>."); + "Expected: some element <2> But: was [1, 1, 1]."); }); test('orderedEquals', () { @@ -506,22 +375,26 @@ var d = [1, 2]; shouldPass(d, orderedEquals([1, 2])); shouldFail(d, orderedEquals([2, 1]), - "Expected: equals <[2, 1]> ordered " - "but: expected <2> but was <1> mismatch at position 0."); + "Expected: equals [2, 1] ordered " + "But: expected <2> but was <1> mismatch at position 0. " + "Actual: [1, 2]"); }); test('unorderedEquals', () { var d = [1, 2]; shouldPass(d, unorderedEquals([2, 1])); shouldFail(d, unorderedEquals([1]), - "Expected: equals <[1]> unordered " - "but: has too many elements (2 > 1)."); + "Expected: equals [1] unordered " + "But: has too many elements (2 > 1). " + "Actual: [1, 2]"); shouldFail(d, unorderedEquals([3, 2, 1]), - "Expected: equals <[3, 2, 1]> unordered " - "but: has too few elements (2 < 3)."); + "Expected: equals [3, 2, 1] unordered " + "But: has too few elements (2 < 3). " + "Actual: [1, 2]"); shouldFail(d, unorderedEquals([3, 1]), - "Expected: equals <[3, 1]> unordered " - "but: has no match for element <3> at position 0."); + "Expected: equals [3, 1] unordered " + "But: has no match for element <3> at position 0. " + "Actual: [1, 2]"); }); test('pairwise compare', () { @@ -530,19 +403,23 @@ var e = [1, 4, 9]; shouldFail('x', pairwiseCompare(e, (e,a) => a <= e, "less than or equal"), - "Expected: pairwise less than or equal <[1, 4, 9]> but: " - "not an Iterable."); + "Expected: pairwise less than or equal [1, 4, 9] " + "But: not an Iterable. " + "Actual: 'x'"); shouldFail(c, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"), - "Expected: pairwise less than or equal <[1, 4, 9]> but: " - "length was 2 instead of 3."); + "Expected: pairwise less than or equal [1, 4, 9] " + "But: length was 2 instead of 3. " + "Actual: [1, 2]"); shouldPass(d, pairwiseCompare(e, (e,a) => a <= e, "less than or equal")); shouldFail(d, pairwiseCompare(e, (e,a) => a < e, "less than"), - "Expected: pairwise less than <[1, 4, 9]> but: " - "<1> not less than <1> at position 0."); + "Expected: pairwise less than [1, 4, 9] " + "But: <1> not less than <1> at position 0. " + "Actual: [1, 2, 3]"); shouldPass(d, pairwiseCompare(e, (e,a) => a * a == e, "square root of")); shouldFail(d, pairwiseCompare(e, (e,a) => a + a == e, "double"), - "Expected: pairwise double <[1, 4, 9]> but: " - "<1> not double <1> at position 0."); + "Expected: pairwise double [1, 4, 9] " + "But: <1> not double <1> at position 0. " + "Actual: [1, 2, 3]"); }); }); @@ -553,7 +430,7 @@ shouldPass({}, isEmpty); shouldPass(a, isEmpty); a['foo'] = 'bar'; - shouldFail(a, isEmpty, "Expected: empty but: was <{foo: bar}>."); + shouldFail(a, isEmpty, "Expected: empty But: was {'foo': 'bar'}."); }); test('equals', () { @@ -565,7 +442,8 @@ c['bar'] = 'foo'; shouldPass(a, equals(b)); shouldFail(b, equals(c), - "Expected: <{bar: foo}> but: missing map key 'bar'."); + "Expected: {'bar': 'foo'} But: missing map key 'bar'. " + "Actual: {'foo': 'bar'}"); }); test('equals with different lengths', () { @@ -578,23 +456,29 @@ c['bar'] = 'foo'; c['barrista'] = 'caffeine'; shouldFail(a, equals(b), - "Expected: <{foo: bar, bar: foo}> " - "but: different map lengths; missing map key 'bar'."); + "Expected: {'foo': 'bar', 'bar': 'foo'} " + "But: different map lengths; missing map key 'bar'. " + "Actual: {'foo': 'bar'}"); shouldFail(b, equals(a), - "Expected: <{foo: bar}> " - "but: different map lengths; extra map key 'bar'."); + "Expected: {'foo': 'bar'} " + "But: different map lengths; extra map key 'bar'. " + "Actual: {'foo': 'bar', 'bar': 'foo'}"); shouldFail(b, equals(c), - "Expected: <{bar: foo, barrista: caffeine}> " - "but: missing map key 'barrista'."); + "Expected: {'bar': 'foo', 'barrista': 'caffeine'} " + "But: missing map key 'barrista'. " + "Actual: {'foo': 'bar', 'bar': 'foo'}"); shouldFail(c, equals(b), - "Expected: <{foo: bar, bar: foo}> " - "but: missing map key 'foo'."); + "Expected: {'foo': 'bar', 'bar': 'foo'} " + "But: missing map key 'foo'. " + "Actual: {'bar': 'foo', 'barrista': 'caffeine'}"); shouldFail(a, equals(c), - "Expected: <{bar: foo, barrista: caffeine}> " - "but: different map lengths; missing map key 'bar'."); + "Expected: {'bar': 'foo', 'barrista': 'caffeine'} " + "But: different map lengths; missing map key 'bar'. " + "Actual: {'foo': 'bar'}"); shouldFail(c, equals(a), - "Expected: <{foo: bar}> " - "but: different map lengths; missing map key 'foo'."); + "Expected: {'foo': 'bar'} " + "But: different map lengths; missing map key 'foo'. " + "Actual: {'bar': 'foo', 'barrista': 'caffeine'}"); }); test('contains', () { @@ -603,9 +487,9 @@ var b = new Map(); shouldPass(a, contains('foo')); shouldFail(b, contains('foo'), - "Expected: contains 'foo' but: was <{}>."); + "Expected: contains 'foo' But: was {}."); shouldFail(10, contains('foo'), - "Expected: contains 'foo' but: was <10>."); + "Expected: contains 'foo' But: was <10>."); }); test('containsValue', () { @@ -613,7 +497,7 @@ a['foo'] = 'bar'; shouldPass(a, containsValue('bar')); shouldFail(a, containsValue('ba'), - "Expected: contains value 'ba' but: was <{foo: bar}>."); + "Expected: contains value 'ba' But: was {'foo': 'bar'}."); }); test('containsPair', () { @@ -622,10 +506,12 @@ shouldPass(a, containsPair('foo', 'bar')); shouldFail(a, containsPair('foo', 'ba'), "Expected: contains pair 'foo' => 'ba' " - "but: contains key 'foo' but with value was 'bar'."); + "But: contains key 'foo' but with value was 'bar'. " + "Actual: {'foo': 'bar'}"); shouldFail(a, containsPair('fo', 'bar'), "Expected: contains pair 'fo' => 'bar' " - "but: <{foo: bar}> doesn't contain key 'fo'."); + "But: doesn't contain key 'fo'. " + "Actual: {'foo': 'bar'}"); }); test('hasLength', () { @@ -635,7 +521,8 @@ shouldPass(a, hasLength(1)); shouldFail(b, hasLength(1), "Expected: an object with length of <1> " - "but: was <{}> with length of <0>."); + "But: had length of <0>. " + "Actual: {}"); }); }); @@ -643,7 +530,7 @@ test('anyOf', () { shouldFail(0, anyOf([equals(1), equals(2)]), - "Expected: (<1> or <2>) but: was <0>."); + "Expected: (<1> or <2>) But: was <0>."); shouldPass(1, anyOf([equals(1), equals(2)])); }); @@ -651,7 +538,7 @@ shouldPass(1, allOf([lessThan(10), greaterThan(0)])); shouldFail(-1, allOf([lessThan(10), greaterThan(0)]), "Expected: (a value less than <10> and a value greater than <0>) " - "but: a value greater than <0> was <-1>."); + "But: was <-1> (wasn't a value greater than <0>)."); }); }); @@ -711,7 +598,7 @@ var completer = new Completer(); completer.completeError('X'); shouldFail(completer.future, throwsA(equals('Y')), - "Expected: 'Y' but: was 'X'.", + "Expected: 'Y' But: was 'X'.", isAsync: true); }); }); @@ -719,21 +606,9 @@ group('Predicate Matchers', () { test('isInstanceOf', () { shouldFail(0, predicate((x) => x is String, "an instance of String"), - "Expected: an instance of String but: was <0>."); + "Expected: an instance of String But: was <0>."); shouldPass('cow', predicate((x) => x is String, "an instance of String")); }); }); - - group('Feature Matchers', () { - test("Feature Matcher", () { - var w = new Widget(); - w.price = 10; - shouldPass(w, new HasPrice(10)); - shouldPass(w, new HasPrice(greaterThan(0))); - shouldFail(w, new HasPrice(greaterThan(10)), - 'Expected: Widget with a price that is a value greater than <10> ' - 'but: price was <10>.'); - }); - }); }
diff --git a/pkg/unittest/test/matchers_unminified_test.dart b/pkg/unittest/test/matchers_unminified_test.dart new file mode 100644 index 0000000..7435a0c --- /dev/null +++ b/pkg/unittest/test/matchers_unminified_test.dart
@@ -0,0 +1,132 @@ +// 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 is for matcher tests that rely on the names of various Dart types. +// These tests will fail when run in minified dart2js, since the names will be +// mangled. A version of this file that works in minified dart2js is in +// matchers_minified_test.dart. + +import 'package:unittest/unittest.dart'; + +import 'test_common.dart'; +import 'test_utils.dart'; + +void main() { + initUtils(); + + group('Core matchers', () { + test('throwsFormatException', () { + shouldPass(() { throw new FormatException(''); }, + throwsFormatException); + shouldFail(() { throw new Exception(); }, + throwsFormatException, + matches( + r"Expected: throws an exception which matches FormatException +" + r"But: exception \?:<Exception> does not match FormatException\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsArgumentError', () { + shouldPass(() { throw new ArgumentError(''); }, + throwsArgumentError); + shouldFail(() { throw new Exception(); }, + throwsArgumentError, + matches( + r"Expected: throws an exception which matches ArgumentError +" + r"But: exception \?:<Exception> does not match " + r"ArgumentError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsRangeError', () { + shouldPass(() { throw new RangeError(0); }, + throwsRangeError); + shouldFail(() { throw new Exception(); }, + throwsRangeError, + matches( + r"Expected: throws an exception which matches RangeError +" + r"But: exception \?:<Exception> does not match RangeError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsNoSuchMethodError', () { + shouldPass(() { throw new NoSuchMethodError(null, '', null, null); }, + throwsNoSuchMethodError); + shouldFail(() { throw new Exception(); }, + throwsNoSuchMethodError, + matches( + r"Expected: throws an exception which matches NoSuchMethodError +" + r"But: exception \?:<Exception> does not match " + r"NoSuchMethodError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsUnimplementedError', () { + shouldPass(() { throw new UnimplementedError(''); }, + throwsUnimplementedError); + shouldFail(() { throw new Exception(); }, + throwsUnimplementedError, + matches( + r"Expected: throws an exception which matches " + r"UnimplementedError +" + r"But: exception \?:<Exception> does not match " + r"UnimplementedError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsUnsupportedError', () { + shouldPass(() { throw new UnsupportedError(''); }, + throwsUnsupportedError); + shouldFail(() { throw new Exception(); }, + throwsUnsupportedError, + matches( + r"Expected: throws an exception which matches UnsupportedError +" + r"But: exception \?:<Exception> does not match " + r"UnsupportedError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + + test('throwsStateError', () { + shouldPass(() { throw new StateError(''); }, + throwsStateError); + shouldFail(() { throw new Exception(); }, + throwsStateError, + matches( + r"Expected: throws an exception which matches StateError +" + r"But: exception \?:<Exception> does not match " + r"StateError\." + r"Actual: <Closure(: \(dynamic\) => dynamic)?>")); + }); + }); + + group('Iterable Matchers', () { + test('isEmpty', () { + var d = new SimpleIterable(0); + var e = new SimpleIterable(1); + shouldPass(d, isEmpty); + shouldFail(e, isEmpty, "Expected: empty But: was SimpleIterable:[1]."); + }); + + test('contains', () { + var d = new SimpleIterable(3); + shouldPass(d, contains(2)); + shouldFail(d, contains(5), + "Expected: contains <5> " + "But: was SimpleIterable:[3, 2, 1]."); + }); + }); + + group('Feature Matchers', () { + test("Feature Matcher", () { + var w = new Widget(); + w.price = 10; + shouldPass(w, new HasPrice(10)); + shouldPass(w, new HasPrice(greaterThan(0))); + shouldFail(w, new HasPrice(greaterThan(10)), + "Expected: Widget with a price that is a value greater than <10> " + "But: price was <10>. " + "Actual: <Instance of 'Widget'>"); + }); + }); +}
diff --git a/pkg/unittest/test/pretty_print_minified_test.dart b/pkg/unittest/test/pretty_print_minified_test.dart new file mode 100644 index 0000000..16c5cd6 --- /dev/null +++ b/pkg/unittest/test/pretty_print_minified_test.dart
@@ -0,0 +1,61 @@ +// 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 is for pretty-print tests that rely on the names of various Dart +// types. These tests normally fail when run in minified dart2js, since the +// names will be mangled. This version of the file is modified to expect +// minified names. + +import 'dart:collection'; + +import 'package:unittest/src/pretty_print.dart'; +import 'package:unittest/unittest.dart'; + +class DefaultToString {} + +class CustomToString { + String toString() => "string representation"; +} + +class _PrivateName { + String toString() => "string representation"; +} + +class _PrivateNameIterable extends IterableMixin { + Iterator get iterator => [1, 2, 3].iterator; +} + +// A regexp fragment matching a minified name. +final _minifiedName = r"[A-Za-z0-9]{1,3}"; + +void main() { + group('with an object', () { + test('with a default [toString]', () { + expect(prettyPrint(new DefaultToString()), + matches(r"<Instance of '" + _minifiedName + r"'>")); + }); + + test('with a custom [toString]', () { + expect(prettyPrint(new CustomToString()), + matches(_minifiedName + r':<string representation>')); + }); + + test('with a custom [toString] and a private name', () { + expect(prettyPrint(new _PrivateName()), + matches(_minifiedName + r':<string representation>')); + }); + }); + + group('with an iterable', () { + test("that's not a list", () { + expect(prettyPrint([1, 2, 3, 4].map((n) => n * 2)), + matches(_minifiedName + r":\[2, 4, 6, 8\]")); + }); + + test("that's not a list and has a private name", () { + expect(prettyPrint(new _PrivateNameIterable()), + matches(_minifiedName + r":\[1, 2, 3\]")); + }); + }); +}
diff --git a/pkg/unittest/test/pretty_print_test.dart b/pkg/unittest/test/pretty_print_test.dart new file mode 100644 index 0000000..e5cd2e2 --- /dev/null +++ b/pkg/unittest/test/pretty_print_test.dart
@@ -0,0 +1,181 @@ +// 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 'package:unittest/src/pretty_print.dart'; +import 'package:unittest/unittest.dart'; + +void main() { + test('with primitive objects', () { + expect(prettyPrint(12), equals('<12>')); + expect(prettyPrint(12.13), equals('<12.13>')); + expect(prettyPrint(true), equals('<true>')); + expect(prettyPrint(null), equals('<null>')); + expect(prettyPrint(() => 12), + matches(r'<Closure(: \(dynamic\) => dynamic)?>')); + }); + + group('with a string', () { + test('containing simple characters', () { + expect(prettyPrint('foo'), equals("'foo'")); + }); + + test('containing newlines', () { + expect(prettyPrint('foo\nbar\nbaz'), equals( + "'foo\\n'\n" + " 'bar\\n'\n" + " 'baz'")); + }); + + test('containing escapable characters', () { + expect(prettyPrint("foo\rbar\tbaz'qux"), + equals("'foo\\rbar\\tbaz\\'qux'")); + }); + }); + + group('with an iterable', () { + test('containing primitive objects', () { + expect(prettyPrint([1, true, 'foo']), equals("[1, true, 'foo']")); + }); + + test('containing a multiline string', () { + expect(prettyPrint(['foo', 'bar\nbaz\nbip', 'qux']), equals("[\n" + " 'foo',\n" + " 'bar\\n'\n" + " 'baz\\n'\n" + " 'bip',\n" + " 'qux'\n" + "]")); + }); + + test("that's under maxLineLength", () { + expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 30), + equals("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]")); + }); + + test("that's over maxLineLength", () { + expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 29), + equals("[\n" + " 0,\n" + " 1,\n" + " 2,\n" + " 3,\n" + " 4,\n" + " 5,\n" + " 6,\n" + " 7,\n" + " 8,\n" + " 9\n" + "]")); + }); + + test("factors indentation into maxLineLength", () { + expect(prettyPrint([ + "foo\nbar", + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + ], maxLineLength: 30), equals("[\n" + " 'foo\\n'\n" + " 'bar',\n" + " [\n" + " 0,\n" + " 1,\n" + " 2,\n" + " 3,\n" + " 4,\n" + " 5,\n" + " 6,\n" + " 7,\n" + " 8,\n" + " 9\n" + " ]\n" + "]")); + }); + + test("that's under maxItems", () { + expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 10), + equals("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]")); + }); + + test("that's over maxItems", () { + expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 9), + equals("[0, 1, 2, 3, 4, 5, 6, 7, ...]")); + }); + + test("that's recursive", () { + var list = [1, 2, 3]; + list.add(list); + expect(prettyPrint(list), equals("[1, 2, 3, (recursive)]")); + }); + }); + + group("with a map", () { + test('containing primitive objects', () { + expect(prettyPrint({'foo': 1, 'bar': true}), + equals("{'foo': 1, 'bar': true}")); + }); + + test('containing a multiline string key', () { + expect(prettyPrint({'foo\nbar': 1, 'bar': true}), equals("{\n" + " 'foo\\n'\n" + " 'bar': 1,\n" + " 'bar': true\n" + "}")); + }); + + test('containing a multiline string value', () { + expect(prettyPrint({'foo': 'bar\nbaz', 'qux': true}), equals("{\n" + " 'foo': 'bar\\n'\n" + " 'baz',\n" + " 'qux': true\n" + "}")); + }); + + test('containing a multiline string key/value pair', () { + expect(prettyPrint({'foo\nbar': 'baz\nqux'}), equals("{\n" + " 'foo\\n'\n" + " 'bar': 'baz\\n'\n" + " 'qux'\n" + "}")); + }); + + test("that's under maxLineLength", () { + expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 32), + equals("{'0': 1, '2': 3, '4': 5, '6': 7}")); + }); + + test("that's over maxLineLength", () { + expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 31), + equals("{\n" + " '0': 1,\n" + " '2': 3,\n" + " '4': 5,\n" + " '6': 7\n" + "}")); + }); + + test("factors indentation into maxLineLength", () { + expect(prettyPrint(["foo\nbar", {'0': 1, '2': 3, '4': 5, '6': 7}], + maxLineLength: 32), + equals("[\n" + " 'foo\\n'\n" + " 'bar',\n" + " {\n" + " '0': 1,\n" + " '2': 3,\n" + " '4': 5,\n" + " '6': 7\n" + " }\n" + "]")); + }); + + test("that's under maxItems", () { + expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 4), + equals("{'0': 1, '2': 3, '4': 5, '6': 7}")); + }); + + test("that's over maxItems", () { + expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 3), + equals("{'0': 1, '2': 3, ...}")); + }); + }); +}
diff --git a/pkg/unittest/test/pretty_print_unminified_test.dart b/pkg/unittest/test/pretty_print_unminified_test.dart new file mode 100644 index 0000000..4417bcb --- /dev/null +++ b/pkg/unittest/test/pretty_print_unminified_test.dart
@@ -0,0 +1,58 @@ +// 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 is for pretty-print tests that rely on the names of various Dart +// types. These tests will fail when run in minified dart2js, since the names +// will be mangled. A version of this file that works in minified dart2js is in +// pretty_print_minified_test.dart. + +import 'dart:collection'; + +import 'package:unittest/src/pretty_print.dart'; +import 'package:unittest/unittest.dart'; + +class DefaultToString {} + +class CustomToString { + String toString() => "string representation"; +} + +class _PrivateName { + String toString() => "string representation"; +} + +class _PrivateNameIterable extends IterableMixin { + Iterator get iterator => [1, 2, 3].iterator; +} + +void main() { + group('with an object', () { + test('with a default [toString]', () { + expect(prettyPrint(new DefaultToString()), + equals("<Instance of 'DefaultToString'>")); + }); + + test('with a custom [toString]', () { + expect(prettyPrint(new CustomToString()), + equals('CustomToString:<string representation>')); + }); + + test('with a custom [toString] and a private name', () { + expect(prettyPrint(new _PrivateName()), + equals('?:<string representation>')); + }); + }); + + group('with an iterable', () { + test("that's not a list", () { + expect(prettyPrint([1, 2, 3, 4].map((n) => n * 2)), + equals("MappedListIterable:[2, 4, 6, 8]")); + }); + + test("that's not a list and has a private name", () { + expect(prettyPrint(new _PrivateNameIterable()), + equals("?:[1, 2, 3]")); + }); + }); +}
diff --git a/pkg/unittest/test/test_common.dart b/pkg/unittest/test/test_common.dart new file mode 100644 index 0000000..8631768 --- /dev/null +++ b/pkg/unittest/test/test_common.dart
@@ -0,0 +1,59 @@ +// 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 test_common; + +import 'dart:collection'; + +import 'package:unittest/unittest.dart'; + +class Widget { + int price; +} + +class HasPrice extends CustomMatcher { + HasPrice(matcher) : + super("Widget with a price that is", "price", matcher); + featureValueOf(actual) => actual.price; +} + +class SimpleIterable extends IterableBase { + int count; + SimpleIterable(this.count); + + bool contains(int val) => count < val ? false : true; + + bool any(bool f(element)) { + for(var i = 0; i <= count; i++) { + if(f(i)) return true; + } + return false; + } + + String toString() => "<[$count]>"; + + Iterator get iterator { + return new SimpleIterator(count); + } +} + +class SimpleIterator implements Iterator { + int _count; + int _current; + + SimpleIterator(this._count); + + bool moveNext() { + if (_count > 0) { + _current = _count; + _count--; + return true; + } + _current = null; + return false; + } + + get current => _current; +} +
diff --git a/pkg/unittest/test/test_utils.dart b/pkg/unittest/test/test_utils.dart index d783665..f0b276d 100644 --- a/pkg/unittest/test/test_utils.dart +++ b/pkg/unittest/test/test_utils.dart
@@ -2,7 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of unittestTests; +library test_utils; + +import 'package:unittest/unittest.dart'; + +import 'dart:async'; int errorCount; String errorString; @@ -58,3 +62,20 @@ afterTest(); } } + +doesNotThrow() {} +doesThrow() { throw 'X'; } + +class PrefixMatcher extends BaseMatcher { + final String _prefix; + const PrefixMatcher(this._prefix); + bool matches(item, MatchState matchState) { + return item is String && + (collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix)); + } + + Description describe(Description description) => + description.add('a string starting with '). + addDescriptionOf(collapseWhitespace(_prefix)). + add(' ignoring whitespace'); +}
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart index 1bbfb18..cc28d9e 100644 --- a/pkg/unittest/test/unittest_test.dart +++ b/pkg/unittest/test/unittest_test.dart
@@ -405,7 +405,7 @@ var tests = { 'single correct test': buildStatusString(1, 0, 0, 'single correct test'), 'single failing test': buildStatusString(0, 1, 0, 'single failing test', - message: 'Expected: <5> but: was <4>.'), + message: 'Expected: <5> But: was <4>.'), 'exception test': buildStatusString(0, 1, 0, 'exception test', message: 'Caught Exception: Fail.'), 'group name test': buildStatusString(2, 0, 0, 'a a::a b b'), @@ -427,7 +427,7 @@ message: 'Callback called (2) after test case testOne has already ' 'been marked as pass.:testTwo:'), 'middle exception test': buildStatusString(2, 1, 0, - 'testOne::testTwo:Expected: false but: was <true>.:testThree'), + 'testOne::testTwo:Expected: false But: was <true>.:testThree'), 'async setup/teardown test': buildStatusString(2, 0, 3, 'good setup/good teardown foo1::' 'good setup/bad teardown foo2:good setup/bad teardown ' @@ -440,13 +440,13 @@ 'test returning future': buildStatusString(2, 4, 0, 'successful::' 'error1:Callback called more times than expected (1).:' - 'fail1:Expected: <false> but: was <true>.:' + 'fail1:Expected: <false> But: was <true>.:' 'error2:Callback called more times than expected (1).:' 'fail2:failure:' 'foo5'), 'test returning future using runAsync': buildStatusString(2, 4, 0, 'successful::' - 'fail1:Expected: <false> but: was <true>.:' + 'fail1:Expected: <false> But: was <true>.:' 'error1:Callback called more times than expected (1).:' 'fail2:failure:' 'error2:Callback called more times than expected (1).:'
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc index 41d71f1..5e5b61a 100644 --- a/runtime/bin/gen_snapshot.cc +++ b/runtime/bin/gen_snapshot.cc
@@ -267,6 +267,17 @@ } +static Builtin::BuiltinLibraryId BuiltinId(const char* url) { + if (DartUtils::IsDartBuiltinLibURL(url)) { + return Builtin::kBuiltinLibrary; + } + if (DartUtils::IsDartIOLibURL(url)) { + return Builtin::kIOLibrary; + } + return Builtin::kInvalidLibrary; +} + + static Dart_Handle CreateSnapshotLibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url) { @@ -292,17 +303,36 @@ const char* mapped_url_string = DartUtils::MapLibraryUrl(url_mapping, url_string); + Builtin::BuiltinLibraryId libraryBuiltinId = BuiltinId(library_url_string); if (tag == kCanonicalizeUrl) { - // Keep original names for libraries that have a mapping (e.g. dart:io). if (mapped_url_string) { return url; } + // Parts of internal libraries are handled internally. + if (libraryBuiltinId != Builtin::kInvalidLibrary) { + return url; + } return ResolveUri(library_url_string, url_string); } - if (DartUtils::IsDartIOLibURL(url_string) && mapped_url_string == NULL) { - // No url mapping for dart:io. Load original version. - return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary); + Builtin::BuiltinLibraryId builtinId = BuiltinId(url_string); + if (builtinId != Builtin::kInvalidLibrary) { + // Special case for importing a builtin library. + if (tag == kImportTag) { + return Builtin::LoadAndCheckLibrary(builtinId); + } + ASSERT(tag == kSourceTag); + return Dart_Error("Unable to part '%s' ", url_string); + } + + if (libraryBuiltinId != Builtin::kInvalidLibrary) { + // Special case for parting sources of a builtin library. + if (tag == kSourceTag) { + return Dart_LoadSource( + library, url, Builtin::PartSource(libraryBuiltinId, url_string)); + } + ASSERT(tag == kImportTag); + return Dart_Error("Unable to import '%s' ", url_string); } Dart_Handle resolved_url = url;
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart index d10f3ae..3de4c29 100644 --- a/runtime/bin/socket_patch.dart +++ b/runtime/bin/socket_patch.dart
@@ -867,13 +867,12 @@ void done([error]) { if (streamCompleter != null) { - var tmp = streamCompleter; - streamCompleter = null; if (error != null) { - tmp.completeError(error); + streamCompleter.completeError(error); } else { - tmp.complete(socket); + streamCompleter.complete(socket); } + streamCompleter = null; } }
diff --git a/runtime/embedders/openglui/build_skia.sh b/runtime/embedders/openglui/build_skia.sh index 03f0f5b..42710a8 100755 --- a/runtime/embedders/openglui/build_skia.sh +++ b/runtime/embedders/openglui/build_skia.sh
@@ -61,7 +61,7 @@ if [ ${DO_ANDROID} != 0 ] ; then echo "Building for Android ${TARGET_ARCH}" - curl http://skia.googlecode.com/svn/android/gclient.config -o .gclient + curl http://skia.googlecode.com/svn/trunk/platform_tools/android/gclient.config -o .gclient gclient sync export ANDROID_SDK_ROOT=`readlink -f ../android_tools/sdk` @@ -71,9 +71,10 @@ echo "Using SDK ${ANDROID_SDK_ROOT}" if [ ${CLEAN} != 0 ] ; then - ../android/bin/android_make -d $TARGET_ARCH -j clean + ./platform_tools/android/bin/android_make -d $TARGET_ARCH -j clean else - env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j + echo env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j + env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${GSUTIL_LOCATION}" ./platform_tools/android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j fi else
diff --git a/runtime/embedders/openglui/openglui_embedder.gypi b/runtime/embedders/openglui/openglui_embedder.gypi index c3671ee..c67cf90 100644 --- a/runtime/embedders/openglui/openglui_embedder.gypi +++ b/runtime/embedders/openglui/openglui_embedder.gypi
@@ -50,6 +50,7 @@ '../../vm/version.h', '../../../third_party/android_tools/ndk/sources/android/native_app_glue/android_native_app_glue.h', '../../../third_party/android_tools/ndk/sources/android/native_app_glue/android_native_app_glue.c', + '../../../third_party/skia/trunk/src/core/SkPaintOptionsAndroid.cpp', 'android/android_graphics_handler.cc', 'android/android_graphics_handler.h', 'android/android_input_handler.h', @@ -115,6 +116,10 @@ '-lgif', '-ljpeg', '-lpng', + '-lwebp_dec', + '-lwebp_utils', + '-lwebp_dsp', + '-lwebp_enc', '-lskia_core', '-lskia_effects', '-lskia_gr', @@ -264,7 +269,8 @@ '-lGL', '-lglut', '-lGLU', - '-lm' + '-lm', + '-lwebp' ], }, 'conditions': [
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc index 2b1f1c7..dbc6886 100644 --- a/runtime/lib/double.cc +++ b/runtime/lib/double.cc
@@ -80,8 +80,8 @@ Exceptions::ThrowByType(Exceptions::kUnsupported, args); } const Bigint& big = Bigint::Handle(BigintOperations::NewFromDouble(val)); - if (BigintOperations::FitsIntoMint(big)) { - return Integer::New(BigintOperations::ToMint(big)); + if (BigintOperations::FitsIntoInt64(big)) { + return Integer::New(BigintOperations::ToInt64(big)); } else { return big.raw(); }
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc index d368415..eb8bd93 100644 --- a/runtime/lib/integers.cc +++ b/runtime/lib/integers.cc
@@ -24,7 +24,7 @@ if (i.IsBigint()) { const Bigint& bigint = Bigint::Cast(i); return !BigintOperations::FitsIntoSmi(bigint) && - !BigintOperations::FitsIntoMint(bigint); + !BigintOperations::FitsIntoInt64(bigint); } if (i.IsMint()) { const Mint& mint = Mint::Cast(i);
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart index a0c7711..c279c19 100644 --- a/runtime/lib/math_patch.dart +++ b/runtime/lib/math_patch.dart
@@ -68,27 +68,31 @@ // 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 is selected from "Numerical Recipes 3rd Edition" p.348 B1. - int _nextInt32() { + void _nextState() { var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; _state[kSTATE_LO] = state & _MASK_32; _state[kSTATE_HI] = state >> 32; - return _state[kSTATE_LO]; } int nextInt(int max) { - if (max <= 0 || max > _POW2_32) { + // TODO(srdjan): Remove the 'limit' check once optimizing comparison of + // Smi-s with Mint constants. + final limit = 0x3FFFFFFF; + if (max <= 0 || ((max > limit) && (max > _POW2_32))) { throw new ArgumentError("max must be positive and < 2^32:" " $max"); } if ((max & -max) == max) { // Fast case for powers of two. - return _nextInt32() & (max - 1); + _nextState(); + return _state[kSTATE_LO] & (max - 1); } var rnd32; var result; do { - rnd32 = _nextInt32(); + _nextState(); + rnd32 = _state[kSTATE_LO]; result = rnd32 % max; } while ((rnd32 - result + max) >= _POW2_32); return result; @@ -119,6 +123,7 @@ _prng = new Random(new DateTime.now().millisecondsSinceEpoch); } // Trigger the PRNG once to change the internal state. - return _prng._nextInt32(); + _prng._nextState(); + return _prng._state[kSTATE_LO]; } }
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc index ac26d087..a4a3faf 100644 --- a/runtime/lib/object.cc +++ b/runtime/lib/object.cc
@@ -17,8 +17,7 @@ DEFINE_NATIVE_ENTRY(Object_cid, 1) { const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0)); - const Class& cls = Class::Handle(instance.clazz()); - return Smi::New(cls.id()); + return Smi::New(instance.GetClassId()); }
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart index e9f5759..dbe8dc0 100644 --- a/runtime/lib/string_patch.dart +++ b/runtime/lib/string_patch.dart
@@ -199,6 +199,43 @@ String _substringUncheckedNative(int startIndex, int endIndex) native "StringBase_substringUnchecked"; + // Checks for one-byte whitespaces only. + static bool _isOneByteWhitespace(int codePoint) { + return + (codePoint == 32) || // Space. + ((9 <= codePoint) && (codePoint <= 13)) || // CR, LF, TAB, etc. + (codePoint == 0x85) || // NEL + (codePoint == 0xA0); // NBSP + } + + // Characters with Whitespace property (Unicode 6.2). + // 0009..000D ; White_Space # Cc <control-0009>..<control-000D> + // 0020 ; White_Space # Zs SPACE + // 0085 ; White_Space # Cc <control-0085> + // 00A0 ; White_Space # Zs NO-BREAK SPACE + // 1680 ; White_Space # Zs OGHAM SPACE MARK + // 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR + // 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE + // 2028 ; White_Space # Zl LINE SEPARATOR + // 2029 ; White_Space # Zp PARAGRAPH SEPARATOR + // 202F ; White_Space # Zs NARROW NO-BREAK SPACE + // 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE + // 3000 ; White_Space # Zs IDEOGRAPHIC SPACE + // + // BOM: 0xFEFF + static bool _isTwoByteWhitespace(int codePoint) { + if (codePoint < 256) return _isOneByteWhitespace(codePoint); + return (codePoint == 0x1680) || + (codePoint == 0x180E) || + ((0x2000 <= codePoint) && (codePoint <= 0x200A)) || + (codePoint == 0x2028) || + (codePoint == 0x2029) || + (codePoint == 0x202F) || + (codePoint == 0x205F) || + (codePoint == 0x3000) || + (codePoint == 0xFEFF); + } + String trim() { final int len = this.length; int first = 0; @@ -510,13 +547,8 @@ int get hashCode native "String_getHashCode"; - // Checks for one-byte whitespaces only. - // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid - // whitespaces for one byte strings. bool _isWhitespace(int codePoint) { - return - (codePoint == 32) || // Space. - ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. + return _StringBase._isOneByteWhitespace(codePoint); } String _substringUncheckedNative(int startIndex, int endIndex) @@ -568,30 +600,8 @@ "_TwoByteString can only be allocated by the VM"); } - // Checks for one-byte whitespaces only. - // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid - // whitespaces. Add checking for multi-byte whitespace codepoints. bool _isWhitespace(int codePoint) { - return - (codePoint == 32) || // Space. - ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. - } -} - - -class _FourByteString extends _StringBase implements String { - factory _FourByteString._uninstantiable() { - throw new UnsupportedError( - "_FourByteString can only be allocated by the VM"); - } - - // Checks for one-byte whitespaces only. - // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid - // whitespaces. Add checking for multi-byte whitespace codepoints. - bool _isWhitespace(int codePoint) { - return - (codePoint == 32) || // Space. - ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. + return _StringBase._isTwoByteWhitespace(codePoint); } } @@ -602,13 +612,8 @@ "_ExternalOneByteString can only be allocated by the VM"); } - // Checks for one-byte whitespaces only. - // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid - // whitespaces for one byte strings. bool _isWhitespace(int codePoint) { - return - (codePoint == 32) || // Space. - ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. + return _StringBase._isOneByteWhitespace(codePoint); } } @@ -619,13 +624,8 @@ "_ExternalTwoByteString can only be allocated by the VM"); } - // Checks for one-byte whitespaces only. - // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid - // whitespaces. Add checking for multi-byte whitespace codepoints. bool _isWhitespace(int codePoint) { - return - (codePoint == 32) || // Space. - ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc. + return _StringBase._isTwoByteWhitespace(codePoint); } }
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index 5787071..a79042d 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status
@@ -81,3 +81,8 @@ cc/CustomIsolates: Skip # Bug 6890 cc/NewNativePort: Skip # Bug 6890 cc/RunLoop_ExceptionParent: Skip # Bug 6890 + +[ $compiler == dartanalyzer ] +# has compilation error, as designed +dart/isolate_mirror_local_test: fail +
diff --git a/runtime/vm/bigint_operations.cc b/runtime/vm/bigint_operations.cc index 118a836..709baa2 100644 --- a/runtime/vm/bigint_operations.cc +++ b/runtime/vm/bigint_operations.cc
@@ -605,7 +605,7 @@ } -bool BigintOperations::FitsIntoMint(const Bigint& bigint) { +bool BigintOperations::FitsIntoInt64(const Bigint& bigint) { intptr_t bigint_length = bigint.Length(); if (bigint_length == 0) { return true; @@ -663,11 +663,11 @@ } -int64_t BigintOperations::ToMint(const Bigint& bigint) { +int64_t BigintOperations::ToInt64(const Bigint& bigint) { if (bigint.IsZero()) { return 0; } - ASSERT(FitsIntoMint(bigint)); + ASSERT(FitsIntoInt64(bigint)); int64_t value = AbsToUint64(bigint); if (bigint.IsNegative()) { value = -value;
diff --git a/runtime/vm/bigint_operations.h b/runtime/vm/bigint_operations.h index e9c31a2..892ee6c 100644 --- a/runtime/vm/bigint_operations.h +++ b/runtime/vm/bigint_operations.h
@@ -62,8 +62,8 @@ static bool FitsIntoSmi(const Bigint& bigint); static RawSmi* ToSmi(const Bigint& bigint); - static bool FitsIntoMint(const Bigint& bigint); - static int64_t ToMint(const Bigint& bigint); + static bool FitsIntoInt64(const Bigint& bigint); + static int64_t ToInt64(const Bigint& bigint); static bool FitsIntoUint64(const Bigint& bigint); static bool AbsFitsIntoUint64(const Bigint& bigint);
diff --git a/runtime/vm/bigint_operations_test.cc b/runtime/vm/bigint_operations_test.cc index 0c141a1..b43ff90 100644 --- a/runtime/vm/bigint_operations_test.cc +++ b/runtime/vm/bigint_operations_test.cc
@@ -79,45 +79,45 @@ const Bigint& one = Bigint::Handle(BigintOperations::NewFromInt64(1)); big = BigintOperations::NewFromInt64(kMinInt64); - EXPECT(BigintOperations::FitsIntoMint(big)); - int64_t back = BigintOperations::ToMint(big); + EXPECT(BigintOperations::FitsIntoInt64(big)); + int64_t back = BigintOperations::ToInt64(big); EXPECT_EQ(kMinInt64, back); big = BigintOperations::Subtract(big, one); - EXPECT(!BigintOperations::FitsIntoMint(big)); + EXPECT(!BigintOperations::FitsIntoInt64(big)); big = BigintOperations::NewFromInt64(kMaxInt64); - EXPECT(BigintOperations::FitsIntoMint(big)); - back = BigintOperations::ToMint(big); + EXPECT(BigintOperations::FitsIntoInt64(big)); + back = BigintOperations::ToInt64(big); EXPECT_EQ(kMaxInt64, back); big = BigintOperations::Add(big, one); - EXPECT(!BigintOperations::FitsIntoMint(big)); + EXPECT(!BigintOperations::FitsIntoInt64(big)); } TEST_CASE(BigintUint64) { const Bigint& one = Bigint::Handle(BigintOperations::NewFromUint64(1)); - EXPECT(BigintOperations::FitsIntoMint(one)); + EXPECT(BigintOperations::FitsIntoInt64(one)); EXPECT(BigintOperations::FitsIntoUint64(one)); Bigint& big = Bigint::Handle(BigintOperations::NewFromUint64(kMaxUint64)); - EXPECT(!BigintOperations::FitsIntoMint(big)); + EXPECT(!BigintOperations::FitsIntoInt64(big)); EXPECT(BigintOperations::FitsIntoUint64(big)); uint64_t back = BigintOperations::ToUint64(big); EXPECT_EQ(kMaxUint64, back); big = BigintOperations::Add(big, one); - EXPECT(!BigintOperations::FitsIntoMint(big)); + EXPECT(!BigintOperations::FitsIntoInt64(big)); EXPECT(!BigintOperations::FitsIntoUint64(big)); big = BigintOperations::Subtract(big, one); - EXPECT(!BigintOperations::FitsIntoMint(big)); + EXPECT(!BigintOperations::FitsIntoInt64(big)); EXPECT(BigintOperations::FitsIntoUint64(big)); big = BigintOperations::ShiftRight(big, 1); - EXPECT(BigintOperations::FitsIntoMint(big)); + EXPECT(BigintOperations::FitsIntoInt64(big)); EXPECT(BigintOperations::FitsIntoUint64(big)); }
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index 673df7a..aa843a5 100644 --- a/runtime/vm/class_finalizer.cc +++ b/runtime/vm/class_finalizer.cc
@@ -115,7 +115,7 @@ ASSERT(isolate != NULL); HANDLESCOPE(isolate); ObjectStore* object_store = isolate->object_store(); - const Error& error = Error::Handle(object_store->sticky_error()); + const Error& error = Error::Handle(isolate, object_store->sticky_error()); if (!error.IsNull()) { return false; }
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc index 8d74e7b..fb7a9e8 100644 --- a/runtime/vm/code_generator.cc +++ b/runtime/vm/code_generator.cc
@@ -893,13 +893,12 @@ Function::Handle(target_code.function()); ASSERT(!target_function.IsNull()); if (args.length() == 1) { - ic_data.AddReceiverCheck(Class::Handle(args[0]->clazz()).id(), - target_function); + ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function); } else { GrowableArray<intptr_t> class_ids(args.length()); ASSERT(ic_data.num_args_tested() == args.length()); for (intptr_t i = 0; i < args.length(); i++) { - class_ids.Add(Class::Handle(args[i]->clazz()).id()); + class_ids.Add(args[i]->GetClassId()); } ic_data.AddCheck(class_ids, target_function); } @@ -921,7 +920,7 @@ args.length(), caller_frame->pc(), Class::Handle(receiver.clazz()).ToCString(), - Class::Handle(receiver.clazz()).id(), + receiver.GetClassId(), target_function.ToCString()); } } @@ -1088,8 +1087,8 @@ ASSERT(!target_function.IsNull()); GrowableArray<intptr_t> class_ids(kNumArguments); ASSERT(ic_data.num_args_tested() == kNumArguments); - class_ids.Add(Class::Handle(receiver.clazz()).id()); - class_ids.Add(Class::Handle(arg1.clazz()).id()); + class_ids.Add(receiver.GetClassId()); + class_ids.Add(arg1.GetClassId()); ic_data.AddCheck(class_ids, target_function); } @@ -1771,7 +1770,7 @@ const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); const Object& value = Object::Handle(arguments.ArgAt(1)); - field.UpdateCid(Class::Handle(value.clazz()).id()); + field.UpdateCid(value.GetClassId()); } } // namespace dart
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc index 696dbb2..764dfbc 100644 --- a/runtime/vm/compiler.cc +++ b/runtime/vm/compiler.cc
@@ -121,7 +121,6 @@ bool is_compiled = false; Isolate* isolate = Isolate::Current(); HANDLESCOPE(isolate); - ASSERT(isolate->ic_data_array() == Array::null()); // Must be reset to null. const intptr_t prev_deopt_id = isolate->deopt_id(); isolate->set_deopt_id(0); LongJump* old_base = isolate->long_jump_base(); @@ -135,6 +134,7 @@ TimerScope timer(FLAG_compiler_stats, &CompilerStats::graphbuilder_timer, isolate); + Array& ic_data_array = Array::Handle(); if (optimized) { ASSERT(parsed_function.function().HasCode()); // Extract type feedback before the graph is built, as the graph @@ -145,13 +145,14 @@ FLAG_deoptimization_counter_threshold) { const Code& unoptimized_code = Code::Handle(parsed_function.function().unoptimized_code()); - isolate->set_ic_data_array( - unoptimized_code.ExtractTypeFeedbackArray()); + ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); } } // Build the flow graph. - FlowGraphBuilder builder(parsed_function, NULL); // NULL = not inlining. + FlowGraphBuilder builder(parsed_function, + ic_data_array, + NULL); // NULL = not inlining. flow_graph = builder.BuildGraph(); } @@ -396,7 +397,6 @@ is_compiled = false; } // Reset global isolate state. - isolate->set_ic_data_array(Array::null()); isolate->set_long_jump_base(old_base); isolate->set_deopt_id(prev_deopt_id); return is_compiled;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index aa6738a..0707a20 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc
@@ -1326,7 +1326,7 @@ if (int_obj.IsNull()) { RETURN_TYPE_ERROR(isolate, integer, Integer); } - ASSERT(!BigintOperations::FitsIntoMint(Bigint::Cast(int_obj))); + ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(int_obj))); *fits = false; return Api::Success(isolate); } @@ -1402,8 +1402,8 @@ return Api::Success(isolate); } else { const Bigint& bigint = Bigint::Cast(int_obj); - if (BigintOperations::FitsIntoMint(bigint)) { - *value = BigintOperations::ToMint(bigint); + if (BigintOperations::FitsIntoInt64(bigint)) { + *value = BigintOperations::ToInt64(bigint); return Api::Success(isolate); } } @@ -1949,7 +1949,7 @@ // Check for a non-canonical Mint range value. ASSERT(retval.IsBigint()); const Bigint& bigint = Bigint::Handle(); - if (BigintOperations::FitsIntoMint(bigint)) { + if (BigintOperations::FitsIntoInt64(bigint)) { int64_t bigint_value = bigint.AsInt64Value(); if (bigint_value >= kIntptrMin && bigint_value <= kIntptrMax) { *len = static_cast<intptr_t>(bigint_value); @@ -3934,10 +3934,14 @@ RETURN_TYPE_ERROR(isolate, name, String); } - const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container)); - + // Finalize all classes. + Dart_Handle state = Api::CheckIsolateState(isolate); + if (::Dart_IsError(state)) { + return state; + } Field& field = Field::Handle(isolate); Function& getter = Function::Handle(isolate); + const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container)); if (obj.IsNull()) { return Api::NewError("%s expects argument 'container' to be non-null.", CURRENT_FUNC); @@ -3973,11 +3977,6 @@ return Api::NewHandle(isolate, DartEntry::InvokeFunction(getter, args)); } else if (obj.IsClass()) { - // Finalize all classes. - Dart_Handle state = Api::CheckIsolateState(isolate); - if (::Dart_IsError(state)) { - return state; - } // To access a static field we may need to use the Field or the // getter Function. const Class& cls = Class::Cast(obj); @@ -4000,8 +3999,6 @@ } } else if (obj.IsLibrary()) { - // TODO(turnidge): Do we need to call CheckIsolateState here? - // To access a top-level we may need to use the Field or the // getter Function. The getter function may either be in the // library or in the field's owner class, depending. @@ -4061,6 +4058,11 @@ Instance& value_instance = Instance::Handle(isolate); value_instance ^= value_obj.raw(); + // Finalize all classes. + Dart_Handle state = Api::CheckIsolateState(isolate); + if (::Dart_IsError(state)) { + return state; + } Field& field = Field::Handle(isolate); Function& setter = Function::Handle(isolate); const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index 047df63..6d8626a 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc
@@ -3516,6 +3516,53 @@ } +TEST_CASE(GetField_CheckIsolate) { + const char* kScriptChars = + "class TestClass {\n" + " static int fld2 = 11;\n" + " static void testMain() {\n" + " }\n" + "}\n"; + Dart_Handle result; + int64_t value = 0; + + // Create a test library and Load up a test script in it. + Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); + Dart_Handle cls = Dart_GetClass(lib, NewString("TestClass")); + EXPECT_VALID(cls); + + result = Dart_GetField(cls, NewString("fld2")); + EXPECT_VALID(result); + result = Dart_IntegerToInt64(result, &value); + EXPECT_EQ(11, value); +} + + +TEST_CASE(SetField_CheckIsolate) { + const char* kScriptChars = + "class TestClass {\n" + " static int fld2 = 11;\n" + " static void testMain() {\n" + " }\n" + "}\n"; + Dart_Handle result; + int64_t value = 0; + + // Create a test library and Load up a test script in it. + Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); + Dart_Handle cls = Dart_GetClass(lib, NewString("TestClass")); + EXPECT_VALID(cls); + + result = Dart_SetField(cls, NewString("fld2"), Dart_NewInteger(13)); + EXPECT_VALID(result); + + result = Dart_GetField(cls, NewString("fld2")); + EXPECT_VALID(result); + result = Dart_IntegerToInt64(result, &value); + EXPECT_EQ(13, value); +} + + TEST_CASE(New) { const char* kScriptChars = "class MyClass {\n"
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc index 1b9e361..89ebb10 100644 --- a/runtime/vm/dart_entry.cc +++ b/runtime/vm/dart_entry.cc
@@ -176,17 +176,17 @@ intptr_t ArgumentsDescriptor::count_offset() { - return Array::data_offset() + (kCountIndex * kWordSize); + return Array::element_offset(kCountIndex); } intptr_t ArgumentsDescriptor::positional_count_offset() { - return Array::data_offset() + (kPositionalCountIndex * kWordSize); + return Array::element_offset(kPositionalCountIndex); } intptr_t ArgumentsDescriptor::first_named_entry_offset() { - return Array::data_offset() + (kFirstNamedEntryIndex * kWordSize); + return Array::element_offset(kFirstNamedEntryIndex); }
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index a470b0a..0d80af0 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc
@@ -779,7 +779,6 @@ src_breakpoints_(NULL), code_breakpoints_(NULL), resume_action_(kContinue), - last_bpt_line_(-1), ignore_breakpoints_(false), exc_pause_info_(kNoPauseOnExceptions) { } @@ -1024,8 +1023,6 @@ if (!ShouldPauseOnException(stack_trace, exc)) { return; } - // No single-stepping possible after this pause event. - last_bpt_line_ = -1; ASSERT(stack_trace_ == NULL); stack_trace_ = stack_trace; ASSERT(obj_cache_ == NULL); @@ -1532,31 +1529,19 @@ top_frame->pc()); } - if (!bpt->IsInternal()) { - // This is a user-defined breakpoint so we call the breakpoint - // callback even if it is on the same line as the previous breakpoint. - last_bpt_line_ = -1; - } - - bool notify_frontend = - (last_bpt_line_ < 0) || (last_bpt_line_ != bpt->LineNumber()); - - if (notify_frontend) { - resume_action_ = kContinue; - if (event_handler_ != NULL) { - ASSERT(stack_trace_ == NULL); - ASSERT(obj_cache_ == NULL); - obj_cache_ = new RemoteObjectCache(64); - stack_trace_ = stack_trace; - DebuggerEvent event; - event.type = kBreakpointReached; - ASSERT(stack_trace->Length() > 0); - event.top_frame = stack_trace->ActivationFrameAt(0); - (*event_handler_)(&event); - stack_trace_ = NULL; - obj_cache_ = NULL; // Remote object cache is zone allocated. - last_bpt_line_ = bpt->LineNumber(); - } + resume_action_ = kContinue; + if (event_handler_ != NULL) { + ASSERT(stack_trace_ == NULL); + ASSERT(obj_cache_ == NULL); + obj_cache_ = new RemoteObjectCache(64); + stack_trace_ = stack_trace; + DebuggerEvent event; + event.type = kBreakpointReached; + ASSERT(stack_trace->Length() > 0); + event.top_frame = stack_trace->ActivationFrameAt(0); + (*event_handler_)(&event); + stack_trace_ = NULL; + obj_cache_ = NULL; // Remote object cache is zone allocated. } Function& currently_instrumented_func = Function::Handle(); @@ -1656,7 +1641,6 @@ if (func_to_instrument.IsNull() || (func_to_instrument.raw() != currently_instrumented_func.raw())) { - last_bpt_line_ = -1; RemoveInternalBreakpoints(); // *bpt is now invalid. if (!func_to_instrument.IsNull()) { InstrumentForStepping(func_to_instrument);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h index d184d3b..9df08bd 100644 --- a/runtime/vm/debugger.h +++ b/runtime/vm/debugger.h
@@ -373,10 +373,6 @@ // Tells debugger what to do when resuming execution after a breakpoint. ResumeAction resume_action_; - // If >= 0, last_bpt_line contains the line number of the last breakpoint - // location for which the breakpoint callback function was called. - intptr_t last_bpt_line_; - // Do not call back to breakpoint handler if this flag is set. // Effectively this means ignoring breakpoints. Set when Dart code may // be run as a side effect of getting values of fields.
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc index 43a80d4..123db7c 100644 --- a/runtime/vm/debugger_api_impl.cc +++ b/runtime/vm/debugger_api_impl.cc
@@ -492,7 +492,7 @@ DARTSCOPE(isolate); UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in); CHECK_NOT_NULL(class_id); - *class_id = Class::Handle(obj.clazz()).id(); + *class_id = obj.GetClassId(); return Api::True(isolate); }
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc index a10bbeb..6810a61b 100644 --- a/runtime/vm/debugger_api_impl_test.cc +++ b/runtime/vm/debugger_api_impl_test.cc
@@ -361,10 +361,12 @@ "f1", "foo", "X.X.", + "X.X.", "foo", "X.kvmk", "f2", "X.kvmk", + "X.kvmk", "foo", "main" }; @@ -418,11 +420,7 @@ LoadScript(kScriptChars); Dart_SetPausedEventHandler(&TestStepIntoHandler); - // Set a breakpoint in function f1, then repeatedly step out until - // we get to main. We should see one breakpoint each in f1, - // foo, main, but not in f2. SetBreakpointAtEntry("", "main"); - breakpoint_hit = false; breakpoint_hit_counter = 0; Dart_Handle retval = Invoke("main");
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index bd43c7a..d27f76c 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc
@@ -42,8 +42,10 @@ FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function, + const Array& ic_data_array, InlineExitCollector* exit_collector) : parsed_function_(parsed_function), + ic_data_array_(ic_data_array), num_copied_params_(parsed_function.num_copied_params()), // All parameters are copied if any parameter is. num_non_copied_params_((num_copied_params_ == 0) @@ -926,7 +928,8 @@ node->kind(), arguments, Array::ZoneHandle(), - 2); + 2, + owner()->ic_data_array()); ReturnDefinition(call); } @@ -1168,7 +1171,8 @@ node->kind(), arguments, Array::ZoneHandle(), // No argument names. - kNumArgsChecked); + kNumArgsChecked, + owner()->ic_data_array()); ReturnDefinition(call); } @@ -1237,7 +1241,8 @@ node->kind(), arguments, Array::ZoneHandle(), // No argument names. - kNumArgsChecked); + kNumArgsChecked, + owner()->ic_data_array()); ReturnDefinition(call); } } @@ -1282,7 +1287,8 @@ node->token_pos(), Token::kEQ, for_left_value.value(), - for_right_value.value()); + for_right_value.value(), + owner()->ic_data_array()); if (node->kind() == Token::kEQ) { ReturnDefinition(comp); } else { @@ -1295,7 +1301,8 @@ node->token_pos(), node->kind(), for_left_value.value(), - for_right_value.value()); + for_right_value.value(), + owner()->ic_data_array()); ReturnDefinition(comp); } return; @@ -1310,7 +1317,8 @@ RelationalOpInstr* comp = new RelationalOpInstr(node->token_pos(), node->kind(), for_left_value.value(), - for_right_value.value()); + for_right_value.value(), + owner()->ic_data_array()); ReturnDefinition(comp); } @@ -1345,7 +1353,8 @@ node->kind(), arguments, Array::ZoneHandle(), - 1); + 1, + owner()->ic_data_array()); ReturnDefinition(call); } @@ -1913,7 +1922,9 @@ InstanceCallInstr* call = new InstanceCallInstr( node->token_pos(), node->function_name(), Token::kILLEGAL, arguments, - node->arguments()->names(), 1); + node->arguments()->names(), + 1, + owner()->ic_data_array()); ReturnDefinition(call); } @@ -2017,32 +2028,37 @@ // In checked mode, if the type arguments are uninstantiated, they may need to // be checked against declared bounds at run time. - Definition* allocate_comp = NULL; + Definition* allocation = NULL; if (FLAG_enable_type_checks && requires_type_arguments && !node->type_arguments().IsNull() && !node->type_arguments().IsInstantiated() && node->type_arguments().IsBounded()) { - Value* type_arguments = NULL; - Value* instantiator = NULL; - BuildConstructorTypeArguments(node, &type_arguments, &instantiator, NULL); + ZoneGrowableArray<PushArgumentInstr*>* allocate_arguments = + new ZoneGrowableArray<PushArgumentInstr*>(4); + // Argument 1: Empty argument slot for return value. + Value* null_val = Bind(new ConstantInstr(Object::ZoneHandle())); + allocate_arguments->Add(PushArgument(null_val)); + // Argument 2: Class. + Value* cls_val = + Bind(new ConstantInstr(Class::ZoneHandle(node->constructor().Owner()))); + allocate_arguments->Add(PushArgument(cls_val)); + // Build arguments 3 and 4. + BuildConstructorTypeArguments(node, allocate_arguments); // The uninstantiated type arguments cannot be verified to be within their // bounds at compile time, so verify them at runtime. - allocate_comp = new AllocateObjectWithBoundsCheckInstr(node, - type_arguments, - instantiator); + allocation = new AllocateObjectWithBoundsCheckInstr(node); } else { ZoneGrowableArray<PushArgumentInstr*>* allocate_arguments = new ZoneGrowableArray<PushArgumentInstr*>(); - if (requires_type_arguments) { - BuildConstructorTypeArguments(node, NULL, NULL, allocate_arguments); + BuildConstructorTypeArguments(node, allocate_arguments); } - allocate_comp = new AllocateObjectInstr(node, allocate_arguments); + allocation = new AllocateObjectInstr(node, allocate_arguments); } - return Bind(allocate_comp); + return Bind(allocation); } @@ -2249,73 +2265,69 @@ void EffectGraphVisitor::BuildConstructorTypeArguments( ConstructorCallNode* node, - Value** type_arguments, - Value** instantiator, ZoneGrowableArray<PushArgumentInstr*>* call_arguments) { const Class& cls = Class::ZoneHandle(node->constructor().Owner()); ASSERT(cls.HasTypeArguments() && !node->constructor().IsFactory()); if (node->type_arguments().IsNull() || node->type_arguments().IsInstantiated()) { Value* type_arguments_val = Bind(new ConstantInstr(node->type_arguments())); - if (call_arguments != NULL) { - ASSERT(type_arguments == NULL); - call_arguments->Add(PushArgument(type_arguments_val)); - } else { - ASSERT(type_arguments != NULL); - *type_arguments = type_arguments_val; - } + call_arguments->Add(PushArgument(type_arguments_val)); // No instantiator required. Value* instantiator_val = Bind(new ConstantInstr( Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator)))); - if (call_arguments != NULL) { - ASSERT(instantiator == NULL); - call_arguments->Add(PushArgument(instantiator_val)); - } else { - ASSERT(instantiator != NULL); - *instantiator = instantiator_val; - } + call_arguments->Add(PushArgument(instantiator_val)); return; } + // The type arguments are uninstantiated. We use expression_temp_var to save - // the instantiator type arguments becuase they have two uses. + // the instantiator type arguments because they have two uses. ASSERT(owner()->parsed_function().expression_temp_var() != NULL); const LocalVariable& temp = *owner()->parsed_function().expression_temp_var(); const Class& instantiator_class = Class::Handle( owner()->parsed_function().function().Owner()); - Value* instantiator_type_arguments = BuildInstantiatorTypeArguments( + Value* type_arguments_val = BuildInstantiatorTypeArguments( node->token_pos(), instantiator_class, NULL); - Value* stored_instantiator = - Bind(BuildStoreTemp(temp, instantiator_type_arguments)); - Value* type_arguments_val = Bind( - new ExtractConstructorTypeArgumentsInstr( - node->token_pos(), - node->type_arguments(), - instantiator_class, - stored_instantiator)); + const bool use_instantiator_type_args = + node->type_arguments().IsUninstantiatedIdentity() || + node->type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class); - if (call_arguments != NULL) { - ASSERT(type_arguments == NULL); - call_arguments->Add(PushArgument(type_arguments_val)); - } else { - ASSERT(type_arguments != NULL); - *type_arguments = type_arguments_val; + if (!use_instantiator_type_args) { + const intptr_t len = node->type_arguments().Length(); + if (node->type_arguments().IsRawInstantiatedRaw(len)) { + type_arguments_val = + Bind(BuildStoreTemp(temp, type_arguments_val)); + type_arguments_val = Bind( + new ExtractConstructorTypeArgumentsInstr( + node->token_pos(), + node->type_arguments(), + instantiator_class, + type_arguments_val)); + } else { + Do(BuildStoreTemp(temp, type_arguments_val)); + type_arguments_val = Bind(new ConstantInstr(node->type_arguments())); + } } + call_arguments->Add(PushArgument(type_arguments_val)); - Value* load_instantiator = Bind(BuildLoadLocal(temp)); - Value* instantiator_val = - Bind(new ExtractConstructorInstantiatorInstr(node, - instantiator_class, - load_instantiator)); - - if (call_arguments != NULL) { - ASSERT(instantiator == NULL); - call_arguments->Add(PushArgument(instantiator_val)); + Value* instantiator_val = NULL; + if (!use_instantiator_type_args) { + instantiator_val = Bind(BuildLoadLocal(temp)); + const intptr_t len = node->type_arguments().Length(); + if (node->type_arguments().IsRawInstantiatedRaw(len)) { + instantiator_val = + Bind(new ExtractConstructorInstantiatorInstr(node, + instantiator_class, + instantiator_val)); + } } else { - ASSERT(instantiator != NULL); - *instantiator = instantiator_val; + // No instantiator required. + instantiator_val = Bind(new ConstantInstr( + Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator)))); } + call_arguments->Add(PushArgument(instantiator_val)); } @@ -2357,8 +2369,12 @@ const String& name = String::ZoneHandle(Field::GetterSymbol(node->field_name())); InstanceCallInstr* call = new InstanceCallInstr( - node->token_pos(), name, Token::kGET, - arguments, Array::ZoneHandle(), 1); + node->token_pos(), + name, + Token::kGET, + arguments, Array::ZoneHandle(), + 1, + owner()->ic_data_array()); ReturnDefinition(call); } @@ -2397,7 +2413,8 @@ Token::kSET, arguments, Array::ZoneHandle(), - 2); // Checked arg count. + 2, // Checked arg count. + owner()->ic_data_array()); ReturnDefinition(call); } @@ -2413,7 +2430,8 @@ Token::kSET, arguments, Array::ZoneHandle(), - 2)); // Checked argument count. + 2, // Checked argument count. + owner()->ic_data_array())); ReturnDefinition(BuildLoadExprTemp()); } @@ -2778,7 +2796,8 @@ Token::kINDEX, arguments, Array::ZoneHandle(), - checked_argument_count); + checked_argument_count, + owner()->ic_data_array()); ReturnDefinition(load); } } @@ -2877,7 +2896,8 @@ Token::kASSIGN_INDEX, arguments, Array::ZoneHandle(), - checked_argument_count); + checked_argument_count, + owner()->ic_data_array()); if (result_is_needed) { Do(store); return BuildLoadExprTemp();
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h index 950224f..59a752d 100644 --- a/runtime/vm/flow_graph_builder.h +++ b/runtime/vm/flow_graph_builder.h
@@ -102,11 +102,13 @@ public: // The inlining context is NULL if not inlining. FlowGraphBuilder(const ParsedFunction& parsed_function, + const Array& ic_data_array, InlineExitCollector* exit_collector); FlowGraph* BuildGraph(); const ParsedFunction& parsed_function() const { return parsed_function_; } + const Array& ic_data_array() const { return ic_data_array_; } void Bailout(const char* reason); @@ -147,6 +149,7 @@ } const ParsedFunction& parsed_function_; + const Array& ic_data_array_; const intptr_t num_copied_params_; const intptr_t num_non_copied_params_; @@ -263,8 +266,6 @@ // May be called only if allocating an object of a parameterized class. void BuildConstructorTypeArguments( ConstructorCallNode* node, - Value** type_arguments, - Value** instantiator, ZoneGrowableArray<PushArgumentInstr*>* call_arguments); void BuildTypecheckPushArguments(
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc index 7b0e38b..a5d50b1 100644 --- a/runtime/vm/flow_graph_compiler.cc +++ b/runtime/vm/flow_graph_compiler.cc
@@ -219,7 +219,7 @@ continue; } - entry->PrepareEntry(this); + entry->EmitNativeCode(this); // Compile all successors until an exit, branch, or a block entry. for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { Instruction* instr = it.Current(); @@ -338,9 +338,10 @@ void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id, intptr_t token_pos) { ASSERT(is_optimizing()); - CompilerDeoptInfo* info = new CompilerDeoptInfo(deopt_id, kDeoptAtCall); - ASSERT(pending_deoptimization_env_ != NULL); - info->set_deoptimization_env(pending_deoptimization_env_); + CompilerDeoptInfo* info = + new CompilerDeoptInfo(deopt_id, + kDeoptAtCall, + pending_deoptimization_env_); info->set_pc_offset(assembler()->CodeSize()); deopt_infos_.Add(info); } @@ -399,11 +400,11 @@ Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id, DeoptReasonId reason) { - CompilerDeoptInfoWithStub* stub = - new CompilerDeoptInfoWithStub(deopt_id, reason); ASSERT(is_optimizing_); - ASSERT(pending_deoptimization_env_ != NULL); - stub->set_deoptimization_env(pending_deoptimization_env_); + CompilerDeoptInfoWithStub* stub = + new CompilerDeoptInfoWithStub(deopt_id, + reason, + pending_deoptimization_env_); deopt_infos_.Add(stub); return stub->entry_label(); }
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h index f301879..0cb7843 100644 --- a/runtime/vm/flow_graph_compiler.h +++ b/runtime/vm/flow_graph_compiler.h
@@ -107,11 +107,15 @@ // For deoptimization before instruction use class CompilerDeoptInfoWithStub. class CompilerDeoptInfo : public ZoneAllocated { public: - CompilerDeoptInfo(intptr_t deopt_id, DeoptReasonId reason) + CompilerDeoptInfo(intptr_t deopt_id, + DeoptReasonId reason, + Environment* deopt_env) : pc_offset_(-1), deopt_id_(deopt_id), reason_(reason), - deoptimization_env_(NULL) {} + deopt_env_(deopt_env) { + ASSERT(deopt_env != NULL); + } RawDeoptInfo* CreateDeoptInfo(FlowGraphCompiler* compiler, DeoptInfoBuilder* builder); @@ -124,11 +128,8 @@ void set_pc_offset(intptr_t offset) { pc_offset_ = offset; } intptr_t deopt_id() const { return deopt_id_; } - DeoptReasonId reason() const { return reason_; } - - const Environment* deoptimization_env() const { return deoptimization_env_; } - void set_deoptimization_env(Environment* env) { deoptimization_env_ = env; } + const Environment* deopt_env() const { return deopt_env_; } private: void EmitMaterializations(Environment* env, DeoptInfoBuilder* builder); @@ -139,7 +140,7 @@ intptr_t pc_offset_; const intptr_t deopt_id_; const DeoptReasonId reason_; - Environment* deoptimization_env_; + Environment* deopt_env_; DISALLOW_COPY_AND_ASSIGN(CompilerDeoptInfo); }; @@ -148,8 +149,9 @@ class CompilerDeoptInfoWithStub : public CompilerDeoptInfo { public: CompilerDeoptInfoWithStub(intptr_t deopt_id, - DeoptReasonId reason) - : CompilerDeoptInfo(deopt_id, reason), entry_label_() { + DeoptReasonId reason, + Environment* deopt_env) + : CompilerDeoptInfo(deopt_id, reason, deopt_env), entry_label_() { ASSERT(reason != kDeoptAtCall); }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc index f7db7fe..d1e17a8 100644 --- a/runtime/vm/flow_graph_compiler_arm.cc +++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -45,17 +45,17 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, DeoptInfoBuilder* builder) { - if (deoptimization_env_ == NULL) return DeoptInfo::null(); + if (deopt_env_ == NULL) return DeoptInfo::null(); intptr_t stack_height = compiler->StackSize(); - AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height); + AllocateIncomingParametersRecursive(deopt_env_, &stack_height); intptr_t slot_ix = 0; - Environment* current = deoptimization_env_; + Environment* current = deopt_env_; // Emit all kMaterializeObject instructions describing objects to be // materialized on the deoptimization as a prefix to the deoptimization info. - EmitMaterializations(deoptimization_env_, builder); + EmitMaterializations(deopt_env_, builder); // The real frame starts here. builder->MarkFrameStart(); @@ -150,7 +150,7 @@ __ Bind(entry_label()); if (FLAG_trap_on_deoptimization) __ bkpt(0); - ASSERT(deoptimization_env() != NULL); + ASSERT(deopt_env() != NULL); __ BranchLink(&StubCode::DeoptimizeLabel()); set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc index a4af2f8..aa731d9 100644 --- a/runtime/vm/flow_graph_compiler_ia32.cc +++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -48,17 +48,17 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, DeoptInfoBuilder* builder) { - if (deoptimization_env_ == NULL) return DeoptInfo::null(); + if (deopt_env_ == NULL) return DeoptInfo::null(); intptr_t stack_height = compiler->StackSize(); - AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height); + AllocateIncomingParametersRecursive(deopt_env_, &stack_height); intptr_t slot_ix = 0; - Environment* current = deoptimization_env_; + Environment* current = deopt_env_; // Emit all kMaterializeObject instructions describing objects to be // materialized on the deoptimization as a prefix to the deoptimization info. - EmitMaterializations(deoptimization_env_, builder); + EmitMaterializations(deopt_env_, builder); // The real frame starts here. builder->MarkFrameStart(); @@ -148,7 +148,7 @@ __ Bind(entry_label()); if (FLAG_trap_on_deoptimization) __ int3(); - ASSERT(deoptimization_env() != NULL); + ASSERT(deopt_env() != NULL); __ call(&StubCode::DeoptimizeLabel()); set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc index 27f6d64..4b88a5f 100644 --- a/runtime/vm/flow_graph_compiler_mips.cc +++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -60,7 +60,7 @@ __ Bind(entry_label()); if (FLAG_trap_on_deoptimization) __ break_(0); - ASSERT(deoptimization_env() != NULL); + ASSERT(deopt_env() != NULL); __ BranchLink(&StubCode::DeoptimizeLabel()); set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc index 2ae5235..dd764ea 100644 --- a/runtime/vm/flow_graph_compiler_x64.cc +++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -46,17 +46,17 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, DeoptInfoBuilder* builder) { - if (deoptimization_env_ == NULL) return DeoptInfo::null(); + if (deopt_env_ == NULL) return DeoptInfo::null(); intptr_t stack_height = compiler->StackSize(); - AllocateIncomingParametersRecursive(deoptimization_env_, &stack_height); + AllocateIncomingParametersRecursive(deopt_env_, &stack_height); intptr_t slot_ix = 0; - Environment* current = deoptimization_env_; + Environment* current = deopt_env_; // Emit all kMaterializeObject instructions describing objects to be // materialized on the deoptimization as a prefix to the deoptimization info. - EmitMaterializations(deoptimization_env_, builder); + EmitMaterializations(deopt_env_, builder); // The real frame starts here. builder->MarkFrameStart(); @@ -146,7 +146,7 @@ __ Bind(entry_label()); if (FLAG_trap_on_deoptimization) __ int3(); - ASSERT(deoptimization_env() != NULL); + ASSERT(deopt_env() != NULL); __ call(&StubCode::DeoptimizeLabel()); set_pc_offset(assem->CodeSize());
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc index d3f7d7d..541b3f6 100644 --- a/runtime/vm/flow_graph_inliner.cc +++ b/runtime/vm/flow_graph_inliner.cc
@@ -465,9 +465,6 @@ } Isolate* isolate = Isolate::Current(); - // Save and clear IC data. - const Array& prev_ic_data = Array::Handle(isolate->ic_data_array()); - isolate->set_ic_data_array(Array::null()); // Save and clear deopt id. const intptr_t prev_deopt_id = isolate->deopt_id(); isolate->set_deopt_id(0); @@ -487,16 +484,17 @@ } // Load IC data for the callee. + Array& ic_data_array = Array::Handle(); if (function.HasCode()) { const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); - isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); + ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); } // Build the callee graph. InlineExitCollector* exit_collector = new InlineExitCollector(caller_graph_, call); - FlowGraphBuilder builder(*parsed_function, exit_collector); + FlowGraphBuilder builder(*parsed_function, ic_data_array, exit_collector); builder.SetInitialBlockId(caller_graph_->max_block_id()); FlowGraph* callee_graph; { @@ -597,7 +595,6 @@ } isolate->set_long_jump_base(base); isolate->set_deopt_id(prev_deopt_id); - isolate->set_ic_data_array(prev_ic_data.raw()); TRACE_INLINING(OS::Print(" Bailout: heuristics with " "code size: %"Pd", " "call sites: %"Pd", " @@ -621,7 +618,6 @@ inlined_size_ += size; isolate->set_long_jump_base(base); isolate->set_deopt_id(prev_deopt_id); - isolate->set_ic_data_array(prev_ic_data.raw()); call_data->callee_graph = callee_graph; call_data->parameter_stubs = param_stubs; @@ -634,7 +630,6 @@ isolate->object_store()->clear_sticky_error(); isolate->set_long_jump_base(base); isolate->set_deopt_id(prev_deopt_id); - isolate->set_ic_data_array(prev_ic_data.raw()); TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); return false; }
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc index f818958..2da6e02 100644 --- a/runtime/vm/flow_graph_optimizer.cc +++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5984,7 +5984,8 @@ new EqualityCompareInstr(equality_compare->token_pos(), comparison->kind(), left, - right); + right, + Array::Handle()); new_equality_compare->set_ic_data(equality_compare->ic_data()); new_comparison = new_equality_compare; } else { @@ -5994,7 +5995,8 @@ new RelationalOpInstr(relational_op->token_pos(), comparison->kind(), left, - right); + right, + Array::Handle()); new_relational_op->set_ic_data(relational_op->ic_data()); new_comparison = new_relational_op; }
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc index f709124..d096872 100644 --- a/runtime/vm/flow_graph_type_propagator.cc +++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -736,7 +736,7 @@ if (value().IsInstance()) { return CompileType::Create( - Class::Handle(value().clazz()).id(), + value().GetClassId(), AbstractType::ZoneHandle(Instance::Cast(value()).GetType())); } else { ASSERT(value().IsAbstractTypeArguments());
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index 91eca39..ed56e35 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc
@@ -42,6 +42,17 @@ } +ICData* Instruction::GetICData(const Array& ic_data_array) const { + ICData& ic_data = ICData::ZoneHandle(); + // The deopt_id can be outside the range of the IC data array for + // computations added in the optimizing compiler. + if (!ic_data_array.IsNull() && (deopt_id_ < ic_data_array.Length())) { + ic_data ^= ic_data_array.At(deopt_id_); + } + return &ic_data; +} + + intptr_t Instruction::Hashcode() const { intptr_t result = tag(); for (intptr_t i = 0; i < InputCount(); ++i) { @@ -1396,56 +1407,13 @@ } -// Shared code generation methods (EmitNativeCode, MakeLocationSummary, and -// PrepareEntry). Only assembly code that can be shared across all architectures -// can be used. Machine specific register allocation and code generation -// is located in intermediate_language_<arch>.cc +// Shared code generation methods (EmitNativeCode and +// MakeLocationSummary). Only assembly code that can be shared across all +// architectures can be used. Machine specific register allocation and code +// generation is located in intermediate_language_<arch>.cc #define __ compiler->assembler()-> -void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { - // Nothing to do. -} - - -void JoinEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { - if (!compiler->is_optimizing()) { - compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, - deopt_id_, - Scanner::kDummyTokenIndex); - } - __ Bind(compiler->GetJumpLabel(this)); - if (HasParallelMove()) { - compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); - } -} - - -void TargetEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { - if (!compiler->is_optimizing()) { - compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, - deopt_id_, - Scanner::kDummyTokenIndex); - } - __ Bind(compiler->GetJumpLabel(this)); - if (HasParallelMove()) { - compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); - } -} - - -void CatchBlockEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { - __ Bind(compiler->GetJumpLabel(this)); - compiler->AddExceptionHandler(catch_try_index(), - try_index(), - compiler->assembler()->CodeSize(), - catch_handler_types_); - if (HasParallelMove()) { - compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); - } -} - - LocationSummary* GraphEntryInstr::MakeLocationSummary() const { UNREACHABLE(); return NULL; @@ -1453,7 +1421,7 @@ void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - UNREACHABLE(); + // Nothing to do. } @@ -1464,7 +1432,15 @@ void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - UNREACHABLE(); + if (!compiler->is_optimizing()) { + compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, + deopt_id_, + Scanner::kDummyTokenIndex); + } + __ Bind(compiler->GetJumpLabel(this)); + if (HasParallelMove()) { + compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); + } } @@ -1475,7 +1451,15 @@ void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - UNREACHABLE(); + if (!compiler->is_optimizing()) { + compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, + deopt_id_, + Scanner::kDummyTokenIndex); + } + __ Bind(compiler->GetJumpLabel(this)); + if (HasParallelMove()) { + compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); + } } @@ -1486,7 +1470,14 @@ void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - UNREACHABLE(); + __ Bind(compiler->GetJumpLabel(this)); + compiler->AddExceptionHandler(catch_try_index(), + try_index(), + compiler->assembler()->CodeSize(), + catch_handler_types_); + if (HasParallelMove()) { + compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); + } }
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index f881959..42c8470 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h
@@ -646,6 +646,8 @@ return deopt_id_; } + ICData* GetICData(const Array& ic_data_array) const; + bool IsBlockEntry() { return (AsBlockEntry() != NULL); } virtual BlockEntryInstr* AsBlockEntry() { return NULL; } @@ -1070,7 +1072,6 @@ virtual intptr_t PredecessorCount() const = 0; virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0; - virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0; intptr_t preorder_number() const { return preorder_number_; } void set_preorder_number(intptr_t number) { preorder_number_ = number; } @@ -1292,8 +1293,6 @@ CatchBlockEntryInstr* GetCatchEntry(intptr_t index); - virtual void PrepareEntry(FlowGraphCompiler* compiler); - GrowableArray<Definition*>* initial_definitions() { return &initial_definitions_; } @@ -1359,8 +1358,6 @@ ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; } - virtual void PrepareEntry(FlowGraphCompiler* compiler); - void InsertPhi(intptr_t var_index, intptr_t var_count); void RemoveDeadPhis(Definition* replacement); @@ -1429,8 +1426,6 @@ return predecessor_; } - virtual void PrepareEntry(FlowGraphCompiler* compiler); - virtual void PrintTo(BufferFormatter* f) const; private: @@ -1478,8 +1473,6 @@ return &initial_definitions_; } - virtual void PrepareEntry(FlowGraphCompiler* compiler); - virtual void PrintTo(BufferFormatter* f) const; private: @@ -2600,8 +2593,9 @@ Token::Kind token_kind, ZoneGrowableArray<PushArgumentInstr*>* arguments, const Array& argument_names, - intptr_t checked_argument_count) - : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), + intptr_t checked_argument_count, + const Array& ic_data_array) + : ic_data_(GetICData(ic_data_array)), token_pos_(token_pos), function_name_(function_name), token_kind_(token_kind), @@ -2842,12 +2836,12 @@ EqualityCompareInstr(intptr_t token_pos, Token::Kind kind, Value* left, - Value* right) + Value* right, + const Array& ic_data_array) : ComparisonInstr(kind, left, right), + ic_data_(GetICData(ic_data_array)), token_pos_(token_pos), receiver_class_id_(kIllegalCid) { - // deopt_id() checks receiver_class_id_ value. - ic_data_ = Isolate::Current()->GetICDataForDeoptId(deopt_id()); ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); } @@ -2921,12 +2915,12 @@ RelationalOpInstr(intptr_t token_pos, Token::Kind kind, Value* left, - Value* right) + Value* right, + const Array& ic_data_array) : ComparisonInstr(kind, left, right), + ic_data_(GetICData(ic_data_array)), token_pos_(token_pos), operands_class_id_(kIllegalCid) { - // deopt_id() checks operands_class_id_ value. - ic_data_ = Isolate::Current()->GetICDataForDeoptId(deopt_id()); ASSERT(Token::IsRelationalOperator(kind)); } @@ -3719,18 +3713,16 @@ }; -class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<2> { +class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<0> { public: - AllocateObjectWithBoundsCheckInstr(ConstructorCallNode* node, - Value* type_arguments, - Value* instantiator) + explicit AllocateObjectWithBoundsCheckInstr(ConstructorCallNode* node) : ast_node_(*node) { - SetInputAt(0, type_arguments); - SetInputAt(1, instantiator); } DECLARE_INSTRUCTION(AllocateObjectWithBoundsCheck) + virtual intptr_t ArgumentCount() const { return 4; } + const Function& constructor() const { return ast_node_.constructor(); } intptr_t token_pos() const { return ast_node_.token_pos(); }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc index 9d93594..ecbaf96 100644 --- a/runtime/vm/intermediate_language_arm.cc +++ b/runtime/vm/intermediate_language_arm.cc
@@ -1405,9 +1405,9 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { const intptr_t kNumInputs = 2; - const intptr_t num_temps = 0; + const intptr_t kNumTemps = 0; LocationSummary* summary = - new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresRegister()); summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister() @@ -1610,27 +1610,24 @@ // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity() && - !type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments. - Label type_arguments_instantiated; - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - __ CompareImmediate(instantiator_reg, - reinterpret_cast<intptr_t>(Object::null())); - __ b(&type_arguments_instantiated, EQ); - } - // Instantiate non-null type arguments. - // In the non-factory case, we rely on the allocation stub to - // instantiate the type arguments. - __ LoadObject(result_reg, type_arguments()); - // result_reg: uninstantiated type arguments. - __ Bind(&type_arguments_instantiated); - } - ASSERT(instantiator_reg == result_reg); + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments. + Label type_arguments_instantiated; + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + __ CompareImmediate(instantiator_reg, + reinterpret_cast<intptr_t>(Object::null())); + __ b(&type_arguments_instantiated, EQ); + // Instantiate non-null type arguments. + // In the non-factory case, we rely on the allocation stub to + // instantiate the type arguments. + __ LoadObject(result_reg, type_arguments()); + // result_reg: uninstantiated type arguments. + __ Bind(&type_arguments_instantiated); + // result_reg: uninstantiated or instantiated type arguments. } @@ -1654,30 +1651,23 @@ // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity() || - type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // The instantiator was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ LoadImmediate(instantiator_reg, - Smi::RawValue(StubCode::kNoInstantiator)); - } else { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments and do not pass the instantiator. - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - Label instantiator_not_null; - __ CompareImmediate(instantiator_reg, - reinterpret_cast<intptr_t>(Object::null())); - __ b(&instantiator_not_null, NE); - // Null was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ LoadImmediate(instantiator_reg, - Smi::RawValue(StubCode::kNoInstantiator)); - __ Bind(&instantiator_not_null); - } - } + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments and do not pass the instantiator. + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + Label instantiator_not_null; + __ CompareImmediate(instantiator_reg, + reinterpret_cast<intptr_t>(Object::null())); + __ b(&instantiator_not_null, NE); + // Null was used in VisitExtractConstructorTypeArguments as the + // instantiated type arguments, no proper instantiator needed. + __ LoadImmediate(instantiator_reg, + Smi::RawValue(StubCode::kNoInstantiator)); + __ Bind(&instantiator_not_null); // instantiator_reg: instantiator or kNoInstantiator. } @@ -2640,9 +2630,9 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - // Add deoptimization descriptor for deoptimizing instructions - // that may be inserted before this instruction. if (!compiler->is_optimizing()) { + // Add deoptimization descriptor for deoptimizing instructions that may + // be inserted before this instruction. compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, GetDeoptId(), 0); // No token position.
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index 8e43726..6569c52 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1704,9 +1704,9 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { const intptr_t kNumInputs = 2; - const intptr_t num_temps = 0; + const intptr_t kNumTemps = 0; LocationSummary* summary = - new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresRegister()); summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister() @@ -1828,37 +1828,19 @@ LocationSummary* AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const { - const intptr_t kNumInputs = 2; - const intptr_t kNumTemps = 0; - LocationSummary* locs = - new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(EAX)); - locs->set_in(1, Location::RegisterLocation(ECX)); - locs->set_out(Location::RegisterLocation(EAX)); - return locs; + return MakeCallSummary(); } void AllocateObjectWithBoundsCheckInstr::EmitNativeCode( FlowGraphCompiler* compiler) { - const Class& cls = Class::ZoneHandle(constructor().Owner()); - Register type_arguments = locs()->in(0).reg(); - Register instantiator_type_arguments = locs()->in(1).reg(); - Register result = locs()->out().reg(); - - // Push the result place holder initialized to NULL. - __ PushObject(Object::ZoneHandle()); - __ PushObject(cls); - __ pushl(type_arguments); - __ pushl(instantiator_type_arguments); compiler->GenerateCallRuntime(token_pos(), deopt_id(), kAllocateObjectWithBoundsCheckRuntimeEntry, locs()); - // Pop instantiator type arguments, type arguments, and class. - // source location. __ Drop(3); - __ popl(result); // Pop new instance. + ASSERT(locs()->out().reg() == EAX); + __ popl(EAX); // Pop new instance. } @@ -1947,28 +1929,25 @@ // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity() && - !type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments. - Label type_arguments_instantiated; - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - const Immediate& raw_null = - Immediate(reinterpret_cast<intptr_t>(Object::null())); - __ cmpl(instantiator_reg, raw_null); - __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); - } - // Instantiate non-null type arguments. - // In the non-factory case, we rely on the allocation stub to - // instantiate the type arguments. - __ LoadObject(result_reg, type_arguments()); - // result_reg: uninstantiated type arguments. - __ Bind(&type_arguments_instantiated); - } - ASSERT(instantiator_reg == result_reg); + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments. + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + Label type_arguments_instantiated; + const Immediate& raw_null = + Immediate(reinterpret_cast<intptr_t>(Object::null())); + __ cmpl(instantiator_reg, raw_null); + __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); + // Instantiate non-null type arguments. + // In the non-factory case, we rely on the allocation stub to + // instantiate the type arguments. + __ LoadObject(result_reg, type_arguments()); + // result_reg: uninstantiated type arguments. + + __ Bind(&type_arguments_instantiated); // result_reg: uninstantiated or instantiated type arguments. } @@ -1992,31 +1971,24 @@ // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity() || - type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // The instantiator was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ movl(instantiator_reg, - Immediate(Smi::RawValue(StubCode::kNoInstantiator))); - } else { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments and do not pass the instantiator. - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - const Immediate& raw_null = - Immediate(reinterpret_cast<intptr_t>(Object::null())); - Label instantiator_not_null; - __ cmpl(instantiator_reg, raw_null); - __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); - // Null was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ movl(instantiator_reg, - Immediate(Smi::RawValue(StubCode::kNoInstantiator))); - __ Bind(&instantiator_not_null); - } - } + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments and do not pass the instantiator. + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + const Immediate& raw_null = + Immediate(reinterpret_cast<intptr_t>(Object::null())); + Label instantiator_not_null; + __ cmpl(instantiator_reg, raw_null); + __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); + // Null was used in VisitExtractConstructorTypeArguments as the + // instantiated type arguments, no proper instantiator needed. + __ movl(instantiator_reg, + Immediate(Smi::RawValue(StubCode::kNoInstantiator))); + __ Bind(&instantiator_not_null); // instantiator_reg: instantiator or kNoInstantiator. } @@ -4290,9 +4262,9 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - // Add deoptimization descriptor for deoptimizing instructions - // that may be inserted before this instruction. if (!compiler->is_optimizing()) { + // Add deoptimization descriptor for deoptimizing instructions that may + // be inserted before this instruction. compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, GetDeoptId(), 0); // No token position.
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc index c07ff89..f9e270b 100644 --- a/runtime/vm/intermediate_language_mips.cc +++ b/runtime/vm/intermediate_language_mips.cc
@@ -1342,9 +1342,9 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { const intptr_t kNumInputs = 2; - const intptr_t num_temps = 0; + const intptr_t kNumTemps = 0; LocationSummary* summary = - new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresRegister()); summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister() @@ -1556,27 +1556,24 @@ // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity() && - !type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments. - Label type_arguments_instantiated; - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - __ BranchEqual(instantiator_reg, - reinterpret_cast<intptr_t>(Object::null()), - &type_arguments_instantiated); - } - // Instantiate non-null type arguments. - // In the non-factory case, we rely on the allocation stub to - // instantiate the type arguments. - __ LoadObject(result_reg, type_arguments()); - // result_reg: uninstantiated type arguments. - __ Bind(&type_arguments_instantiated); - } - ASSERT(instantiator_reg == result_reg); + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments. + Label type_arguments_instantiated; + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + __ BranchEqual(instantiator_reg, + reinterpret_cast<intptr_t>(Object::null()), + &type_arguments_instantiated); + // Instantiate non-null type arguments. + // In the non-factory case, we rely on the allocation stub to + // instantiate the type arguments. + __ LoadObject(result_reg, type_arguments()); + // result_reg: uninstantiated type arguments. + __ Bind(&type_arguments_instantiated); + // result_reg: uninstantiated or instantiated type arguments. } @@ -1600,29 +1597,22 @@ // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity() || - type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // The instantiator was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ LoadImmediate(instantiator_reg, - Smi::RawValue(StubCode::kNoInstantiator)); - } else { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments and do not pass the instantiator. - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - Label instantiator_not_null; - __ BranchNotEqual(instantiator_reg, - reinterpret_cast<intptr_t>(Object::null()), &instantiator_not_null); - // Null was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ LoadImmediate(instantiator_reg, - Smi::RawValue(StubCode::kNoInstantiator)); - __ Bind(&instantiator_not_null); - } - } + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments and do not pass the instantiator. + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + Label instantiator_not_null; + __ BranchNotEqual(instantiator_reg, + reinterpret_cast<intptr_t>(Object::null()), &instantiator_not_null); + // Null was used in VisitExtractConstructorTypeArguments as the + // instantiated type arguments, no proper instantiator needed. + __ LoadImmediate(instantiator_reg, + Smi::RawValue(StubCode::kNoInstantiator)); + __ Bind(&instantiator_not_null); // instantiator_reg: instantiator or kNoInstantiator. } @@ -2618,9 +2608,9 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ TraceSimMsg("GotoInstr"); - // Add deoptimization descriptor for deoptimizing instructions - // that may be inserted before this instruction. if (!compiler->is_optimizing()) { + // Add deoptimization descriptor for deoptimizing instructions that may + // be inserted before this instruction. compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, GetDeoptId(), 0); // No token position.
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index f089bed..88557a7 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc
@@ -1689,9 +1689,9 @@ LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { const intptr_t kNumInputs = 2; - const intptr_t num_temps = 0; + const intptr_t kNumTemps = 0; LocationSummary* summary = - new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresRegister()); summary->set_in(1, ShouldEmitStoreBarrier() ? Location::WritableRegister() @@ -1811,36 +1811,19 @@ LocationSummary* AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const { - const intptr_t kNumInputs = 2; - const intptr_t kNumTemps = 0; - LocationSummary* locs = - new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); - locs->set_in(0, Location::RegisterLocation(RAX)); - locs->set_in(1, Location::RegisterLocation(RCX)); - locs->set_out(Location::RegisterLocation(RAX)); - return locs; + return MakeCallSummary(); } void AllocateObjectWithBoundsCheckInstr::EmitNativeCode( FlowGraphCompiler* compiler) { - const Class& cls = Class::ZoneHandle(constructor().Owner()); - Register type_arguments = locs()->in(0).reg(); - Register instantiator_type_arguments = locs()->in(1).reg(); - Register result = locs()->out().reg(); - - // Push the result place holder initialized to NULL. - __ PushObject(Object::ZoneHandle()); - __ PushObject(cls); - __ pushq(type_arguments); - __ pushq(instantiator_type_arguments); compiler->GenerateCallRuntime(token_pos(), deopt_id(), kAllocateObjectWithBoundsCheckRuntimeEntry, locs()); - // Pop instantiator type arguments, type arguments, and class. __ Drop(3); - __ popq(result); // Pop new instance. + ASSERT(locs()->out().reg() == RAX); + __ popq(RAX); // Pop new instance. } @@ -1929,28 +1912,25 @@ // instantiator_reg is the instantiator type argument vector, i.e. an // AbstractTypeArguments object (or null). - if (!type_arguments().IsUninstantiatedIdentity() && - !type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments. - Label type_arguments_instantiated; - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - const Immediate& raw_null = - Immediate(reinterpret_cast<intptr_t>(Object::null())); - __ cmpq(instantiator_reg, raw_null); - __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); - } - // Instantiate non-null type arguments. - // In the non-factory case, we rely on the allocation stub to - // instantiate the type arguments. - __ LoadObject(result_reg, type_arguments()); - // result_reg: uninstantiated type arguments. - __ Bind(&type_arguments_instantiated); - } - ASSERT(instantiator_reg == result_reg); + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments. + Label type_arguments_instantiated; + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + const Immediate& raw_null = + Immediate(reinterpret_cast<intptr_t>(Object::null())); + __ cmpq(instantiator_reg, raw_null); + __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); + // Instantiate non-null type arguments. + // In the non-factory case, we rely on the allocation stub to + // instantiate the type arguments. + __ LoadObject(result_reg, type_arguments()); + // result_reg: uninstantiated type arguments. + + __ Bind(&type_arguments_instantiated); // result_reg: uninstantiated or instantiated type arguments. } @@ -1974,31 +1954,24 @@ // instantiator_reg is the instantiator AbstractTypeArguments object // (or null). - if (type_arguments().IsUninstantiatedIdentity() || - type_arguments().CanShareInstantiatorTypeArguments( - instantiator_class())) { - // The instantiator was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ movq(instantiator_reg, - Immediate(Smi::RawValue(StubCode::kNoInstantiator))); - } else { - // If the instantiator is null and if the type argument vector - // instantiated from null becomes a vector of dynamic, then use null as - // the type arguments and do not pass the instantiator. - const intptr_t len = type_arguments().Length(); - if (type_arguments().IsRawInstantiatedRaw(len)) { - const Immediate& raw_null = - Immediate(reinterpret_cast<intptr_t>(Object::null())); - Label instantiator_not_null; - __ cmpq(instantiator_reg, raw_null); - __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); - // Null was used in VisitExtractConstructorTypeArguments as the - // instantiated type arguments, no proper instantiator needed. - __ movq(instantiator_reg, - Immediate(Smi::RawValue(StubCode::kNoInstantiator))); - __ Bind(&instantiator_not_null); - } - } + ASSERT(!type_arguments().IsUninstantiatedIdentity() && + !type_arguments().CanShareInstantiatorTypeArguments( + instantiator_class())); + + // If the instantiator is null and if the type argument vector + // instantiated from null becomes a vector of dynamic, then use null as + // the type arguments and do not pass the instantiator. + ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length())); + const Immediate& raw_null = + Immediate(reinterpret_cast<intptr_t>(Object::null())); + Label instantiator_not_null; + __ cmpq(instantiator_reg, raw_null); + __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); + // Null was used in VisitExtractConstructorTypeArguments as the + // instantiated type arguments, no proper instantiator needed. + __ movq(instantiator_reg, + Immediate(Smi::RawValue(StubCode::kNoInstantiator))); + __ Bind(&instantiator_not_null); // instantiator_reg: instantiator or kNoInstantiator. } @@ -4090,9 +4063,9 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - // Add deoptimization descriptor for deoptimizing instructions - // that may be inserted before this instruction. if (!compiler->is_optimizing()) { + // Add deoptimization descriptor for deoptimizing instructions that may + // be inserted before this instruction. compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, GetDeoptId(), 0); // No token position.
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h index 4828657..d55d3c1 100644 --- a/runtime/vm/intrinsifier.h +++ b/runtime/vm/intrinsifier.h
@@ -91,6 +91,7 @@ V(::, sqrt, Math_sqrt, 1662640002) \ V(::, sin, Math_sin, 1273932041) \ V(::, cos, Math_cos, 1749547468) \ + V(_Random, _nextState, Random_nextState, 77315414) \ #define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc index d263973..49d87c0 100644 --- a/runtime/vm/intrinsifier_arm.cc +++ b/runtime/vm/intrinsifier_arm.cc
@@ -311,6 +311,11 @@ } +bool Intrinsifier::Random_nextState(Assembler* assembler) { + return false; +} + + bool Intrinsifier::Object_equal(Assembler* assembler) { return false; }
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc index 097da1b..8d5ff5a 100644 --- a/runtime/vm/intrinsifier_ia32.cc +++ b/runtime/vm/intrinsifier_ia32.cc
@@ -14,6 +14,7 @@ #include "vm/intrinsifier.h" #include "vm/assembler.h" +#include "vm/flow_graph_compiler.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/os.h" @@ -1427,6 +1428,52 @@ } +// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; +// _state[kSTATE_LO] = state & _MASK_32; +// _state[kSTATE_HI] = state >> 32; +bool Intrinsifier::Random_nextState(Assembler* assembler) { + const Library& math_lib = Library::Handle(Library::MathLibrary()); + ASSERT(!math_lib.IsNull()); + const Class& random_class = + Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); + ASSERT(!random_class.IsNull()); + const Field& state_field = Field::ZoneHandle( + random_class.LookupInstanceField(Symbols::_state())); + ASSERT(!state_field.IsNull()); + const Field& random_A_field = Field::ZoneHandle( + random_class.LookupStaticField(Symbols::_A())); + ASSERT(!random_A_field.IsNull()); + ASSERT(random_A_field.is_const()); + const Instance& a_value = Instance::Handle(random_A_field.value()); + const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value(); + // 'a_int_value' is a mask. + ASSERT(Utils::IsUint(32, a_int_value)); + int32_t a_int32_value = static_cast<int32_t>(a_int_value); + __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Receiver. + __ movl(EBX, FieldAddress(EAX, state_field.Offset())); // Field '_state'. + // Addresses of _state[0] and _state[1]. + Address addr_0 = FlowGraphCompiler::ElementAddressForIntIndex( + kTypedDataUint32ArrayCid, + FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid), + EBX, + 0); + Address addr_1 = FlowGraphCompiler::ElementAddressForIntIndex( + kTypedDataUint32ArrayCid, + FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid), + EBX, + 1); + __ movl(EAX, Immediate(a_int32_value)); + // 64-bit multiply EAX * value -> EDX:EAX. + __ mull(addr_0); + __ addl(EAX, addr_1); + __ adcl(EDX, Immediate(0)); + __ movl(addr_1, EDX); + __ movl(addr_0, EAX); + __ ret(); + return true; +} + + // Identity comparison. bool Intrinsifier::Object_equal(Assembler* assembler) { Label is_true;
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc index eaa50ef..d2d00bb 100644 --- a/runtime/vm/intrinsifier_mips.cc +++ b/runtime/vm/intrinsifier_mips.cc
@@ -311,6 +311,11 @@ } +bool Intrinsifier::Random_nextState(Assembler* assembler) { + return false; +} + + bool Intrinsifier::Object_equal(Assembler* assembler) { return false; }
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc index c9befeb..15bec3d 100644 --- a/runtime/vm/intrinsifier_x64.cc +++ b/runtime/vm/intrinsifier_x64.cc
@@ -8,6 +8,7 @@ #include "vm/intrinsifier.h" #include "vm/assembler.h" +#include "vm/flow_graph_compiler.h" #include "vm/instructions.h" #include "vm/object_store.h" #include "vm/symbols.h" @@ -1343,6 +1344,52 @@ } +// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; +// _state[kSTATE_LO] = state & _MASK_32; +// _state[kSTATE_HI] = state >> 32; +bool Intrinsifier::Random_nextState(Assembler* assembler) { + const Library& math_lib = Library::Handle(Library::MathLibrary()); + ASSERT(!math_lib.IsNull()); + const Class& random_class = + Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random())); + ASSERT(!random_class.IsNull()); + const Field& state_field = Field::ZoneHandle( + random_class.LookupInstanceField(Symbols::_state())); + ASSERT(!state_field.IsNull()); + const Field& random_A_field = Field::ZoneHandle( + random_class.LookupStaticField(Symbols::_A())); + ASSERT(!random_A_field.IsNull()); + ASSERT(random_A_field.is_const()); + const Instance& a_value = Instance::Handle(random_A_field.value()); + const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value(); + __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Receiver. + __ movq(RBX, FieldAddress(RAX, state_field.Offset())); // Field '_state'. + // Addresses of _state[0] and _state[1]. + Address addr_0 = FlowGraphCompiler::ElementAddressForIntIndex( + kTypedDataUint32ArrayCid, + FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid), + RBX, + 0); + Address addr_1 = FlowGraphCompiler::ElementAddressForIntIndex( + kTypedDataUint32ArrayCid, + FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid), + RBX, + 1); + + __ movq(RAX, Immediate(a_int_value)); + __ movl(RCX, addr_0); + __ imulq(RCX, RAX); + __ movl(RDX, addr_1); + __ addq(RDX, RCX); + __ movl(addr_0, RDX); + __ shrq(RDX, Immediate(32)); + __ movl(addr_1, RDX); + __ ret(); + return true; +} + + + // Identity comparison. bool Intrinsifier::Object_equal(Assembler* assembler) { Label is_true;
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index fe15ff3..6c41997 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc
@@ -382,7 +382,6 @@ long_jump_base_(NULL), timer_list_(), deopt_id_(0), - ic_data_array_(Array::null()), mutex_(new Mutex()), stack_limit_(0), saved_stack_limit_(0), @@ -650,21 +649,6 @@ } -ICData* Isolate::GetICDataForDeoptId(intptr_t deopt_id) const { - if (ic_data_array() == Array::null()) { - return &ICData::ZoneHandle(); - } - const Array& array_handle = Array::Handle(ic_data_array()); - if (deopt_id >= array_handle.Length()) { - // For computations being added in the optimizing compiler. - return &ICData::ZoneHandle(); - } - ICData& ic_data_handle = ICData::ZoneHandle(); - ic_data_handle ^= array_handle.At(deopt_id); - return &ic_data_handle; -} - - static int MostUsedFunctionFirst(const Function* const* a, const Function* const* b) { if ((*a)->usage_counter() > (*b)->usage_counter()) { @@ -837,9 +821,6 @@ // Visit the top context which is stored in the isolate. visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_context_)); - // Visit the currently active IC data array. - visitor->VisitPointer(reinterpret_cast<RawObject**>(&ic_data_array_)); - // Visit objects in the debugger. debugger()->VisitObjectPointers(visitor); }
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index 407a9f8..e0059cf 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h
@@ -405,10 +405,6 @@ return (deopt_id % kDeoptIdStep) == kDeoptIdAfterOffset; } - RawArray* ic_data_array() const { return ic_data_array_; } - void set_ic_data_array(RawArray* value) { ic_data_array_ = value; } - ICData* GetICDataForDeoptId(intptr_t deopt_id) const; - Mutex* mutex() const { return mutex_; } Debugger* debugger() const { return debugger_; } @@ -615,7 +611,6 @@ LongJump* long_jump_base_; TimerList timer_list_; intptr_t deopt_id_; - RawArray* ic_data_array_; Mutex* mutex_; // protects stack_limit_ and saved_stack_limit_. uword stack_limit_; uword saved_stack_limit_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index f620fe3..ae6e05b 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc
@@ -943,12 +943,14 @@ cls = Class::New<Instance>(kIllegalCid); RegisterClass(cls, Symbols::Float32x4(), lib); + cls.set_is_prefinalized(); pending_classes.Add(cls, Heap::kOld); type = Type::NewNonParameterizedType(cls); object_store->set_float32x4_type(type); cls = Class::New<Instance>(kIllegalCid); RegisterClass(cls, Symbols::Uint32x4(), lib); + cls.set_is_prefinalized(); pending_classes.Add(cls, Heap::kOld); type = Type::NewNonParameterizedType(cls); object_store->set_uint32x4_type(type); @@ -976,18 +978,21 @@ cls = Class::New<Instance>(kIllegalCid); RegisterClass(cls, Symbols::Int(), core_lib); + cls.set_is_prefinalized(); pending_classes.Add(cls, Heap::kOld); type = Type::NewNonParameterizedType(cls); object_store->set_int_type(type); cls = Class::New<Instance>(kIllegalCid); RegisterClass(cls, Symbols::Double(), core_lib); + cls.set_is_prefinalized(); pending_classes.Add(cls, Heap::kOld); type = Type::NewNonParameterizedType(cls); object_store->set_double_type(type); name = Symbols::New("String"); cls = Class::New<Instance>(kIllegalCid); + cls.set_is_prefinalized(); RegisterClass(cls, name, core_lib); pending_classes.Add(cls, Heap::kOld); type = Type::NewNonParameterizedType(cls); @@ -995,6 +1000,7 @@ cls = Class::New<Instance>(kIllegalCid); RegisterClass(cls, Symbols::List(), core_lib); + cls.set_is_prefinalized(); pending_classes.Add(cls, Heap::kOld); object_store->set_list_class(cls); @@ -2482,7 +2488,7 @@ field ^= flds.At(i); field_name ^= field.name(); if (String::EqualsIgnoringPrivateKey(field_name, name)) { - return field.raw(); + return field.raw(); } } // No field found. @@ -4820,6 +4826,9 @@ const char* Field::ToCString() const { + if (IsNull()) { + return "Field::null"; + } const char* kF0 = is_static() ? " static" : ""; const char* kF1 = is_final() ? " final" : ""; const char* kF2 = is_const() ? " const" : ""; @@ -6054,7 +6063,8 @@ } // Create the array of scripts and cache it in loaded_scripts_. - StorePointer(&raw_ptr()->loaded_scripts_, Array::MakeArray(scripts)); + const Array& scripts_array = Array::Handle(Array::MakeArray(scripts)); + StorePointer(&raw_ptr()->loaded_scripts_, scripts_array.raw()); } return loaded_scripts(); } @@ -7091,7 +7101,7 @@ const char* PcDescriptors::KindAsStr(intptr_t index) const { switch (DescriptorKind(index)) { - case PcDescriptors::kDeopt: return "deopt "; + case PcDescriptors::kDeopt: return "deopt "; case PcDescriptors::kEntryPatch: return "entry-patch "; case PcDescriptors::kPatchCode: return "patch "; case PcDescriptors::kLazyDeoptJump: return "lazy-deopt "; @@ -10344,7 +10354,7 @@ if (!OS::StringToInt64(str.ToCString(), &value)) { const Bigint& big = Bigint::Handle(Bigint::New(str, space)); ASSERT(!BigintOperations::FitsIntoSmi(big)); - ASSERT(!BigintOperations::FitsIntoMint(big)); + ASSERT(!BigintOperations::FitsIntoInt64(big)); return big.raw(); } return Integer::New(value, space); @@ -10358,7 +10368,7 @@ if (!OS::StringToInt64(str.ToCString(), &value)) { const Bigint& big = Bigint::Handle(Bigint::NewCanonical(str)); ASSERT(!BigintOperations::FitsIntoSmi(big)); - ASSERT(!BigintOperations::FitsIntoMint(big)); + ASSERT(!BigintOperations::FitsIntoInt64(big)); return big.raw(); } if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) { @@ -10410,8 +10420,8 @@ big_value ^= raw(); if (BigintOperations::FitsIntoSmi(big_value)) { return BigintOperations::ToSmi(big_value); - } else if (BigintOperations::FitsIntoMint(big_value)) { - return Mint::New(BigintOperations::ToMint(big_value)); + } else if (BigintOperations::FitsIntoInt64(big_value)) { + return Mint::New(BigintOperations::ToInt64(big_value)); } else { return big_value.raw(); } @@ -10512,7 +10522,7 @@ const Bigint& left_big = Bigint::Handle(AsBigint()); const Bigint& right_big = Bigint::Handle(other.AsBigint()); const Bigint& result = - Bigint::Handle(left_big.ArithmeticOp(operation, right_big)); + Bigint::Handle(left_big.BigArithmeticOp(operation, right_big)); return Integer::Handle(result.AsValidInteger()).raw(); } @@ -10776,7 +10786,7 @@ } } if (other.IsBigint()) { - ASSERT(!BigintOperations::FitsIntoMint(Bigint::Cast(other))); + ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(other))); if (this->IsNegative() == other.IsNegative()) { return this->IsNegative() ? 1 : -1; } @@ -10918,8 +10928,8 @@ } -RawBigint* Bigint::ArithmeticOp(Token::Kind operation, - const Bigint& other) const { +RawBigint* Bigint::BigArithmeticOp(Token::Kind operation, + const Bigint& other) const { switch (operation) { case Token::kADD: return BigintOperations::Add(*this, other); @@ -10971,7 +10981,7 @@ RawBigint* Bigint::New(const String& str, Heap::Space space) { const Bigint& result = Bigint::Handle( BigintOperations::NewFromCString(str.ToCString(), space)); - ASSERT(!BigintOperations::FitsIntoMint(result)); + ASSERT(!BigintOperations::FitsIntoInt64(result)); return result.raw(); } @@ -10979,7 +10989,7 @@ RawBigint* Bigint::NewCanonical(const String& str) { const Bigint& value = Bigint::Handle( BigintOperations::NewFromCString(str.ToCString(), Heap::kOld)); - ASSERT(!BigintOperations::FitsIntoMint(value)); + ASSERT(!BigintOperations::FitsIntoInt64(value)); const Class& cls = Class::Handle(Isolate::Current()->object_store()->bigint_class()); const Array& constants = Array::Handle(cls.constants()); @@ -11012,17 +11022,17 @@ int64_t Bigint::AsInt64Value() const { - if (!BigintOperations::FitsIntoMint(*this)) { + if (!BigintOperations::FitsIntoInt64(*this)) { UNREACHABLE(); } - return BigintOperations::ToMint(*this); + return BigintOperations::ToInt64(*this); } // For positive values: Smi < Mint < Bigint. int Bigint::CompareWith(const Integer& other) const { ASSERT(!FitsIntoSmi(*this)); - ASSERT(!BigintOperations::FitsIntoMint(*this)); + ASSERT(!BigintOperations::FitsIntoInt64(*this)); if (other.IsBigint()) { return BigintOperations::Compare(*this, Bigint::Cast(other)); }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h index b5406ff..755262e 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h
@@ -216,7 +216,10 @@ ASSERT(!IsNull()); raw()->SetCanonical(); } - + intptr_t GetClassId() const { + return !raw()->IsHeapObject() ? + static_cast<intptr_t>(kSmiCid) : raw()->GetClassId(); + } inline RawClass* clazz() const; static intptr_t tags_offset() { return OFFSET_OF(RawObject, tags_); } @@ -4096,12 +4099,12 @@ return RoundedAllocationSize(sizeof(RawBigint) + (len * kBytesPerElement)); } - RawBigint* ArithmeticOp(Token::Kind operation, const Bigint& other) const; - protected: // Only Integer::NewXXX is allowed to call Bigint::NewXXX directly. friend class Integer; + RawBigint* BigArithmeticOp(Token::Kind operation, const Bigint& other) const; + static RawBigint* New(const String& str, Heap::Space space = Heap::kNew); // Returns a canonical Bigint object allocated in the old gen space.
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index 33db8c2..2628ce3 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc
@@ -3250,7 +3250,8 @@ } else { // Not patching a class, but it has been found. This must be one of the // pre-registered classes from object.cc or a duplicate definition. - if (cls.functions() != Object::empty_array().raw()) { + if (!(cls.is_prefinalized() || + RawObject::IsTypedDataViewClassId(cls.id()))) { ErrorMsg(classname_pos, "class '%s' is already defined", class_name.ToCString()); }
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc index 60a22ec..30df9e1 100644 --- a/runtime/vm/raw_object_snapshot.cc +++ b/runtime/vm/raw_object_snapshot.cc
@@ -138,8 +138,9 @@ intptr_t num_flds = (unresolved_class.raw()->to() - unresolved_class.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); unresolved_class.StorePointer((unresolved_class.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } return unresolved_class.raw(); } @@ -201,7 +202,8 @@ // allocations may happen. intptr_t num_flds = (type.raw()->to() - type.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { - type.StorePointer((type.raw()->from() + i), reader->ReadObjectRef()); + (*reader->ObjectHandle()) = reader->ReadObjectRef(); + type.StorePointer((type.raw()->from() + i), reader->ObjectHandle()->raw()); } // If object needs to be a canonical object, Canonicalize it. @@ -315,8 +317,9 @@ intptr_t num_flds = (type_parameter.raw()->to() - type_parameter.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); type_parameter.StorePointer((type_parameter.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } return type_parameter.raw(); @@ -386,8 +389,9 @@ intptr_t num_flds = (bounded_type.raw()->to() - bounded_type.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); bounded_type.StorePointer((bounded_type.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } bounded_type.set_is_being_checked(false); @@ -536,9 +540,10 @@ intptr_t num_flds = (instantiated_type_arguments.raw()->to() - instantiated_type_arguments.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); instantiated_type_arguments.StorePointer( (instantiated_type_arguments.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } return instantiated_type_arguments.raw(); } @@ -1352,7 +1357,9 @@ // allocations may happen. intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { - context.StorePointer((context.raw()->from() + i), reader->ReadObjectRef()); + (*reader->ObjectHandle()) = reader->ReadObjectRef(); + context.StorePointer((context.raw()->from() + i), + reader->ObjectHandle()->raw()); } return context.raw(); @@ -1481,8 +1488,9 @@ // allocations may happen. intptr_t num_flds = (api_error.raw()->to() - api_error.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); api_error.StorePointer((api_error.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } return api_error.raw(); @@ -1527,8 +1535,9 @@ intptr_t num_flds = (language_error.raw()->to() - language_error.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { + (*reader->ObjectHandle()) = reader->ReadObjectRef(); language_error.StorePointer((language_error.raw()->from() + i), - reader->ReadObjectRef()); + reader->ObjectHandle()->raw()); } return language_error.raw();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index 59d6d29..4e161c6 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc
@@ -18,6 +18,7 @@ #include "vm/constants_arm.h" #include "vm/disassembler.h" #include "vm/native_arguments.h" +#include "vm/stack_frame.h" #include "vm/thread.h" namespace dart { @@ -113,6 +114,13 @@ bool GetFValue(char* desc, float* value); bool GetDValue(char* desc, double* value); + void PrintDartFrame(uword pc, uword fp, uword sp, + const Function& function, + intptr_t token_pos, + bool is_optimized, + bool is_inlined); + void PrintBacktrace(); + // Set or delete a breakpoint. Returns true if successful. bool SetBreakpoint(Instr* breakpc); bool DeleteBreakpoint(Instr* breakpc); @@ -254,6 +262,79 @@ } +void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp, + const Function& function, + intptr_t token_pos, + bool is_optimized, + bool is_inlined) { + const Script& script = Script::Handle(function.script()); + const String& func_name = String::Handle(function.QualifiedUserVisibleName()); + const String& url = String::Handle(script.url()); + intptr_t line = -1; + intptr_t column = -1; + if (token_pos >= 0) { + script.GetTokenLocation(token_pos, &line, &column); + } + OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s%s (%s:%"Pd":%"Pd")\n", + pc, fp, sp, + is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", + func_name.ToCString(), + url.ToCString(), + line, column); +} + + +void SimulatorDebugger::PrintBacktrace() { + StackFrameIterator frames(sim_->get_register(FP), + sim_->get_register(SP), + sim_->get_pc(), + StackFrameIterator::kDontValidateFrames); + StackFrame* frame = frames.NextFrame(); + ASSERT(frame != NULL); + Function& function = Function::Handle(); + Function& inlined_function = Function::Handle(); + Code& code = Code::Handle(); + Code& unoptimized_code = Code::Handle(); + while (frame != NULL) { + if (frame->IsDartFrame()) { + code = frame->LookupDartCode(); + function = code.function(); + if (code.is_optimized()) { + // For optimized frames, extract all the inlined functions if any + // into the stack trace. + InlinedFunctionsIterator it(frame); + while (!it.Done()) { + // Print each inlined frame with its pc in the corresponding + // unoptimized frame. + inlined_function = it.function(); + unoptimized_code = it.code(); + uword unoptimized_pc = it.pc(); + it.Advance(); + if (!it.Done()) { + PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(), + inlined_function, + unoptimized_code.GetTokenIndexOfPC(unoptimized_pc), + true, true); + } + } + // Print the optimized inlining frame below. + } + PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), + function, + code.GetTokenIndexOfPC(frame->pc()), + code.is_optimized(), false); + } else { + OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s frame\n", + frame->pc(), frame->fp(), frame->sp(), + frame->IsEntryFrame() ? "entry" : + frame->IsExitFrame() ? "exit" : + frame->IsStubFrame() ? "stub" : "invalid"); + } + frame = frames.NextFrame(); + } +} + + bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { // Check if a breakpoint can be set. If not return without any side-effects. if (sim_->break_pc_ != NULL) { @@ -350,6 +431,8 @@ "pd/printdouble <dreg or *addr> -- print double value\n" "po/printobject <*reg or *addr> -- print object\n" "si/stepi -- single step an instruction\n" + "trace -- toggle execution tracing mode\n" + "bt -- print backtrace\n" "unstop -- if current pc is a stop instr make it a nop\n" "q/quit -- Quit the debugger and exit the program\n"); } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { @@ -481,6 +564,11 @@ } else { OS::Print("Not at debugger stop.\n"); } + } else if (strcmp(cmd, "trace") == 0) { + FLAG_trace_sim = !FLAG_trace_sim; + OS::Print("execution tracing %s\n", FLAG_trace_sim ? "on" : "off"); + } else if (strcmp(cmd, "bt") == 0) { + PrintBacktrace(); } else { OS::Print("Unknown command: %s\n", cmd); }
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc index b45d133..163e653 100644 --- a/runtime/vm/stack_frame.cc +++ b/runtime/vm/stack_frame.cc
@@ -215,6 +215,7 @@ uword exit_marker = *reinterpret_cast<uword*>(exit_address); frames_.fp_ = exit_marker; frames_.sp_ = 0; + frames_.pc_ = 0; } @@ -223,29 +224,52 @@ SetupLastExitFrameData(); // Setup data for last exit frame. } + StackFrameIterator::StackFrameIterator(uword last_fp, bool validate) : validate_(validate), entry_(), exit_(), current_frame_(NULL) { frames_.fp_ = last_fp; + frames_.sp_ = 0; + frames_.pc_ = 0; +} + + +StackFrameIterator::StackFrameIterator(uword fp, uword sp, uword pc, + bool validate) + : validate_(validate), entry_(), exit_(), current_frame_(NULL) { + frames_.fp_ = fp; + frames_.sp_ = sp; + frames_.pc_ = pc; } StackFrame* StackFrameIterator::NextFrame() { // When we are at the start of iteration after having created an - // iterator object current_frame_ will be NULL as we haven't seen - // any frames yet. At this point if NextFrame is called it tries + // iterator object, current_frame_ will be NULL as we haven't seen + // any frames yet (unless we start iterating in the simulator from a given + // triplet of fp, sp, and pc). At this point, if NextFrame is called, it tries // to set up the next exit frame by reading the top_exit_frame_info - // from the isolate. If we do not have any dart invocations yet + // from the isolate. If we do not have any dart invocations yet, // top_exit_frame_info will be 0 and so we would return NULL. // current_frame_ will also be NULL, when we are at the end of having - // iterated through all the frames. if NextFrame is called at this - // point we will try and set up the next exit frame but since we are - // at the end of the iteration fp_ will be 0 and we would return NULL. + // iterated through all the frames. If NextFrame is called at this + // point, we will try and set up the next exit frame, but since we are + // at the end of the iteration, fp_ will be 0 and we would return NULL. if (current_frame_ == NULL) { if (!HasNextFrame()) { return NULL; } - current_frame_ = NextExitFrame(); + if (frames_.pc_ == 0) { + // Iteration starts from an exit frame given by its fp. + current_frame_ = NextExitFrame(); + } else if (*(reinterpret_cast<uword*>( + frames_.fp_ + (kSavedCallerFpSlotFromFp * kWordSize))) == 0) { + // Iteration starts from an entry frame given by its fp, sp, and pc. + current_frame_ = NextEntryFrame(); + } else { + // Iteration starts from a Dart or stub frame given by its fp, sp, and pc. + current_frame_ = frames_.NextFrame(validate_); + } return current_frame_; } ASSERT((validate_ == kDontValidateFrames) || current_frame_->IsValid()); @@ -276,8 +300,10 @@ frame = &stack_frame_; frame->sp_ = sp_; frame->fp_ = fp_; + frame->pc_ = pc_; sp_ = frame->GetCallerSp(); fp_ = frame->GetCallerFp(); + pc_ = frame->GetCallerPc(); ASSERT((validate == kDontValidateFrames) || frame->IsValid()); return frame; } @@ -286,8 +312,10 @@ ExitFrame* StackFrameIterator::NextExitFrame() { exit_.sp_ = frames_.sp_; exit_.fp_ = frames_.fp_; + exit_.pc_ = frames_.pc_; frames_.sp_ = exit_.GetCallerSp(); frames_.fp_ = exit_.GetCallerFp(); + frames_.pc_ = exit_.GetCallerPc(); ASSERT(exit_.IsValid()); return &exit_; } @@ -297,6 +325,7 @@ ASSERT(!frames_.HasNext()); entry_.sp_ = frames_.sp_; entry_.fp_ = frames_.fp_; + entry_.pc_ = frames_.pc_; SetupNextExitFrameData(); // Setup data for next exit frame in chain. ASSERT(entry_.IsValid()); return &entry_; @@ -317,7 +346,7 @@ intptr_t deopt_reason = kDeoptUnknown; deopt_info_ = code_.GetDeoptInfoAtPc(frame->pc(), &deopt_reason); if (deopt_info_.IsNull()) { - // This is the case when a call without deopt info in optimzed code + // This is the case when a call without deopt info in optimized code // throws an exception. (e.g. in the parameter copying prologue). // In that case there won't be any inlined frames. function_ = code_.function();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h index 10b63c5..2b206fa 100644 --- a/runtime/vm/stack_frame.h +++ b/runtime/vm/stack_frame.h
@@ -36,9 +36,7 @@ // Accessors to get the pc, sp and fp of a frame. uword sp() const { return sp_; } uword fp() const { return fp_; } - uword pc() const { - return *reinterpret_cast<uword*>(sp_ + (kSavedPcSlotFromSp * kWordSize)); - } + uword pc() const { return pc_; } // The pool pointer is not implemented on all architectures. static int SavedCallerPpSlotFromFp() { @@ -79,7 +77,7 @@ protected: - StackFrame() : fp_(0), sp_(0) { } + StackFrame() : fp_(0), sp_(0), pc_(0) { } // Name of the frame, used for generic frame printing functionality. virtual const char* GetName() const { return IsStubFrame()? "stub" : "dart"; } @@ -94,9 +92,14 @@ return *(reinterpret_cast<uword*>( fp() + (kSavedCallerFpSlotFromFp * kWordSize))); } + uword GetCallerPc() const { + return *(reinterpret_cast<uword*>( + fp() + (kSavedCallerPcSlotFromFp * kWordSize))); + } uword fp_; uword sp_; + uword pc_; // The iterators FrameSetIterator and StackFrameIterator set the private // fields fp_ and sp_ when they return the respective frame objects. @@ -154,16 +157,20 @@ }; -// Iterator for iterating over all frames from the last ExitFrame to the -// first EntryFrame. class StackFrameIterator : public ValueObject { public: static const bool kValidateFrames = true; static const bool kDontValidateFrames = false; + // Iterators for iterating over all frames from the last ExitFrame to the + // first EntryFrame. explicit StackFrameIterator(bool validate); StackFrameIterator(uword last_fp, bool validate); + // Iterator for iterating over all frames from the current frame (given by its + // fp, sp, and pc) to the first EntryFrame. + StackFrameIterator(uword fp, uword sp, uword pc, bool validate); + // Checks if a next frame exists. bool HasNextFrame() const { return frames_.fp_ != 0; } @@ -189,10 +196,11 @@ StackFrame* NextFrame(bool validate); private: - FrameSetIterator() : fp_(0), sp_(0), stack_frame_() { } + FrameSetIterator() : fp_(0), sp_(0), pc_(0), stack_frame_() { } uword fp_; uword sp_; + uword pc_; StackFrame stack_frame_; // Singleton frame returned by NextFrame(). friend class StackFrameIterator;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 2c85c1c..efe97a0 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h
@@ -257,6 +257,9 @@ V(DartTypedData, "dart:typed_data") \ V(DartUri, "dart:uri") \ V(DartUtf, "dart:utf") \ + V(_Random, "_Random") \ + V(_state, "_state") \ + V(_A, "_A") \ // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart index 2c94493..69d3cfa 100644 --- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart +++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -38,6 +38,8 @@ outputProvider: outputProvider, enableTypeAssertions: hasOption(options, '--enable-checked-mode'), enableUserAssertions: hasOption(options, '--enable-checked-mode'), + trustTypeAnnotations: + hasOption(options, '--trust-type-annotations'), enableMinification: hasOption(options, '--minify'), enableNativeLiveTypeAnalysis: !hasOption(options, '--disable-native-live-type-analysis'),
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart index fff0b37..b1d62ca 100644 --- a/sdk/lib/_internal/compiler/implementation/closure.dart +++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -67,7 +67,9 @@ // move these classes to elements/modelx.dart or see if we can find a // more general solution. class ClosureFieldElement extends ElementX { - ClosureFieldElement(SourceString name, ClassElement enclosing) + ClosureFieldElement(SourceString name, + this.variableElement, + ClassElement enclosing) : super(name, ElementKind.FIELD, enclosing); bool isInstanceMember() => true; @@ -77,9 +79,16 @@ bool hasFixedBackendName() => true; String fixedBackendName() => name.slowToString(); - DartType computeType(Compiler compiler) => compiler.types.dynamicType; + DartType computeType(Compiler compiler) { + return variableElement.computeType(compiler); + } String toString() => "ClosureFieldElement($name)"; + + /** + * The source variable this element refers to. + */ + final Element variableElement; } // TODO(ahe): These classes continuously cause problems. We need to @@ -114,10 +123,12 @@ Token position() => node.getBeginToken(); + Node parseNode(DiagnosticListener listener) => node; + /** * The most outer method this closure is declared into. */ - Element methodElement; + final Element methodElement; } // TODO(ahe): These classes continuously cause problems. We need to @@ -126,6 +137,24 @@ class BoxElement extends ElementX { BoxElement(SourceString name, Element enclosingElement) : super(name, ElementKind.VARIABLE, enclosingElement); + + DartType computeType(Compiler compiler) => compiler.types.dynamicType; +} + +// TODO(ngeoffray, 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 BoxFieldElement extends ElementX { + BoxFieldElement(SourceString name, + this.variableElement, + BoxElement enclosingBox) + : super(name, ElementKind.FIELD, enclosingBox); + + DartType computeType(Compiler compiler) { + return variableElement.computeType(compiler); + } + + final Element variableElement; } // TODO(ahe): These classes continuously cause problems. We need to @@ -137,6 +166,8 @@ bool isAssignable() => false; + DartType computeType(Compiler compiler) => compiler.types.dynamicType; + // Since there is no declaration corresponding to 'this', use the position of // the enclosing method. Token position() => enclosingElement.position(); @@ -150,6 +181,8 @@ CheckVariableElement(SourceString 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(); @@ -226,25 +259,25 @@ return copy != null && !copy.isMember(); } - void forEachCapturedVariable(void f(Element element)) { - freeVariableMapping.forEach((variable, _) { + void forEachCapturedVariable(void f(Element local, Element field)) { + freeVariableMapping.forEach((variable, copy) { if (variable is BoxElement) return; - f(variable); + f(variable, copy); }); } - void forEachBoxedVariable(void f(Element element)) { + void forEachBoxedVariable(void f(Element local, Element field)) { freeVariableMapping.forEach((variable, copy) { if (!isVariableBoxed(variable)) return; - f(variable); + f(variable, copy); }); } - void forEachNonBoxedCapturedVariable(void f(Element element)) { + void forEachNonBoxedCapturedVariable(void f(Element local, Element field)) { freeVariableMapping.forEach((variable, copy) { if (variable is BoxElement) return; if (isVariableBoxed(variable)) return; - f(variable); + f(variable, copy); }); } } @@ -342,8 +375,9 @@ assert(closureElement != null || (fieldCaptures.isEmpty && boxes.isEmpty)); void addElement(Element element, SourceString name) { - Element fieldElement = new ClosureFieldElement(name, closureElement); - closureElement.addBackendMember(fieldElement); + Element fieldElement = new ClosureFieldElement( + name, element, closureElement); + closureElement.addMember(fieldElement, compiler); data.capturedFieldMapping[fieldElement] = element; freeVariableMapping[element] = fieldElement; } @@ -568,7 +602,7 @@ namer.getClosureVariableName(new SourceString(elementName), boxedFieldCounter++); // TODO(kasperl): Should this be a FieldElement instead? - Element boxed = new ElementX(boxedName, ElementKind.FIELD, box); + Element boxed = new BoxFieldElement(boxedName, element, box); // No need to rename the fields of a box, so we give them a native name // right now. boxed.setFixedBackendName(boxedName.slowToString()); @@ -658,7 +692,7 @@ new FunctionElementX.from(Compiler.CALL_OPERATOR_NAME, element, globalizedElement); - globalizedElement.addBackendMember(callElement); + globalizedElement.addMember(callElement, compiler); // The nested function's 'this' is the same as the one for the outer // function. It could be [null] if we are inside a static method. Element thisElement = closureData.thisElement;
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart index dc99d27..47b66c2 100644 --- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart +++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -884,8 +884,7 @@ } jsNewArguments.add(fieldValue); }, - includeBackendMembers: true, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); return jsNewArguments; } }
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart index c2de002..a292e28 100644 --- a/sdk/lib/_internal/compiler/implementation/compiler.dart +++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -137,7 +137,8 @@ Enqueuer enqueuer, TreeElements elements) {} void registerStringInterpolation(TreeElements elements) {} - void registerCatchStatement(TreeElements elements) {} + void registerCatchStatement(Enqueuer enqueuer, + TreeElements elements) {} void registerWrapException(TreeElements elements) {} void registerThrowExpression(TreeElements elements) {} void registerLazyField(TreeElements elements) {} @@ -251,6 +252,7 @@ final bool enableMinification; final bool enableTypeAssertions; final bool enableUserAssertions; + final bool trustTypeAnnotations; final bool enableConcreteTypeInference; /** * The maximum size of a concrete type before it widens to dynamic during @@ -440,6 +442,7 @@ Compiler({this.tracer: const Tracer(), this.enableTypeAssertions: false, this.enableUserAssertions: false, + this.trustTypeAnnotations: false, this.enableConcreteTypeInference: false, this.maxConcreteTypeSize: 5, this.enableMinification: false, @@ -1024,7 +1027,6 @@ if (message is TypeWarning) { // TODO(ahe): Don't supress these warning when the type checker // is more complete. - if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return; if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return; if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) { return;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart index 1afb82b..20856b7 100644 --- a/sdk/lib/_internal/compiler/implementation/dart2js.dart +++ b/sdk/lib/_internal/compiler/implementation/dart2js.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 dart2js; +library dart2js.cmdline; import 'dart:async'; import 'dart:collection' show Queue, LinkedHashMap; @@ -212,6 +212,8 @@ (_) => passThrough('--enable-checked-mode')), new OptionHandler('--enable-concrete-type-inference', (_) => passThrough('--enable-concrete-type-inference')), + new OptionHandler('--trust-type-annotations', + (_) => passThrough('--trust-type-annotations')), new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true), new OptionHandler('--package-root=.+|-p.+', setPackageRoot), new OptionHandler('--disallow-unsafe-eval', passThrough),
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart index ecee2ba..bcec921 100644 --- a/sdk/lib/_internal/compiler/implementation/dart_types.dart +++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -341,6 +341,8 @@ return visitor.visitMalformedType(this, argument); } + bool operator ==(other) => identical(this, other); + String toString() { var sb = new StringBuffer(); if (typeArguments != null) { @@ -446,8 +448,9 @@ } bool operator ==(other) { - if (!identical(element, other.element)) return false; - return typeArguments == other.typeArguments; + if (other is !GenericType) return false; + return identical(element, other.element) + && typeArguments == other.typeArguments; } bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType); @@ -521,7 +524,9 @@ ClassElement classElement = element; InterfaceType receiver = this; InterfaceType declarer = receiver; - Element member = classElement.lookupLocalMember(name); + // TODO(johnniwinther): Lookup and callers should handle private members and + // injected members. + Element member = classElement.implementation.lookupLocalMember(name); if (member != null) { return createMember(receiver, declarer, member); } @@ -533,7 +538,7 @@ if (supertype.element.isMixinApplication) continue; declarer = supertype; ClassElement lookupTarget = declarer.element; - member = lookupTarget.lookupLocalMember(name); + member = lookupTarget.implementation.lookupLocalMember(name); if (member != null) { return createMember(receiver, declarer, member); }
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart index cecab14..c0bc01e4 100644 --- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart +++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -198,6 +198,7 @@ bool isTypedef(); bool isTypeVariable(); bool isField(); + bool isFieldParameter(); bool isAbstractField(); bool isGetter(); bool isSetter(); @@ -488,15 +489,13 @@ /// A `compareTo` function that places [Element]s in a consistent order based /// on the source code order. static int compareByPosition(Element a, Element b) { - CompilationUnitElement unitA = a.getCompilationUnit(); - CompilationUnitElement unitB = b.getCompilationUnit(); - if (!identical(unitA, unitB)) { - int r = unitA.script.uri.path.compareTo(unitB.script.uri.path); - if (r != 0) return r; - } + int r = a.getLibrary().compareTo(b.getLibrary()); + if (r != 0) return r; + r = a.getCompilationUnit().compareTo(b.getCompilationUnit()); + if (r != 0) return r; Token positionA = a.position(); Token positionB = b.position(); - int r = positionA.charOffset.compareTo(positionB.charOffset); + r = positionA.charOffset.compareTo(positionB.charOffset); if (r != 0) return r; r = a.name.slowToString().compareTo(b.name.slowToString()); if (r != 0) return r; @@ -548,6 +547,16 @@ } return false; } + + static bool isUnusedLabel(LabeledStatement node, TreeElements elements) { + Node body = node.statement; + TargetElement element = elements[body]; + // Labeled statements with no element on the body have no breaks. + // A different target statement only happens if the body is itself + // a break or continue for a different target. In that case, this + // label is also always unused. + return element == null || element.statement != body; + } } abstract class ErroneousElement extends Element implements FunctionElement { @@ -578,6 +587,8 @@ void addMember(Element element, DiagnosticListener listener); void setPartOf(PartOf tag, DiagnosticListener listener); bool get hasMembers; + + int compareTo(CompilationUnitElement other); } abstract class LibraryElement extends Element implements ScopeContainerElement { @@ -639,6 +650,8 @@ bool hasLibraryName(); String getLibraryOrScriptName(); + + int compareTo(LibraryElement other); } abstract class PrefixElement extends Element { @@ -837,11 +850,10 @@ void forEachMember(void f(ClassElement enclosingClass, Element member), {includeBackendMembers: false, - includeSuperMembers: false}); + includeSuperAndInjectedMembers: false}); void forEachInstanceField(void f(ClassElement enclosingClass, Element field), - {includeBackendMembers: false, - includeSuperMembers: false}); + {includeSuperAndInjectedMembers: false}); void forEachBackendMember(void f(Element member)); }
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart index 0cb0a4d..d8f90d4 100644 --- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart +++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -84,6 +84,7 @@ bool isTypedef() => identical(kind, ElementKind.TYPEDEF); bool isTypeVariable() => identical(kind, ElementKind.TYPE_VARIABLE); bool isField() => identical(kind, ElementKind.FIELD); + bool isFieldParameter() => identical(kind, ElementKind.FIELD_PARAMETER); bool isAbstractField() => identical(kind, ElementKind.ABSTRACT_FIELD); bool isGetter() => identical(kind, ElementKind.GETTER); bool isSetter() => identical(kind, ElementKind.SETTER); @@ -525,6 +526,11 @@ } bool get hasMembers => !localMembers.isEmpty; + + int compareTo(CompilationUnitElement other) { + if (this == other) return 0; + return '${script.uri}'.compareTo('${other.script.uri}'); + } } class LibraryElementX extends ElementX implements LibraryElement { @@ -770,6 +776,11 @@ return 'library(${getLibraryOrScriptName()})'; } } + + int compareTo(LibraryElement other) { + if (this == other) return 0; + return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName()); + } } class PrefixElementX extends ElementX implements PrefixElement { @@ -1498,6 +1509,8 @@ void setDefaultConstructor(FunctionElement constructor, Compiler compiler); void addBackendMember(Element member) { + // TODO(ngeoffray): Deprecate this method. + assert(member.isGenerativeConstructorBody()); backendMembers = backendMembers.prepend(member); } @@ -1590,6 +1603,11 @@ current != null; current = current.superclass) { Element member = current.lookupLocalMember(name); + if (member == null && current.isPatched) { + // Doing lookups on selectors is done after resolution, so it + // is safe to look in the patch class. + member = current.patch.lookupLocalMember(name); + } if (member == null) continue; // Private members from a different library are not visible. if (isPrivate && !identical(library, member.getLibrary())) continue; @@ -1715,7 +1733,7 @@ * Runs through all members of this class. * * The enclosing class is passed to the callback. This is useful when - * [includeSuperMembers] is [:true:]. + * [includeSuperAndInjectedMembers] is [:true:]. * * When called on an implementation element both the members in the origin * and patch class are included. @@ -1723,8 +1741,8 @@ // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. void forEachMember(void f(ClassElement enclosingClass, Element member), {includeBackendMembers: false, - includeSuperMembers: false}) { - bool includeInjectedMembers = isPatch; + includeSuperAndInjectedMembers: false}) { + bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch; Set<ClassElement> seen = new Set<ClassElement>(); ClassElement classElement = declaration; do { @@ -1746,7 +1764,9 @@ }); } } - classElement = includeSuperMembers ? classElement.superclass : null; + classElement = includeSuperAndInjectedMembers + ? classElement.superclass + : null; } while(classElement != null); } @@ -1754,18 +1774,13 @@ * Runs through all instance-field members of this class. * * The enclosing class is passed to the callback. This is useful when - * [includeSuperMembers] is [:true:]. - * - * When [includeBackendMembers] and [includeSuperMembers] are both [:true:] - * then the fields are visited in the same order as they need to be given - * to the JavaScript constructor. + * [includeSuperAndInjectedMembers] is [:true:]. * * When called on the implementation element both the fields declared in the * origin and in the patch are included. */ void forEachInstanceField(void f(ClassElement enclosingClass, Element field), - {includeBackendMembers: false, - includeSuperMembers: false}) { + {includeSuperAndInjectedMembers: false}) { // Filters so that [f] is only invoked with instance fields. void fieldFilter(ClassElement enclosingClass, Element member) { if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { @@ -1774,8 +1789,7 @@ } forEachMember(fieldFilter, - includeBackendMembers: includeBackendMembers, - includeSuperMembers: includeSuperMembers); + includeSuperAndInjectedMembers: includeSuperAndInjectedMembers); } void forEachBackendMember(void f(Element member)) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart index 79ad151..b4bfbdb5 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -646,6 +646,7 @@ ClassElement jsDoubleClass; ClassElement jsNullClass; ClassElement jsBoolClass; + ClassElement jsUnknownClass; ClassElement jsIndexableClass; ClassElement jsMutableIndexableClass; @@ -862,7 +863,7 @@ if (uses == null) return null; Set<ClassElement> result = null; for (MixinApplicationElement use in uses) { - Iterable<ClassElement> subclasses = compiler.world.subclasses[use]; + Iterable<ClassElement> subclasses = compiler.world.subclassesOf(use); if (subclasses != null) { for (ClassElement subclass in subclasses) { if (subclass.isNative()) { @@ -921,7 +922,10 @@ jsFixedArrayClass = compiler.findInterceptor(const SourceString('JSFixedArray')), jsExtendableArrayClass = - compiler.findInterceptor(const SourceString('JSExtendableArray'))]; + compiler.findInterceptor(const SourceString('JSExtendableArray')), + jsUnknownClass = + compiler.findInterceptor(const SourceString('JSUnknown')), + ]; jsIndexableClass = compiler.findInterceptor(const SourceString('JSIndexable')); @@ -1012,7 +1016,7 @@ classesMixedIntoNativeClasses.add(mixinApplication.mixin); } }, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); } } @@ -1028,7 +1032,7 @@ member.name, () => new Set<Element>()); set.add(member); }, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); } enqueuer.registerInstantiatedClass(cls, elements); } @@ -1124,6 +1128,8 @@ addInterceptors(jsIntClass, enqueuer, elements); addInterceptors(jsDoubleClass, enqueuer, elements); addInterceptors(jsNumberClass, enqueuer, elements); + } else if (cls == jsUnknownClass) { + addInterceptors(jsUnknownClass, enqueuer, elements); } else if (cls.isNative()) { addInterceptorsForNativeClassMembers(cls, enqueuer); } @@ -1134,7 +1140,7 @@ if (!member.isInstanceMember() || !member.isField()) return; DartType type = member.computeType(compiler); enqueuer.registerIsCheck(type, elements); - }, includeSuperMembers: true); + }, includeSuperAndInjectedMembers: true); } } @@ -1177,8 +1183,11 @@ enqueueInResolution(getStringInterpolationHelper(), elements); } - void registerCatchStatement(TreeElements elements) { + void registerCatchStatement(Enqueuer enqueuer, TreeElements elements) { enqueueInResolution(getExceptionUnwrapper(), elements); + if (jsUnknownClass != null) { + enqueuer.registerInstantiatedClass(jsUnknownClass, elements); + } } void registerWrapException(TreeElements elements) { @@ -1680,7 +1689,8 @@ ? const SourceString("stringSuperTypeCast") : const SourceString('stringSuperTypeCheck'); } - } else if (element == compiler.listClass || element == jsArrayClass) { + } else if ((element == compiler.listClass || element == jsArrayClass) && + type.isRaw) { if (nativeCheckOnly) return null; return typeCast ? const SourceString("listTypeCast") @@ -1704,15 +1714,18 @@ ? const SourceString("interceptedTypeCast") : const SourceString('interceptedTypeCheck'); } else { - if (typeCast) { - return const SourceString("propertyTypeCast"); - } if (type.kind == TypeKind.INTERFACE && !type.isRaw) { - return const SourceString('assertSubtype'); + return typeCast + ? const SourceString('subtypeCast') + : const SourceString('assertSubtype'); } else if (type.kind == TypeKind.TYPE_VARIABLE) { - return const SourceString('assertSubtypeOfRuntimeType'); + return typeCast + ? const SourceString('subtypeOfRuntimeTypeCast') + : const SourceString('assertSubtypeOfRuntimeType'); } else { - return const SourceString('propertyTypeCheck'); + return typeCast + ? const SourceString('propertyTypeCast') + : const SourceString('propertyTypeCheck'); } } }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart index 9273ad7..2b4d152 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -269,8 +269,7 @@ } emittedArgumentCount++; }, - includeBackendMembers: true, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); if ((constant.protoValue == null && emittedArgumentCount != 3) || (constant.protoValue != null && emittedArgumentCount != 4)) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart index a1f1c9a..e269d41 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -1197,8 +1197,7 @@ classElement.implementation.forEachMember( visitMember, - includeBackendMembers: true, - includeSuperMembers: false); + includeBackendMembers: true); if (identical(classElement, compiler.objectClass) && compiler.enabledNoSuchMethod) { @@ -1349,8 +1348,7 @@ // superclasses for non-instantiated classes. classElement.implementation.forEachInstanceField( visitField, - includeBackendMembers: true, - includeSuperMembers: isInstantiated); + includeSuperAndInjectedMembers: isInstantiated); } void generateGetter(Element member, String fieldName, String accessorName, @@ -1800,8 +1798,15 @@ .where(isStaticFunction) .toSet(); + LibraryElement previousLibrary = null; for (Element element in Elements.sortedByPosition(elements)) { CodeBuffer buffer = bufferForElement(element, eagerBuffer); + LibraryElement library = element.getLibrary(); + if (library != previousLibrary) { + previousLibrary = library; + addComment( + 'Library: ${library.getLibraryOrScriptName()}', buffer); + } jsAst.Expression code = backend.generatedCode[element]; emitStaticFunction(buffer, namer.getName(element), code); jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; @@ -1811,6 +1816,9 @@ } } + if (!pendingElementsWithBailouts.isEmpty) { + addComment('pendingElementsWithBailouts', eagerBuffer); + } // Is it possible the primary function was inlined but the bailout was not? for (Element element in Elements.sortedByPosition(pendingElementsWithBailouts)) { @@ -2601,6 +2609,14 @@ ['receiver']))); } else { + ClassElement jsUnknown = backend.jsUnknownClass; + if (compiler.codegenWorld.instantiatedClasses.contains(jsUnknown)) { + block.statements.add( + js.if_(js('!(receiver instanceof #)', + js(namer.isolateAccess(compiler.objectClass))), + buildReturnInterceptor(jsUnknown))); + } + block.statements.add(js.return_(js('receiver'))); } @@ -2958,7 +2974,14 @@ // Might create boundClosures. if (!regularClasses.isEmpty) { addComment('Classes', mainBuffer); + LibraryElement previousLibrary = null; for (ClassElement element in regularClasses) { + LibraryElement library = element.getLibrary(); + if (library != previousLibrary) { + previousLibrary = library; + addComment( + 'Library: ${library.getLibraryOrScriptName()}', mainBuffer); + } generateClass(element, mainBuffer); } }
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 0c02e6e..21f07e2 100644 --- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart +++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -115,7 +115,7 @@ classesNeedingRti.add(cls); // TODO(ngeoffray): This should use subclasses, not subtypes. - Set<ClassElement> classes = compiler.world.subtypes[cls]; + Set<ClassElement> classes = compiler.world.subtypesOf(cls); if (classes != null) { classes.forEach((ClassElement sub) { potentiallyAddForRti(sub);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart index d5dccf6..35de8a8 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
@@ -139,6 +139,9 @@ } record = lookupDispatchRecord(object); + if (record == null) { + return const JSUnknown(); + } setDispatchProperty(JS('', 'Object.getPrototypeOf(#)', object), record); return getNativeInterceptor(object); } @@ -335,6 +338,15 @@ Type get runtimeType => Null; } +class JSUnknown extends Interceptor { + const JSUnknown(); + + String toString() => JS('String', 'String(#)', this); + + int get hashCode => 0; + + Type get runtimeType => null; +} /** * The supertype for JSString and JSArray. Used by the backend as to
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart index f5350d1..56e7221 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -19,7 +19,8 @@ makeDispatchRecord, setDispatchProperty, Interceptor, - JSMutableIndexable; + JSMutableIndexable, + JSUnknown; import "dart:_collection-dev" as _symbol_dev; part 'constant_map.dart'; @@ -294,6 +295,13 @@ /** [: r"$".codeUnitAt(0) :] */ static const int DOLLAR_CHAR_VALUE = 36; + /// Creates a string containing the complete type for the class [className] + /// with the given type arguments. + static String formatType(String className, List typeArguments) { + return '$className${joinArguments(typeArguments, 0)}'; + } + + /// Returns the type of [object] as a string (including type arguments). static String objectTypeName(Object object) { String name = constructorNameFallback(object); if (name == 'Object') { @@ -306,8 +314,10 @@ } // TODO(kasperl): If the namer gave us a fresh global name, we may // want to remove the numeric suffix that makes it unique too. - if (identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) name = name.substring(1); - return name; + if (identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) { + name = name.substring(1); + } + return formatType(name, getRuntimeTypeInfo(object)); } static String objectToString(Object object) { @@ -757,8 +767,13 @@ unwrapException(ex) { // Note that we are checking if the object has the property. If it // has, it could be set to null if the thrown value is null. + if (ex == null) return null; + if (JS('bool', 'typeof # !== "object"', ex)) return ex; + if (JS('bool', r'"dartException" in #', ex)) { return JS('', r'#.dartException', ex); + } else if (!JS('bool', r'"message" in #', ex)) { + return ex; } // Grab hold of the exception message. This field is available on @@ -795,7 +810,7 @@ message.endsWith('is null or undefined') || message.endsWith('of undefined') || message.endsWith('of null')) { - return new NoSuchMethodError(null, '<unknown>', [], {}); + return new NoSuchMethodError(null, message, [], {}); } else if (contains(message, ' has no method ') || contains(message, ' is not a function') || (ieErrorCode == 438 && ieFacilityNumber == 10)) { @@ -805,7 +820,7 @@ // Object doesn't support property or method 'foo' which sets the error // code 438 in IE. // TODO(kasperl): Compute the right name if possible. - return new NoSuchMethodError('', '<unknown>', [], {}); + return new NoSuchMethodError('', message, [], {}); } } @@ -846,7 +861,13 @@ * exception. */ StackTrace getTraceFromException(exception) { - return new _StackTrace(JS("var", r"#.stack", exception)); + if (exception == null) return null; + if (JS('bool', 'typeof # !== "object"', exception)) return null; + if (JS('bool', r'"stack" in #', exception)) { + return new _StackTrace(JS("var", r"#.stack", exception)); + } else { + return null; + } } class _StackTrace implements StackTrace {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart index 2085dc4..21be9af 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
@@ -134,14 +134,27 @@ return checkArguments(substitution, arguments, checks); } +String computeTypeName(String isField, List arguments) { + // Shorten the field name to the class name and append the textual + // representation of the type arguments. + int prefixLength = JS_OPERATOR_IS_PREFIX().length; + return Primitives.formatType(isField.substring(prefixLength, isField.length), + arguments); +} + +Object subtypeCast(Object object, String isField, List checks, String asField) { + if (!checkSubtype(object, isField, checks, asField)) { + String actualType = Primitives.objectTypeName(object); + String typeName = computeTypeName(isField, checks); + throw new CastErrorImplementation(object, typeName); + } + return object; +} + Object assertSubtype(Object object, String isField, List checks, String asField) { if (!checkSubtype(object, isField, checks, asField)) { - // Shorten the field name to the class name and append the textual - // representation of the type arguments. - int prefixLength = JS_OPERATOR_IS_PREFIX().length; - String typeName = '${isField.substring(prefixLength, isField.length)}' - '${joinArguments(checks, 0)}'; + String typeName = computeTypeName(isField, checks); throw new TypeErrorImplementation(object, typeName); } return object; @@ -212,6 +225,14 @@ return isSubtype(type, t); } +Object subtypeOfRuntimeTypeCast(Object object, var type) { + if (!checkSubtypeOfRuntimeType(object, type)) { + String actualType = Primitives.objectTypeName(object); + throw new CastErrorImplementation(actualType, runtimeTypeToString(type)); + } + return object; +} + Object assertSubtypeOfRuntimeType(Object object, var type) { if (!checkSubtypeOfRuntimeType(object, type)) { throw new TypeErrorImplementation(object, runtimeTypeToString(type));
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart index 1fa69ec..b7a1f44 100644 --- a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart +++ b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
@@ -79,9 +79,11 @@ if (object == null) return 'Null'; var constructor = JS('var', "#.constructor", object); if (identical(JS('String', "typeof(#)", constructor), 'function')) { + var name = JS('var', r'#.builtin$cls', constructor); + if (name != null) return name; // The constructor isn't null or undefined at this point. Try // to grab hold of its name. - var name = JS('var', '#.name', constructor); + name = JS('var', '#.name', constructor); // If the name is a non-empty string, we use that as the type // name of this object. On Firefox, we often get 'Object' as // the constructor name even for more specialized objects so @@ -269,6 +271,7 @@ lookupInterceptor(var hasOwnPropertyFunction, String tag) { var map = interceptorsByTag; + if (map == null) return null; return callHasOwnProperty(hasOwnPropertyFunction, map, tag) ? propertyGet(map, tag) : null; @@ -288,11 +291,17 @@ } } if (interceptor == null) { - // TODO(sra): Think about the error case. - interceptor = JS('', '{__what: "interceptor not found", __tag: #}', tag); + // This object is not known to Dart. There could be several + // reasons for that, including (but not limited to): + // * A bug in native code (hopefully this is caught during development). + // * An unknown DOM object encountered. + // * JavaScript code running in an unexpected context. For + // example, on node.js. + return null; } - var isLeaf = JS('', '#[#]', leafTags, tag); - if (true == isLeaf) { + var isLeaf = + (leafTags != null) && JS('bool', '(#[#]) === true', leafTags, tag); + if (isLeaf) { return makeDispatchRecord(interceptor, false, null); } else { var proto = JS('', 'Object.getPrototypeOf(#)', obj);
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart index e196afa..9be802d 100644 --- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart +++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -1587,7 +1587,7 @@ String fieldName = field.name.slowToString(); _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]); index++; - }, includeBackendMembers: true, includeSuperMembers: true); + }, includeSuperAndInjectedMembers: true); } } return _fieldMapCache;
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart index c6a7a9a..b4fe9d9 100644 --- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart +++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -876,7 +876,7 @@ // TODO(johnniwinther): Store the mapping in the resolution enqueuer. element.mapping = mapping; return compiler.withCurrentElement(element, () { - measure(() { + return measure(() { Typedef node = compiler.parser.measure(() => element.parseNode(compiler)); TypedefResolverVisitor visitor = @@ -2201,6 +2201,10 @@ compiler.backend.registerClassUsingVariableExpression(cls); compiler.backend.registerTypeVariableExpression(mapping); } else if (target.impliesType() && !sendIsMemberAccess) { + // Set the type of the node to [Type] to mark this send as a + // type literal. + mapping.setType(node, compiler.typeClass.computeType(compiler)); + world.registerInstantiatedClass(compiler.typeClass, mapping); compiler.backend.registerTypeLiteral(mapping); } } @@ -2556,8 +2560,7 @@ (ClassElement enclosingClass, Element member) { world.addToWorkList(member); }, - includeBackendMembers: false, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); if (isSymbolConstructor) { if (node.isConst()) { @@ -2968,7 +2971,7 @@ } visitCatchBlock(CatchBlock node) { - compiler.backend.registerCatchStatement(mapping); + compiler.backend.registerCatchStatement(world, mapping); // Check that if catch part is present, then // it has one or two formal parameters. if (node.formals != null) { @@ -3740,7 +3743,19 @@ requiredParameterCount = parametersBuilder.length; parameters = parametersBuilder.toLink(); } - DartType returnType = compiler.resolveReturnType(element, returnNode); + DartType returnType; + if (element.isFactoryConstructor()) { + returnType = element.getEnclosingClass().computeType(compiler); + // Because there is no type annotation for the return type of + // this element, we explicitly add one. + if (compiler.enableTypeAssertions) { + compiler.enqueuer.resolution.registerIsCheck( + returnType, new TreeElementMapping(element)); + } + } else { + returnType = compiler.resolveReturnType(element, returnNode); + } + if (element.isSetter() && (requiredParameterCount != 1 || visitor.optionalParameterCount != 0)) { // If there are no formal parameters, we already reported an error above.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart index 1722f9f..ae43bed 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -103,10 +103,7 @@ } HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { - // The body of the constructor will be generated in a separate function. - final ClassElement classElement = work.element.getEnclosingClass(); - return builder.buildFactory(classElement.implementation, - work.element.implementation); + return builder.buildFactory(work.element); } } @@ -279,8 +276,7 @@ builder.graph.thisInstruction = thisInstruction; builder.graph.entry.addAtEntry(thisInstruction); updateLocal(closureData.closureElement, thisInstruction); - } else if (element.isInstanceMember() - || element.isGenerativeConstructor()) { + } else if (element.isInstanceMember()) { // Once closures have been mapped to classes their instance members might // not have any thisElement if the closure was created inside a static // context. @@ -376,7 +372,7 @@ Element redirect = redirectionMapping[element]; HInstruction receiver = readLocal(closureData.closureElement); HInstruction fieldGet = new HFieldGet(redirect, receiver); - fieldGet.instructionType = builder.getTypeOfCapturedVariable(element); + fieldGet.instructionType = builder.getTypeOfCapturedVariable(redirect); builder.add(fieldGet); return fieldGet; } else if (isBoxed(element)) { @@ -389,7 +385,7 @@ assert(redirect.enclosingElement.isVariable()); HInstruction box = readLocal(redirect.enclosingElement); HInstruction lookup = new HFieldGet(redirect, box); - lookup.instructionType = builder.getTypeOfCapturedVariable(element); + lookup.instructionType = builder.getTypeOfCapturedVariable(redirect); builder.add(lookup); return lookup; } else { @@ -1014,6 +1010,7 @@ new Map<Element, HType>(); HType getTypeOfCapturedVariable(Element element) { + assert(element.isField()); return cachedTypesOfCapturedVariables.putIfAbsent(element, () { return new HType.inferredTypeForElement(element, compiler); }); @@ -1116,6 +1113,7 @@ } HParameterValue addParameter(Element element) { + assert(inliningStack.isEmpty); HParameterValue result = new HParameterValue(element); if (lastAddedParameter == null) { graph.entry.addBefore(graph.entry.first, result); @@ -1178,7 +1176,7 @@ // may have an impact on the state of the current method. InliningState state = new InliningState( function, returnElement, returnType, elements, stack, localsHandler); - LocalsHandler newLocalsHandler = new LocalsHandler.from(localsHandler); + LocalsHandler newLocalsHandler = new LocalsHandler(this); newLocalsHandler.closureData = compiler.closureToClassMapper.computeClosureToClassMapping( function, function.parseNode(compiler), elements); @@ -1272,7 +1270,6 @@ if (element is !PartialFunctionElement) return false; // TODO(ngeoffray): try to inline generative constructors. They // don't have any body, which make it more difficult. - if (element.isGenerativeConstructor()) return false; if (inliningStack.length > MAX_INLINING_DEPTH) return false; // Don't inline recursive calls. We use the same elements for the inlined // functions and would thus clobber our local variables. @@ -1319,18 +1316,20 @@ } assert(canBeInlined); - InliningState state = enterInlinedMethod( - function, selector, argumentsNodes, providedArguments, currentNode); - // Add an explicit null check on the receiver. We use [element] - // to get the same name in the NoSuchMethodError message as if we had - // called it. + // Add an explicit null check on the receiver before doing the + // inlining. We use [element] to get the same name in the NoSuchMethodError + // message as if we had called it. if (element.isInstanceMember() && (selector.mask == null || selector.mask.isNullable)) { addWithPosition( new HFieldGet(element, providedArguments[0]), currentNode); } + InliningState state = enterInlinedMethod( + function, selector, argumentsNodes, providedArguments, currentNode); inlinedFrom(element, () { - functionExpression.body.accept(this); + element.isGenerativeConstructor() + ? buildFactory(element) + : functionExpression.body.accept(this); }); leaveInlinedMethod(state); return true; @@ -1436,11 +1435,6 @@ ClosureClassMap newClosureData = compiler.closureToClassMapper.computeClosureToClassMapping( constructor, node, elements); - // The [:this:] element now refers to the one in the new closure - // data, that is the [:this:] of the super constructor. We - // update the element to refer to the current [:this:]. - localsHandler.updateLocal(newClosureData.thisElement, - localsHandler.readThis()); localsHandler.closureData = newClosureData; params.orderedForEachParameter((Element parameterElement) { @@ -1564,9 +1558,7 @@ } fieldValues[member] = value; }); - }, - includeBackendMembers: true, - includeSuperMembers: false); + }); } @@ -1578,21 +1570,20 @@ * to, starting from the current constructor. * - Call the the constructor bodies, starting from the constructor(s) in the * super class(es). - * - * Invariant: Both [classElement] and [functionElement] must be - * implementation elements. */ - HGraph buildFactory(ClassElement classElement, - FunctionElement functionElement) { - assert(invariant(classElement, classElement.isImplementation)); - assert(invariant(functionElement, functionElement.isImplementation)); + HGraph buildFactory(FunctionElement functionElement) { + functionElement = functionElement.implementation; + ClassElement classElement = + functionElement.getEnclosingClass().implementation; FunctionExpression function = functionElement.parseNode(compiler); // Note that constructors (like any other static function) do not need // to deal with optional arguments. It is the callers job to provide all // arguments as if they were positional. - // The initializer list could contain closures. - openFunction(functionElement, function); + if (inliningStack.isEmpty) { + // The initializer list could contain closures. + openFunction(functionElement, function); + } Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); @@ -1624,8 +1615,7 @@ constructorArguments.add(potentiallyCheckType( fieldValues[member], member.computeType(compiler))); }, - includeBackendMembers: true, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); InterfaceType type = classElement.computeType(compiler); HType ssaType = new HType.nonNullExact(type, compiler); @@ -1696,24 +1686,18 @@ bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); } - // TODO(ahe): The constructor name is statically resolved. See - // SsaCodeGenerator.visitInvokeDynamicMethod. Is there a cleaner - // way to do this? - SourceString name = - new SourceString(backend.namer.getName(body.declaration)); - // TODO(kasperl): This seems fishy. We shouldn't be inventing all - // these selectors. Maybe the resolver can do more of the work - // for us here? - LibraryElement library = body.getLibrary(); - Selector selector = new Selector.call( - name, library, bodyCallInputs.length - 1); - HInvokeDynamic invoke = - new HInvokeDynamicMethod(selector, bodyCallInputs); - invoke.element = body; + HInvokeConstructorBody invoke = + new HInvokeConstructorBody(body, bodyCallInputs); + invoke.sideEffects = compiler.world.getSideEffectsOfElement(constructor); add(invoke); } - closeAndGotoExit(new HReturn(newObject)); - return closeFunction(); + if (inliningStack.isEmpty) { + closeAndGotoExit(new HReturn(newObject)); + return closeFunction(); + } else { + localsHandler.updateLocal(returnElement, newObject); + return null; + } } void addParameterCheckInstruction(Element element) { @@ -1830,14 +1814,12 @@ } } - HInstruction buildTypeConversion(Compiler compiler, HInstruction original, - DartType type, int kind) { + HInstruction buildTypeConversion(HInstruction original, + DartType type, + int kind) { if (type == null) return original; if (type.kind == TypeKind.INTERFACE && !type.isMalformed && !type.isRaw) { HType subtype = new HType.subtype(type, compiler); - if (type.isRaw) { - return new HTypeConversion(type, kind, subtype, original); - } HInstruction representations = buildTypeArgumentRepresentations(type); add(representations); return new HTypeConversion.withTypeRepresentation(type, kind, subtype, @@ -1855,8 +1837,7 @@ HInstruction potentiallyCheckType(HInstruction original, DartType type, { int kind: HTypeConversion.CHECKED_MODE_CHECK }) { if (!compiler.enableTypeAssertions) return original; - HInstruction other = - buildTypeConversion(compiler, original, type, kind); + HInstruction other = buildTypeConversion(original, type, kind); if (other != original) add(other); return other; } @@ -2487,10 +2468,9 @@ // TODO(ahe): This should be registered in codegen, not here. compiler.enqueuer.codegen.registerInstantiatedClass( closureClassElement, work.resolutionTree); - assert(!closureClassElement.hasLocalScopeMembers); List<HInstruction> capturedVariables = <HInstruction>[]; - closureClassElement.forEachBackendMember((Element member) { + closureClassElement.forEachMember((_, Element member) { // The backendMembers also contains the call method(s). We are only // interested in the fields. if (member.isField()) { @@ -2802,8 +2782,8 @@ Node argument = node.arguments.head; TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); DartType type = elements.getType(typeAnnotation); - HInstruction converted = expression.convertType( - compiler, type, HTypeConversion.CAST_TYPE_CHECK); + HInstruction converted = buildTypeConversion( + expression, type, HTypeConversion.CAST_TYPE_CHECK); if (converted != expression) add(converted); stack.add(converted); } else { @@ -2847,7 +2827,7 @@ return new HIs(type, <HInstruction>[expression, call], HIs.VARIABLE_CHECK); } else if (RuntimeTypes.hasTypeArguments(type)) { - Element element = type.element; + ClassElement element = type.element; Element helper = backend.getCheckSubtype(); HInstruction representations = buildTypeArgumentRepresentations(type); @@ -2855,10 +2835,9 @@ String operator = backend.namer.operatorIs(backend.getImplementationClass(element)); HInstruction isFieldName = addConstantString(node, operator); - // TODO(karlklose): use [:null:] for [asField] if [element] does not - // have a subclass. - HInstruction asFieldName = - addConstantString(node, backend.namer.substitutionName(element)); + HInstruction asFieldName = compiler.world.hasAnySubtype(element) + ? addConstantString(node, backend.namer.substitutionName(element)) + : graph.addConstantNull(constantSystem); List<HInstruction> inputs = <HInstruction>[expression, isFieldName, representations, @@ -4274,21 +4253,14 @@ visitLabeledStatement(LabeledStatement node) { Statement body = node.statement; - if (body is Loop || body is SwitchStatement) { + if (body is Loop + || body is SwitchStatement + || Elements.isUnusedLabel(node, elements)) { // Loops and switches handle their own labels. visit(body); return; } - // Non-loop statements can only be break targets, not continue targets. TargetElement targetElement = elements[body]; - if (targetElement == null || !identical(targetElement.statement, body)) { - // Labeled statements with no element on the body have no breaks. - // A different target statement only happens if the body is itself - // a break or continue for a different target. In that case, this - // label is also always unused. - visit(body); - return; - } LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); assert(targetElement.isBreakTarget); JumpHandler handler = new JumpHandler(this, targetElement); @@ -5083,6 +5055,7 @@ static bool canBeInlined(FunctionExpression functionExpression, TreeElements elements) { InlineWeeder weeder = new InlineWeeder(elements); + weeder.visit(functionExpression.initializers); weeder.visit(functionExpression.body); if (weeder.tooDifficult) return false; return true; @@ -5098,7 +5071,7 @@ } void visit(Node node) { - node.accept(this); + if (node != null) node.accept(this); } void visitNode(Node node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart index 48d4466..d420f27 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -741,6 +741,10 @@ js.Catch catchPart = null; js.Block finallyPart = null; if (info.catchBlock != null) { + if (backend.jsUnknownClass != null) { + world.registerInstantiatedClass( + backend.jsUnknownClass, work.resolutionTree); + } HLocalValue exception = info.catchVariable; String name = variableNames.getName(exception); js.VariableDeclaration decl = new js.VariableDeclaration(name); @@ -1483,32 +1487,26 @@ List<js.Expression> arguments = visitArguments(node.inputs); Element target = node.element; - if (target != null) { - // Avoid adding the generative constructor name to the list of - // seen selectors. - if (target.isGenerativeConstructorBody()) { - methodName = name.slowToString(); - } else if (!node.isInterceptedCall) { - if (target == backend.jsArrayAdd) { - methodName = 'push'; - } else if (target == backend.jsArrayRemoveLast) { - methodName = 'pop'; - } else if (target == backend.jsStringSplit) { - methodName = 'split'; - // Split returns a List, so we make sure the backend knows the - // list class is instantiated. - world.registerInstantiatedClass( - compiler.listClass, work.resolutionTree); - } else if (target == backend.jsStringConcat) { - push(new js.Binary('+', object, arguments[0]), node); - return; - } else if (target.isNative() && target.isFunction() - && !node.isInterceptedCall) { - // A direct (i.e. non-interceptor) native call is the result of - // optimization. The optimization ensures any type checks or - // conversions have been satisified. - methodName = target.fixedBackendName(); - } + if (target != null && !node.isInterceptedCall) { + if (target == backend.jsArrayAdd) { + methodName = 'push'; + } else if (target == backend.jsArrayRemoveLast) { + methodName = 'pop'; + } else if (target == backend.jsStringSplit) { + methodName = 'split'; + // Split returns a List, so we make sure the backend knows the + // list class is instantiated. + world.registerInstantiatedClass( + compiler.listClass, work.resolutionTree); + } else if (target == backend.jsStringConcat) { + push(new js.Binary('+', object, arguments[0]), node); + return; + } else if (target.isNative() && target.isFunction() + && !node.isInterceptedCall) { + // A direct (i.e. non-interceptor) native call is the result of + // optimization. The optimization ensures any type checks or + // conversions have been satisified. + methodName = target.fixedBackendName(); } } @@ -1519,6 +1517,14 @@ push(jsPropertyCall(object, methodName, arguments), node); } + void visitInvokeConstructorBody(HInvokeConstructorBody node) { + use(node.inputs[0]); + js.Expression object = pop(); + String methodName = backend.namer.getName(node.element); + List<js.Expression> arguments = visitArguments(node.inputs); + push(jsPropertyCall(object, methodName, arguments), node); + } + void visitOneShotInterceptor(HOneShotInterceptor node) { List<js.Expression> arguments = visitArguments(node.inputs); var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart index ce3c0e3..c29f3e8 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
@@ -357,11 +357,17 @@ // the builder. Mark the if instruction as such. controlFlowOperators.add(startIf); + // Find the next non-HGoto instruction following the phi. + HInstruction nextInstruction = phi.block.first; + while (nextInstruction is HGoto) { + nextInstruction = nextInstruction.block.successors[0].first; + } + // If the operation is only used by the first instruction // of its block and is safe to be generated at use site, mark it // so. if (phi.usedBy.length == 1 - && identical(phi.usedBy[0], phi.block.first) + && phi.usedBy[0] == nextInstruction && isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { markAsGenerateAtUseSite(phi); }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart index 2eb8faa..088fe6e 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -37,6 +37,7 @@ R visitInvokeDynamicSetter(HInvokeDynamicSetter node); R visitInvokeStatic(HInvokeStatic node); R visitInvokeSuper(HInvokeSuper node); + R visitInvokeConstructorBody(HInvokeConstructorBody node); R visitIs(HIs node); R visitLazyStatic(HLazyStatic node); R visitLess(HLess node); @@ -303,6 +304,8 @@ visitInterceptor(HInterceptor node) => visitInstruction(node); visitInvokeClosure(HInvokeClosure node) => visitInvokeDynamic(node); + visitInvokeConstructorBody(HInvokeConstructorBody node) + => visitInvokeStatic(node); visitInvokeDynamicMethod(HInvokeDynamicMethod node) => visitInvokeDynamic(node); visitInvokeDynamicGetter(HInvokeDynamicGetter node) @@ -310,7 +313,7 @@ visitInvokeDynamicSetter(HInvokeDynamicSetter node) => visitInvokeDynamicField(node); visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); - visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); + visitInvokeSuper(HInvokeSuper node) => visitInvokeStatic(node); visitJump(HJump node) => visitControlFlow(node); visitLazyStatic(HLazyStatic node) => visitInstruction(node); visitLess(HLess node) => visitRelational(node); @@ -1083,6 +1086,15 @@ HInstruction convertType(Compiler compiler, DartType type, int kind) { if (type == null) return this; + // Only the builder knows how to create [HTypeConversion] + // instructions with generics. It has the generic type context + // available. + assert(type.kind != TypeKind.TYPE_VARIABLE); + // TODO(5022): Generic typedefs should not be handled here. + assert(type.isRaw + || type.isMalformed + || type.kind == TypeKind.TYPEDEF + || type.kind == TypeKind.FUNCTION); if (identical(type.element, compiler.dynamicClass)) return this; if (identical(type.element, compiler.objectClass)) return this; if (type.isMalformed || type.kind != TypeKind.INTERFACE) { @@ -1399,6 +1411,14 @@ } } +class HInvokeConstructorBody extends HInvokeStatic { + HInvokeConstructorBody(element, inputs) + : super(element, inputs, HType.UNKNOWN); + + String toString() => 'invoke constructor body: ${element.name}'; + accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this); +} + abstract class HFieldAccess extends HInstruction { final Element element;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart index 09df7c1..26523a5 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1586,8 +1586,7 @@ element, node.inputs[j].instructionType); j++; }, - includeBackendMembers: false, - includeSuperMembers: true); + includeSuperAndInjectedMembers: true); } visitFieldSet(HFieldSet node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart index f11f5d5..02d7cfe 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -355,9 +355,7 @@ String visitInvokeStatic(HInvokeStatic invoke) { String target = invoke.element.name.slowToString(); - int offset = HInvoke.ARGUMENTS_OFFSET; - List arguments = invoke.inputs.sublist(offset); - return visitGenericInvoke("Invoke", target, arguments); + return visitGenericInvoke("Invoke", target, invoke.inputs); } String visitInvokeSuper(HInvokeSuper invoke) { @@ -367,6 +365,13 @@ return visitGenericInvoke("Invoke super", target, arguments); } + String visitInvokeConstructorBody(HInvokeConstructorBody invoke) { + String target = invoke.element.name.slowToString(); + int offset = HInvoke.ARGUMENTS_OFFSET + 1; + List arguments = invoke.inputs.sublist(offset); + return visitGenericInvoke("Invoke constructor body", target, arguments); + } + String visitForeign(HForeign foreign) { return visitGenericInvoke("Foreign", "${foreign.codeAst}", foreign.inputs); }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart index 20a0b64..d1d22bf 100644 --- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart +++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -18,11 +18,13 @@ return isNullable ? HType.NULL : HType.CONFLICTING; } + JavaScriptBackend backend = compiler.backend; if (mask.containsOnlyInt(compiler)) { return isNullable ? HType.INTEGER_OR_NULL : HType.INTEGER; } else if (mask.containsOnlyDouble(compiler)) { return isNullable ? HType.DOUBLE_OR_NULL : HType.DOUBLE; - } else if (mask.containsOnlyNum(compiler)) { + } else if (mask.containsOnlyNum(compiler) + || mask.satisfies(backend.jsNumberClass, compiler)) { return isNullable ? HType.NUMBER_OR_NULL : HType.NUMBER; } else if (mask.containsOnlyString(compiler)) { return isNullable ? HType.STRING_OR_NULL : HType.STRING; @@ -38,18 +40,17 @@ return isNullable ? HType.UNKNOWN : HType.NON_NULL; } - JavaScriptBackend backend = compiler.backend; if (!isNullable) { - if (mask.containsOnly(backend.jsIndexableClass)) { - return HType.INDEXABLE_PRIMITIVE; - } else if (mask.containsOnly(backend.jsArrayClass)) { - return HType.READABLE_ARRAY; - } else if (mask.containsOnly(backend.jsMutableArrayClass)) { - return HType.MUTABLE_ARRAY; - } else if (mask.containsOnly(backend.jsFixedArrayClass)) { + if (mask.containsOnly(backend.jsFixedArrayClass)) { return HType.FIXED_ARRAY; } else if (mask.containsOnly(backend.jsExtendableArrayClass)) { return HType.EXTENDABLE_ARRAY; + } else if (mask.satisfies(backend.jsMutableArrayClass, compiler)) { + return HType.MUTABLE_ARRAY; + } else if (mask.satisfies(backend.jsArrayClass, compiler)) { + return HType.READABLE_ARRAY; + } else if (mask.satisfies(backend.jsIndexableClass, compiler)) { + return HType.INDEXABLE_PRIMITIVE; } } return new HBoundedType(mask); @@ -270,6 +271,8 @@ TypeMask union = mask.union(otherMask, compiler); return new HType.fromMask(union, compiler); } + + HType simplify(Compiler compiler) => this; } /** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */ @@ -561,7 +564,11 @@ bool canBePrimitiveNumber(Compiler compiler) { JavaScriptBackend backend = compiler.backend; DartType jsNumberType = backend.jsNumberClass.computeType(compiler); - return mask.contains(jsNumberType, compiler); + DartType jsIntType = backend.jsIntClass.computeType(compiler); + DartType jsDoubleType = backend.jsDoubleClass.computeType(compiler); + return mask.contains(jsNumberType, compiler) + || mask.contains(jsIntType, compiler) + || mask.contains(jsDoubleType, compiler); } bool canBePrimitiveBoolean(Compiler compiler) { @@ -588,6 +595,10 @@ TypeMask computeMask(Compiler compiler) => mask; + HType simplify(Compiler compiler) { + return new HType.fromMask(mask.simplify(compiler), compiler); + } + bool operator ==(HType other) { if (other is !HBoundedType) return false; HBoundedType bounded = other;
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart index 24faf77..b58a0eb 100644 --- a/sdk/lib/_internal/compiler/implementation/typechecker.dart +++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -18,6 +18,22 @@ } /** + * Class used to report different warnings for differrent kinds of members. + */ +class MemberKind { + static const MemberKind METHOD = const MemberKind("method"); + static const MemberKind OPERATOR = const MemberKind("operator"); + static const MemberKind PROPERTY = const MemberKind("property"); + + final String name; + + const MemberKind(this.name); + + String toString() => name; +} + + +/** * [ElementAccess] represents the access of [element], either as a property * access or invocation. */ @@ -49,6 +65,8 @@ Element get element => member.element; DartType computeType(Compiler compiler) => member.computeType(compiler); + + String toString() => 'MemberAccess($member)'; } /// An access of an unresolved element. @@ -60,6 +78,8 @@ DartType computeType(Compiler compiler) => compiler.types.dynamicType; bool isCallable(Compiler compiler) => true; + + String toString() => 'DynamicAccess'; } /** @@ -73,7 +93,19 @@ assert(element != null); } - DartType computeType(Compiler compiler) => element.computeType(compiler); + DartType computeType(Compiler compiler) { + if (element.isGetter()) { + FunctionType functionType = element.computeType(compiler); + return functionType.returnType; + } else if (element.isSetter()) { + FunctionType functionType = element.computeType(compiler); + return functionType.parameterTypes.head; + } else { + return element.computeType(compiler); + } + } + + String toString() => 'ResolvedAccess($element)'; } /** @@ -89,6 +121,23 @@ Element get element => type.element; DartType computeType(Compiler compiler) => type; + + String toString() => 'TypeAccess($type)'; +} + +/** + * An access of a type literal. + */ +class TypeLiteralAccess extends ElementAccess { + final Element element; + TypeLiteralAccess(Element this.element) { + assert(element != null); + } + + DartType computeType(Compiler compiler) => + compiler.typeClass.computeType(compiler); + + String toString() => 'TypeLiteralAccess($element)'; } class TypeCheckerVisitor implements Visitor<DartType> { @@ -98,7 +147,7 @@ Node lastSeenNode; DartType expectedReturnType; - ClassElement currentClass; + final ClassElement currentClass; Link<DartType> cascadeTypes = const Link<DartType>(); @@ -109,7 +158,10 @@ DartType objectType; DartType listType; - TypeCheckerVisitor(this.compiler, this.elements, this.types) { + TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) + : this.elements = elements, + currentClass = elements.currentElement != null + ? elements.currentElement.getEnclosingClass() : null { intType = compiler.intClass.computeType(compiler); doubleType = compiler.doubleClass.computeType(compiler); boolType = compiler.boolClass.computeType(compiler); @@ -122,6 +174,11 @@ compiler.reportWarning(node, new TypeWarning(kind, arguments)); } + reportTypeInfo(Spannable node, MessageKind kind, [Map arguments = const {}]) { + compiler.reportDiagnostic(compiler.spanFromSpannable(node), + 'Info: ${kind.message(arguments)}', api.Diagnostic.INFO); + } + // TODO(karlklose): remove these functions. DartType unhandledStatement() => StatementType.NOT_RETURNING; DartType unhandledExpression() => types.dynamicType; @@ -160,15 +217,17 @@ * Check if a value of type t can be assigned to a variable, * parameter or return value of type s. */ - checkAssignable(Node node, DartType s, DartType t) { - if (!types.isAssignable(s, t)) { + bool checkAssignable(Node node, DartType from, DartType to) { + if (!types.isAssignable(from, to)) { reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, - {'fromType': s, 'toType': t}); + {'fromType': from, 'toType': to}); + return false; } + return true; } checkCondition(Expression condition) { - checkAssignable(condition, boolType, analyze(condition)); + checkAssignable(condition, analyze(condition), boolType); } void pushCascadeType(DartType type) { @@ -260,7 +319,6 @@ } DartType previous = expectedReturnType; expectedReturnType = returnType; - if (element.isMember()) currentClass = element.getEnclosingClass(); StatementType bodyType = analyze(node.body); if (returnType != types.voidType && returnType != types.dynamicType && bodyType != StatementType.RETURNING) { @@ -297,7 +355,8 @@ return unhandledStatement(); } - ElementAccess lookupMethod(Node node, DartType type, SourceString name) { + ElementAccess lookupMember(Node node, DartType type, SourceString name, + MemberKind memberKind) { if (identical(type, types.dynamicType)) { return const DynamicAccess(); } @@ -305,17 +364,35 @@ if (member != null) { return new MemberAccess(member); } - reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, - {'className': type.name, 'memberName': name}); + switch (memberKind) { + case MemberKind.METHOD: + reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, + {'className': type.name, 'memberName': name}); + break; + case MemberKind.OPERATOR: + reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND, + {'className': type.name, 'memberName': name}); + break; + case MemberKind.PROPERTY: + reportTypeWarning(node, MessageKind.PROPERTY_NOT_FOUND, + {'className': type.name, 'memberName': name}); + break; + } return const DynamicAccess(); } - // TODO(johnniwinther): Provide the element from which the type came in order - // to give better error messages. - void analyzeArguments(Send send, DartType type) { + DartType lookupMemberType(Node node, DartType type, SourceString name, + MemberKind memberKind) { + return lookupMember(node, type, name, memberKind).computeType(compiler); + } + + void analyzeArguments(Send send, Element element, DartType type, + [LinkBuilder<DartType> argumentTypes]) { Link<Node> arguments = send.arguments; DartType unaliasedType = type.unalias(compiler); if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { + assert(invariant(send, element != null, message: 'No element for $send')); + bool error = false; FunctionType funType = unaliasedType; Link<DartType> parameterTypes = funType.parameterTypes; Link<DartType> optionalParameterTypes = funType.optionalParameterTypes; @@ -328,57 +405,80 @@ DartType namedParameterType = funType.getNamedParameterType(argumentName); if (namedParameterType == null) { + error = true; // TODO(johnniwinther): Provide better information on the called // function. reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND, {'argumentName': argumentName}); - analyze(argument); + DartType argumentType = analyze(argument); + if (argumentTypes != null) argumentTypes.addLast(argumentType); } else { - checkAssignable(argument, namedParameterType, analyze(argument)); + DartType argumentType = analyze(argument); + if (argumentTypes != null) argumentTypes.addLast(argumentType); + if (!checkAssignable(argument, argumentType, namedParameterType)) { + error = true; + } } } else { if (parameterTypes.isEmpty) { if (optionalParameterTypes.isEmpty) { + error = true; // TODO(johnniwinther): Provide better information on the // called function. reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT); - analyze(argument); + DartType argumentType = analyze(argument); + if (argumentTypes != null) argumentTypes.addLast(argumentType); } else { - checkAssignable(argument, optionalParameterTypes.head, - analyze(argument)); + DartType argumentType = analyze(argument); + if (argumentTypes != null) argumentTypes.addLast(argumentType); + if (!checkAssignable(argument, + argumentType, optionalParameterTypes.head)) { + error = true; + } optionalParameterTypes = optionalParameterTypes.tail; } } else { - checkAssignable(argument, parameterTypes.head, analyze(argument)); + DartType argumentType = analyze(argument); + if (argumentTypes != null) argumentTypes.addLast(argumentType); + if (!checkAssignable(argument, argumentType, parameterTypes.head)) { + error = true; + } parameterTypes = parameterTypes.tail; } } arguments = arguments.tail; } if (!parameterTypes.isEmpty) { + error = true; // TODO(johnniwinther): Provide better information on the called // function. reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, {'argumentType': parameterTypes.head}); } + if (error) { + reportTypeInfo(element, MessageKind.THIS_IS_THE_METHOD); + } } else { while(!arguments.isEmpty) { - analyze(arguments.head); + DartType argumentType = analyze(arguments.head); + if (argumentTypes != null) argumentTypes.addLast(argumentType); arguments = arguments.tail; } } } - DartType analyzeInvocation(Send node, ElementAccess elementAccess) { + DartType analyzeInvocation(Send node, ElementAccess elementAccess, + [LinkBuilder<DartType> argumentTypes]) { DartType type = elementAccess.computeType(compiler); if (elementAccess.isCallable(compiler)) { - analyzeArguments(node, type); + analyzeArguments(node, elementAccess.element, type, argumentTypes); } else { reportTypeWarning(node, MessageKind.NOT_CALLABLE, {'elementName': elementAccess.element.name}); - analyzeArguments(node, types.dynamicType); + analyzeArguments(node, elementAccess.element, types.dynamicType, + argumentTypes); } if (identical(type.kind, TypeKind.FUNCTION)) { FunctionType funType = type; @@ -388,6 +488,104 @@ } } + /** + * Computes the [ElementAccess] for [name] on the [node] possibly using the + * [element] provided for [node] by the resolver. + */ + ElementAccess computeAccess(Send node, SourceString name, Element element, + MemberKind memberKind) { + if (node.receiver != null) { + Element receiverElement = elements[node.receiver]; + if (receiverElement != null) { + if (receiverElement.isPrefix()) { + assert(invariant(node, element != null, + message: 'Prefixed node has no element.')); + return computeResolvedAccess(node, name, element, memberKind); + } + } + // e.foo() for some expression e. + DartType receiverType = analyze(node.receiver); + if (receiverType.isDynamic || + receiverType.isMalformed || + receiverType.isVoid) { + return const DynamicAccess(); + } + TypeKind receiverKind = receiverType.kind; + if (identical(receiverKind, TypeKind.TYPEDEF)) { + // TODO(johnniwinther): handle typedefs. + return const DynamicAccess(); + } + if (identical(receiverKind, TypeKind.FUNCTION)) { + // TODO(johnniwinther): handle functions. + return const DynamicAccess(); + } + if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) { + // TODO(johnniwinther): handle type variables. + return const DynamicAccess(); + } + assert(invariant(node.receiver, + identical(receiverKind, TypeKind.INTERFACE), + message: "interface type expected, got ${receiverKind}")); + return lookupMember(node, receiverType, name, memberKind); + } else { + return computeResolvedAccess(node, name, element, memberKind); + } + } + + /** + * Computes the [ElementAccess] for [name] on the [node] using the [element] + * provided for [node] by the resolver. + */ + ElementAccess computeResolvedAccess(Send node, SourceString name, + Element element, MemberKind memberKind) { + if (Elements.isUnresolved(element)) { + // foo() where foo is unresolved. + return const DynamicAccess(); + } else if (element.isMember()) { + // foo() where foo is an instance member. + return lookupMember(node, currentClass.computeType(compiler), + name, memberKind); + } else if (element.isFunction()) { + // foo() where foo is a method in the same class. + return new ResolvedAccess(element); + } else if (element.isVariable() || + element.isParameter() || + element.isField()) { + // foo() where foo is a field in the same class. + return new ResolvedAccess(element); + } else if (element.impliesType()) { + // The literal `Foo` where Foo is a class, a typedef, or a type variable. + if (elements.getType(node) != null) { + assert(invariant(node, identical(compiler.typeClass, + elements.getType(node).element), + message: 'Expected type literal type: ' + '${elements.getType(node)}')); + return new TypeLiteralAccess(element); + } + return new ResolvedAccess(element); + } else if (element.isGetter() || element.isSetter()) { + return new ResolvedAccess(element); + } else { + compiler.internalErrorOnElement( + element, 'unexpected element kind ${element.kind}'); + } + } + + /** + * Computes the type of the access of [name] on the [node] possibly using the + * [element] provided for [node] by the resolver. + */ + DartType computeAccessType(Send node, SourceString name, Element element, + MemberKind memberKind) { + DartType type = + computeAccess(node, name, element, memberKind).computeType(compiler); + if (type == null) { + compiler.internalError('type is null on access of $name on $node', + node: node); + } + return type; + } + DartType visitSend(Send node) { Element element = elements[node]; @@ -408,117 +606,252 @@ if (node.isOperator && identical(name, 'is')) { analyze(node.receiver); return boolType; + } if (node.isOperator && identical(name, 'as')) { + analyze(node.receiver); + return elements.getType(node.arguments.head); } else if (node.isOperator) { - final Node firstArgument = node.receiver; - final DartType firstArgumentType = analyze(node.receiver); - final arguments = node.arguments; - final Node secondArgument = arguments.isEmpty ? null : arguments.head; - final DartType secondArgumentType = - analyzeWithDefault(secondArgument, null); - - if (identical(name, '+') || identical(name, '=') || - identical(name, '-') || identical(name, '*') || - identical(name, '/') || identical(name, '%') || - identical(name, '~/') || identical(name, '|') || - identical(name, '&') || identical(name, '^') || - identical(name, '~')|| identical(name, '<<') || - identical(name, '>>') || identical(name, '[]')) { - return types.dynamicType; - } else if (identical(name, '<') || identical(name, '>') || - identical(name, '<=') || identical(name, '>=') || - identical(name, '==') || identical(name, '!=') || - identical(name, '===') || identical(name, '!==')) { + final Node receiver = node.receiver; + final DartType receiverType = analyze(receiver); + if (identical(name, '==') || identical(name, '!=') + // TODO(johnniwinther): Remove these. + || identical(name, '===') || identical(name, '!==')) { + // Analyze argument. + analyze(node.arguments.head); return boolType; } else if (identical(name, '||') || - identical(name, '&&') || - identical(name, '!')) { - checkAssignable(firstArgument, boolType, firstArgumentType); - if (!arguments.isEmpty) { - // TODO(karlklose): check number of arguments in validator. - checkAssignable(secondArgument, boolType, secondArgumentType); - } + identical(name, '&&')) { + checkAssignable(receiver, receiverType, boolType); + final Node argument = node.arguments.head; + final DartType argumentType = analyze(argument); + checkAssignable(argument, argumentType, boolType); return boolType; - } else { - return unhandledExpression(); + } else if (identical(name, '!')) { + checkAssignable(receiver, receiverType, boolType); + return boolType; + } else if (identical(name, '?')) { + return boolType; } + SourceString operatorName = selector.source; + if (identical(name, '-') && node.arguments.isEmpty) { + operatorName = const SourceString('unary-'); + } + assert(invariant(node, + identical(name, '+') || identical(name, '=') || + identical(name, '-') || identical(name, '*') || + identical(name, '/') || identical(name, '%') || + identical(name, '~/') || identical(name, '|') || + identical(name, '&') || identical(name, '^') || + identical(name, '~')|| identical(name, '<<') || + identical(name, '>>') || + identical(name, '<') || identical(name, '>') || + identical(name, '<=') || identical(name, '>=') || + identical(name, '[]'), + message: 'Unexpected operator $name')); + ElementAccess access = lookupMember(node, receiverType, + operatorName, MemberKind.OPERATOR); + LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>(); + DartType resultType = + analyzeInvocation(node, access, argumentTypesBuilder); + if (identical(receiverType.element, compiler.intClass)) { + if (identical(name, '+') || + identical(operatorName, const SourceString('-')) || + identical(name, '*') || + identical(name, '%')) { + DartType argumentType = argumentTypesBuilder.toLink().head; + if (identical(argumentType.element, compiler.intClass)) { + return intType; + } else if (identical(argumentType.element, compiler.doubleClass)) { + return doubleType; + } + } + } + return resultType; } else if (node.isPropertyAccess) { - if (node.receiver != null) { - // TODO(karlklose): we cannot handle fields. - return unhandledExpression(); - } - if (element == null) return types.dynamicType; - return computeType(element); - + ElementAccess access = + computeAccess(node, selector.source, element, MemberKind.PROPERTY); + return access.computeType(compiler); } else if (node.isFunctionObjectInvocation) { return unhandledExpression(); } else { - ElementAccess computeMethod() { - if (node.receiver != null) { - // e.foo() for some expression e. - DartType receiverType = analyze(node.receiver); - if (receiverType.element == compiler.dynamicClass || - receiverType == null || - receiverType.isMalformed || - receiverType.isVoid) { - return const DynamicAccess(); - } - TypeKind receiverKind = receiverType.kind; - if (identical(receiverKind, TypeKind.TYPEDEF)) { - // TODO(karlklose): handle typedefs. - return const DynamicAccess(); - } - if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) { - // TODO(karlklose): handle type variables. - return const DynamicAccess(); - } - if (identical(receiverKind, TypeKind.FUNCTION)) { - // TODO(karlklose): handle getters. - return const DynamicAccess(); - } - assert(invariant(node.receiver, - identical(receiverKind, TypeKind.INTERFACE), - message: "interface type expected, got ${receiverKind}")); - return lookupMethod(selector, receiverType, selector.source); - } else { - if (Elements.isUnresolved(element)) { - // foo() where foo is unresolved. - return const DynamicAccess(); - } else if (element.isFunction()) { - // foo() where foo is a method in the same class. - return new ResolvedAccess(element); - } else if (element.isVariable() || element.isField()) { - // foo() where foo is a field in the same class. - return new ResolvedAccess(element); - } else if (element.isGetter()) { - // TODO(karlklose): handle getters. - return const DynamicAccess(); - } else if (element.isClass()) { - // TODO(karlklose): handle type literals. - return const DynamicAccess(); - } else { - compiler.internalErrorOnElement( - element, 'unexpected element kind ${element.kind}'); - } - } - } - return analyzeInvocation(node, computeMethod()); + ElementAccess access = + computeAccess(node, selector.source, element, MemberKind.METHOD); + return analyzeInvocation(node, access); } } + /** + * Checks [: target o= value :] for some operator o, and returns the type + * of the result. This method also handles increment/decrement expressions + * like [: target++ :]. + */ + DartType checkAssignmentOperator(SendSet node, + SourceString operatorName, + Node valueNode, + DartType value) { + assert(invariant(node, !node.isIndex)); + Element element = elements[node]; + Identifier selector = node.selector; + DartType target = + computeAccessType(node, selector.source, element, MemberKind.PROPERTY); + // [operator] is the type of operator+ or operator- on [target]. + DartType operator = + lookupMemberType(node, target, operatorName, MemberKind.OPERATOR); + if (operator is FunctionType) { + FunctionType operatorType = operator; + // [result] is the type of target o value. + DartType result = operatorType.returnType; + DartType operatorArgument = operatorType.parameterTypes.head; + // Check target o value. + bool validValue = checkAssignable(valueNode, value, operatorArgument); + if (validValue || !(node.isPrefix || node.isPostfix)) { + // Check target = result. + checkAssignable(node.assignmentOperator, result, target); + } + return node.isPostfix ? target : result; + } + return types.dynamicType; + } + + /** + * Checks [: base[key] o= value :] for some operator o, and returns the type + * of the result. This method also handles increment/decrement expressions + * like [: base[key]++ :]. + */ + DartType checkIndexAssignmentOperator(SendSet node, + SourceString operatorName, + Node valueNode, + DartType value) { + assert(invariant(node, node.isIndex)); + final DartType base = analyze(node.receiver); + final Node keyNode = node.arguments.head; + final DartType key = analyze(keyNode); + + // [indexGet] is the type of operator[] on [base]. + DartType indexGet = lookupMemberType( + node, base, const SourceString('[]'), MemberKind.OPERATOR); + if (indexGet is FunctionType) { + FunctionType indexGetType = indexGet; + DartType indexGetKey = indexGetType.parameterTypes.head; + // Check base[key]. + bool validKey = checkAssignable(keyNode, key, indexGetKey); + + // [element] is the type of base[key]. + DartType element = indexGetType.returnType; + // [operator] is the type of operator o on [element]. + DartType operator = lookupMemberType( + node, element, operatorName, MemberKind.OPERATOR); + if (operator is FunctionType) { + FunctionType operatorType = operator; + + // Check base[key] o value. + DartType operatorArgument = operatorType.parameterTypes.head; + bool validValue = checkAssignable(valueNode, value, operatorArgument); + + // [result] is the type of base[key] o value. + DartType result = operatorType.returnType; + + // [indexSet] is the type of operator[]= on [base]. + DartType indexSet = lookupMemberType( + node, base, const SourceString('[]='), MemberKind.OPERATOR); + if (indexSet is FunctionType) { + FunctionType indexSetType = indexSet; + DartType indexSetKey = indexSetType.parameterTypes.head; + DartType indexSetValue = + indexSetType.parameterTypes.tail.head; + + if (validKey || indexGetKey != indexSetKey) { + // Only check base[key] on []= if base[key] was valid for [] or + // if the key types differ. + checkAssignable(keyNode, key, indexSetKey); + } + // Check base[key] = result + if (validValue || !(node.isPrefix || node.isPostfix)) { + checkAssignable(node.assignmentOperator, result, indexSetValue); + } + } + return node.isPostfix ? element : result; + } + } + return types.dynamicType; + } + visitSendSet(SendSet node) { + Element element = elements[node]; Identifier selector = node.selector; final name = node.assignmentOperator.source.stringValue; - if (identical(name, '++') || identical(name, '--')) { - final Element element = elements[node.selector]; - final DartType receiverType = computeType(element); - // TODO(karlklose): this should be the return type instead of int. - return node.isPrefix ? intType : receiverType; + if (identical(name, '=')) { + // e1 = value + if (node.isIndex) { + // base[key] = value + final DartType base = analyze(node.receiver); + final Node keyNode = node.arguments.head; + final DartType key = analyze(keyNode); + final Node valueNode = node.arguments.tail.head; + final DartType value = analyze(valueNode); + DartType indexSet = lookupMemberType( + node, base, const SourceString('[]='), MemberKind.OPERATOR); + if (indexSet is FunctionType) { + FunctionType indexSetType = indexSet; + DartType indexSetKey = indexSetType.parameterTypes.head; + checkAssignable(keyNode, key, indexSetKey); + DartType indexSetValue = indexSetType.parameterTypes.tail.head; + checkAssignable(node.assignmentOperator, value, indexSetValue); + } + return value; + } else { + // target = value + DartType target = computeAccessType(node, selector.source, + element, MemberKind.PROPERTY); + final Node valueNode = node.arguments.head; + final DartType value = analyze(valueNode); + checkAssignable(node.assignmentOperator, value, target); + return value; + } + } else if (identical(name, '++') || identical(name, '--')) { + // e++ or e-- + SourceString operatorName = identical(name, '++') + ? const SourceString('+') : const SourceString('-'); + if (node.isIndex) { + // base[key]++, base[key]--, ++base[key], or --base[key] + return checkIndexAssignmentOperator( + node, operatorName, node.assignmentOperator, intType); + } else { + // target++, target--, ++target, or --target + return checkAssignmentOperator( + node, operatorName, node.assignmentOperator, intType); + } } else { - DartType targetType = computeType(elements[node]); - Node value = node.arguments.head; - checkAssignable(value, targetType, analyze(value)); - return targetType; + // e1 o= e2 for some operator o. + SourceString operatorName; + switch (name) { + case '+=': operatorName = const SourceString('+'); break; + case '-=': operatorName = const SourceString('-'); break; + case '*=': operatorName = const SourceString('*'); break; + case '/=': operatorName = const SourceString('/'); break; + case '%=': operatorName = const SourceString('%'); break; + case '~/=': operatorName = const SourceString('~/'); break; + case '&=': operatorName = const SourceString('&'); break; + case '|=': operatorName = const SourceString('|'); break; + case '^=': operatorName = const SourceString('^'); break; + case '<<=': operatorName = const SourceString('<<'); break; + case '>>=': operatorName = const SourceString('>>'); break; + default: + compiler.internalError( + 'Unexpected assignment operator $name', node: node); + } + if (node.isIndex) { + // base[key] o= value for some operator o. + final Node valueNode = node.arguments.tail.head; + final DartType value = analyze(valueNode); + return checkIndexAssignmentOperator( + node, operatorName, valueNode, value); + } else { + // target o= value for some operator o. + final Node valueNode = node.arguments.head; + final DartType value = analyze(valueNode); + return checkAssignmentOperator(node, operatorName, valueNode, value); + } } } @@ -550,11 +883,30 @@ DartType visitNewExpression(NewExpression node) { Element element = elements[node.send]; - analyzeArguments(node.send, computeType(element)); - return analyze(node.send.selector); + DartType constructorType = computeType(element); + DartType newType = elements.getType(node); + // TODO(johnniwinther): Use [:lookupMember:] to account for type variable + // substitution of parameter types. + if (identical(newType.kind, TypeKind.INTERFACE)) { + InterfaceType newInterfaceType = newType; + constructorType = constructorType.subst( + newInterfaceType.typeArguments, + newInterfaceType.element.typeVariables); + } + analyzeArguments(node.send, element, constructorType); + return newType; } DartType visitLiteralList(LiteralList node) { + InterfaceType listType = elements.getType(node); + DartType listElementType = listType.typeArguments.head; + for (Link<Node> link = node.elements.nodes; + !link.isEmpty; + link = link.tail) { + Node element = link.head; + DartType elementType = analyze(element); + checkAssignable(element, elementType, listElementType); + } return listType; } @@ -610,7 +962,7 @@ && !types.isAssignable(expressionType, types.voidType)) { reportTypeWarning(expression, MessageKind.RETURN_VALUE_IN_VOID); } else { - checkAssignable(expression, expectedReturnType, expressionType); + checkAssignable(expression, expressionType, expectedReturnType); } // Let f be the function immediately enclosing a return statement of the @@ -630,6 +982,7 @@ return types.dynamicType; } + // TODO(johnniwinther): Remove this. DartType computeType(Element element) { if (Elements.isUnresolved(element)) return types.dynamicType; DartType result = element.computeType(compiler); @@ -652,12 +1005,12 @@ } for (Link<Node> link = node.definitions.nodes; !link.isEmpty; link = link.tail) { - Node initialization = link.head; - compiler.ensure(initialization is Identifier - || initialization is Send); - if (initialization is Send) { - DartType initializer = analyzeNonVoid(link.head); - checkAssignable(node, type, initializer); + Node definition = link.head; + compiler.ensure(definition is Identifier || definition is SendSet); + if (definition is Send) { + SendSet initialization = definition; + DartType initializer = analyzeNonVoid(initialization.arguments.head); + checkAssignable(initialization.assignmentOperator, initializer, type); } } return StatementType.NOT_RETURNING; @@ -733,7 +1086,19 @@ } visitLiteralMap(LiteralMap node) { - return unhandledExpression(); + InterfaceType mapType = elements.getType(node); + DartType mapKeyType = mapType.typeArguments.head; + DartType mapValueType = mapType.typeArguments.tail.head; + for (Link<Node> link = node.entries.nodes; + !link.isEmpty; + link = link.tail) { + LiteralMapEntry entry = link.head; + DartType keyType = analyze(entry.key); + checkAssignable(entry.key, keyType, mapKeyType); + DartType valueType = analyze(entry.value); + checkAssignable(entry.value, valueType, mapValueType); + } + return mapType; } visitLiteralMapEntry(LiteralMapEntry node) {
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 2bd8266..501beed 100644 --- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart +++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -851,6 +851,8 @@ if (concreteType == null) return null; TypeMask typeMask = new TypeMask.nonNullEmpty(); for (BaseType baseType in concreteType.baseTypes) { + TypeMask other = baseTypeToTypeMask(baseType); + if (other == null) return null; typeMask = typeMask.union(baseTypeToTypeMask(baseType), compiler); } return typeMask; @@ -1098,7 +1100,7 @@ } else if (type.element == compiler.boolClass) { concreteType = singletonConcreteType(baseTypes.boolBaseType); } else { - Set<ClassElement> subtypes = compiler.world.subtypes[type.element]; + Set<ClassElement> subtypes = compiler.world.subtypesOf(type.element); if (subtypes == null) continue; concreteType = emptyConcreteType; for (ClassElement subtype in subtypes) { @@ -1221,7 +1223,7 @@ if (type == null) { uninitializedFields.add(field); } - }, includeSuperMembers: false); + }); // handle initializing formals element.functionSignature.forEachParameter((param) {
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 4e2bf37..8f3cda3 100644 --- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart +++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -62,6 +62,7 @@ bool get isEmpty => (flags >> 1) == EMPTY; bool get isExact => (flags >> 1) == EXACT; bool get isNullable => (flags & 1) != 0; + bool get isUnion => false; // TODO(kasperl): Get rid of these. They should not be a visible // part of the implementation because they make it hard to add @@ -77,6 +78,8 @@ return isNullable ? new FlatTypeMask.internal(base, flags & ~1) : this; } + TypeMask simplify(Compiler compiler) => this; + bool contains(DartType type, Compiler compiler) { if (isEmpty) { return false; @@ -126,6 +129,21 @@ return base.element == cls; } + bool satisfies(ClassElement cls, Compiler compiler) { + if (isEmpty) { + return false; + } else if (base.element == cls) { + return true; + } else if (isExact) { + return false; + } else if (isSubclass) { + return isSubclassOf(base, cls.computeType(compiler).asRaw(), compiler); + } else { + assert(isSubtype); + return isSubtypeOf(base, cls.computeType(compiler).asRaw(), compiler); + } + } + /** * Returns the [ClassElement] if this type represents a single class, * otherwise returns `null`. This method is conservative. @@ -153,23 +171,26 @@ || identical(base.element, compiler.dynamicClass); } - TypeMask union(FlatTypeMask other, Compiler compiler) { + TypeMask union(TypeMask other, Compiler compiler) { + assert(other != null); + if (other is! FlatTypeMask) return other.union(this, compiler); + FlatTypeMask flatOther = other; if (isEmpty) { - return isNullable ? other.nullable() : other; - } else if (other.isEmpty) { - return other.isNullable ? nullable() : this; - } else if (base == other.base) { - return unionSame(other, compiler); - } else if (isSubclassOf(other.base, base, compiler)) { - return unionSubclass(other, compiler); - } else if (isSubclassOf(base, other.base, compiler)) { - return other.unionSubclass(this, compiler); - } else if (isSubtypeOf(other.base, base, compiler)) { - return unionSubtype(other, compiler); - } else if (isSubtypeOf(base, other.base, compiler)) { - return other.unionSubtype(this, compiler); + return isNullable ? flatOther.nullable() : flatOther; + } else if (flatOther.isEmpty) { + return flatOther.isNullable ? nullable() : this; + } else if (base == flatOther.base) { + return unionSame(flatOther, compiler); + } else if (isSubclassOf(flatOther.base, base, compiler)) { + return unionSubclass(flatOther, compiler); + } else if (isSubclassOf(base, flatOther.base, compiler)) { + return flatOther.unionSubclass(this, compiler); + } else if (isSubtypeOf(flatOther.base, base, compiler)) { + return unionSubtype(flatOther, compiler); + } else if (isSubtypeOf(base, flatOther.base, compiler)) { + return flatOther.unionSubtype(this, compiler); } else { - return unionDisjoint(other, compiler); + return new UnionTypeMask._(<FlatTypeMask>[this, flatOther]); } } @@ -222,78 +243,26 @@ : this; } - TypeMask unionDisjoint(FlatTypeMask other, Compiler compiler) { - assert(base != other.base); - assert(!isSubtypeOf(base, other.base, compiler)); - assert(!isSubtypeOf(other.base, base, compiler)); - // If either type mask is a subtype type mask, we cannot use a - // subclass type mask to represent their union. - bool useSubclass = !isSubtype && !other.isSubtype; - // Compute the common supertypes of the two types. - ClassElement thisElement = base.element; - ClassElement otherElement = other.base.element; - Iterable<ClassElement> candidates = - compiler.world.commonSupertypesOf(thisElement, otherElement); - if (candidates.isEmpty) { - // TODO(kasperl): Get rid of this check. It can only happen when - // at least one of the two base types is 'unseen'. - return new TypeMask(compiler.objectClass.rawType, - SUBCLASS, - isNullable || other.isNullable); - } - // Compute the best candidate and its kind. - ClassElement bestElement; - int bestKind; - int bestSize; - for (ClassElement candidate in candidates) { - Set<ClassElement> subclasses = useSubclass - ? compiler.world.subclasses[candidate] - : null; - int size; - int kind; - if (subclasses != null && - subclasses.contains(thisElement) && - subclasses.contains(otherElement)) { - // If both [this] and [other] are subclasses of the supertype, - // then we prefer to construct a subclass type mask because it - // will always be at least as small as the corresponding - // subtype type mask. - kind = SUBCLASS; - size = subclasses.length; - assert(size <= compiler.world.subtypes[candidate].length); - } else { - kind = SUBTYPE; - size = compiler.world.subtypes[candidate].length; - } - // Update the best candidate if the new one is better. - if (bestElement == null || size < bestSize) { - bestElement = candidate; - bestSize = size; - bestKind = kind; - } - } - return new TypeMask(bestElement.computeType(compiler), - bestKind, - isNullable || other.isNullable); - } - - TypeMask intersection(FlatTypeMask other, Compiler compiler) { + TypeMask intersection(TypeMask other, Compiler compiler) { + assert(other != null); + if (other is! FlatTypeMask) return other.intersection(this, compiler); + FlatTypeMask flatOther = other; if (isEmpty) { - return other.isNullable ? this : nonNullable(); - } else if (other.isEmpty) { - return isNullable ? other : other.nonNullable(); - } else if (base == other.base) { - return intersectionSame(other, compiler); - } else if (isSubclassOf(other.base, base, compiler)) { - return intersectionSubclass(other, compiler); - } else if (isSubclassOf(base, other.base, compiler)) { - return other.intersectionSubclass(this, compiler); - } else if (isSubtypeOf(other.base, base, compiler)) { - return intersectionSubtype(other, compiler); - } else if (isSubtypeOf(base, other.base, compiler)) { - return other.intersectionSubtype(this, compiler); + return flatOther.isNullable ? this : nonNullable(); + } else if (flatOther.isEmpty) { + return isNullable ? flatOther : other.nonNullable(); + } else if (base == flatOther.base) { + return intersectionSame(flatOther, compiler); + } else if (isSubclassOf(flatOther.base, base, compiler)) { + return intersectionSubclass(flatOther, compiler); + } else if (isSubclassOf(base, flatOther.base, compiler)) { + return flatOther.intersectionSubclass(this, compiler); + } else if (isSubtypeOf(flatOther.base, base, compiler)) { + return intersectionSubtype(flatOther, compiler); + } else if (isSubtypeOf(base, flatOther.base, compiler)) { + return flatOther.intersectionSubtype(this, compiler); } else { - return intersectionDisjoint(other, compiler); + return intersectionDisjoint(flatOther, compiler); } } @@ -402,10 +371,10 @@ if (isExact) { return new Set<ClassElement>()..add(element); } else if (isSubclass) { - return compiler.world.subclasses[element]; + return compiler.world.subclassesOf(element); } else { assert(isSubtype); - return compiler.world.subtypes[element]; + return compiler.world.subtypesOf(element); } } @@ -510,10 +479,10 @@ if (isExact) { return false; } else if (isSubtype) { - subtypesToCheck = compiler.world.subtypes[cls]; + subtypesToCheck = compiler.world.subtypesOf(cls); } else { assert(isSubclass); - subtypesToCheck = compiler.world.subclasses[cls]; + subtypesToCheck = compiler.world.subclassesOf(cls); } return subtypesToCheck != null @@ -562,14 +531,14 @@ static bool isSubclassOf(DartType x, DartType y, Compiler compiler) { ClassElement xElement = x.element; ClassElement yElement = y.element; - Set<ClassElement> subclasses = compiler.world.subclasses[yElement]; + Set<ClassElement> subclasses = compiler.world.subclassesOf(yElement); return (subclasses != null) ? subclasses.contains(xElement) : false; } static bool isSubtypeOf(DartType x, DartType y, Compiler compiler) { ClassElement xElement = x.element; ClassElement yElement = y.element; - Set<ClassElement> subtypes = compiler.world.subtypes[yElement]; + Set<ClassElement> subtypes = compiler.world.subtypesOf(yElement); return (subtypes != null) ? subtypes.contains(xElement) : false; }
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart index 658ce4e..587e404 100644 --- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart +++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -7,7 +7,8 @@ import 'dart:collection' show Queue, LinkedHashSet; import '../closure.dart' show ClosureClassMap, ClosureScope; -import '../dart_types.dart' show DartType, FunctionType, TypeKind; +import '../dart_types.dart' + show DartType, InterfaceType, FunctionType, TypeKind; import '../elements/elements.dart'; import '../native_handler.dart' as native; import '../tree/tree.dart'; @@ -113,12 +114,12 @@ throw 'Unsupported operation'; } - bool get isNullable => true; - TypeMask intersection(TypeMask other, Compiler compiler) { return other; } + bool get isNullable => true; + String toString() => '$name sentinel type mask'; } @@ -265,7 +266,7 @@ * Sentinel used by the inferrer to notify that it does not know * the type of a specific element. */ - TypeMask dynamicType = new SentinelTypeMask('dynamic'); + TypeMask dynamicType; bool isDynamicType(TypeMask type) => identical(type, dynamicType); TypeMask nullType; @@ -547,6 +548,8 @@ rawTypeOf(backend.functionImplementation)); typeType = new TypeMask.nonNullExact( rawTypeOf(backend.typeImplementation)); + + dynamicType = new TypeMask.subclass(rawTypeOf(compiler.objectClass)); } dump() { @@ -623,6 +626,9 @@ bool recordType(Element analyzedElement, TypeMask type) { assert(type != null); + assert(analyzedElement.isField() + || analyzedElement.isParameter() + || analyzedElement.isFieldParameter()); return internalRecordType(analyzedElement, type, typeOf); } @@ -653,6 +659,18 @@ bool internalRecordType(Element analyzedElement, TypeMask newType, Map<Element, TypeMask> types) { + if (compiler.trustTypeAnnotations + // Parameters are being checked by the method, and we can + // therefore only trust their type after the checks. + || (compiler.enableTypeAssertions && !analyzedElement.isParameter())) { + var annotation = analyzedElement.computeType(compiler); + if (types == returnTypeOf) { + assert(annotation is FunctionType); + annotation = annotation.returnType; + } + newType = narrowType(newType, annotation); + } + // Fields and native methods of native classes are handled // specially when querying for their type or return type. if (isNativeElement(analyzedElement)) return false; @@ -688,9 +706,16 @@ } TypeMask returnType = returnTypeOf[element]; if (returnType == null) { - return dynamicType; + if ((compiler.trustTypeAnnotations || compiler.enableTypeAssertions) + && (element.isFunction() + || element.isGetter() + || element.isFactoryConstructor())) { + FunctionType functionType = element.computeType(compiler); + returnType = narrowType(dynamicType, functionType.returnType); + } else { + returnType = dynamicType; + } } - assert(returnType != null); return returnType; } @@ -746,16 +771,27 @@ element = element.implementation; if (isNativeElement(element) && element.isField()) { var type = typeOf.putIfAbsent(element, () { - return new TypeMask.subtype(element.computeType(compiler).asRaw()); + InterfaceType rawType = element.computeType(compiler).asRaw(); + return rawType.isDynamic ? dynamicType : new TypeMask.subtype(rawType); }); assert(type != null); return type; } TypeMask type = typeOf[element]; if (type == null) { - return dynamicType; + if ((compiler.trustTypeAnnotations + && (element.isField() + || element.isParameter() + || element.isVariable())) + // Parameters are being checked by the method, and we can + // therefore only trust their type after the checks. + || (compiler.enableTypeAssertions + && (element.isField() || element.isVariable()))) { + type = narrowType(dynamicType, element.computeType(compiler)); + } else { + type = dynamicType; + } } - assert(type != null); return type; } @@ -793,6 +829,8 @@ return functionType == null ? dynamicType : functionType; } else if (element.isField()) { return typeOfElement(element); + } else if (Elements.isUnresolved(element)) { + return dynamicType; } else { assert(element.isGetter()); return returnTypeOfElement(element); @@ -1234,7 +1272,6 @@ * [secondType]. */ TypeMask computeLUB(TypeMask firstType, TypeMask secondType) { - assert(secondType != null); if (firstType == null) { return secondType; } else if (isDynamicType(secondType)) { @@ -1254,6 +1291,7 @@ {bool isNullable: true}) { if (annotation.isDynamic) return type; if (annotation.isMalformed) return type; + if (annotation.isVoid) return nullType; if (annotation.element == compiler.objectClass) return type; TypeMask otherType; if (annotation.kind == TypeKind.TYPEDEF @@ -1266,6 +1304,7 @@ otherType = new TypeMask.nonNullSubtype(annotation); } if (isNullable) otherType = otherType.nullable(); + if (type == null) return otherType; return type.intersection(otherType, compiler); } } @@ -1308,21 +1347,27 @@ class LocalsHandler { final InternalSimpleTypesInferrer inferrer; final Map<Element, TypeMask> locals; - final Set<Element> capturedAndBoxed; + final Map<Element, Element> capturedAndBoxed; final Map<Element, TypeMask> fieldsInitializedInConstructor; final bool inTryBlock; bool isThisExposed; bool seenReturn = false; + bool seenBreakOrContinue = false; + + bool get aborts { + return seenReturn || seenBreakOrContinue; + } LocalsHandler(this.inferrer) : locals = new Map<Element, TypeMask>(), - capturedAndBoxed = new Set<Element>(), + capturedAndBoxed = new Map<Element, Element>(), fieldsInitializedInConstructor = new Map<Element, TypeMask>(), inTryBlock = false, isThisExposed = true; LocalsHandler.from(LocalsHandler other, {bool inTryBlock: false}) : locals = new Map<Element, TypeMask>.from(other.locals), - capturedAndBoxed = new Set<Element>.from(other.capturedAndBoxed), + capturedAndBoxed = new Map<Element, Element>.from( + other.capturedAndBoxed), fieldsInitializedInConstructor = new Map<Element, TypeMask>.from( other.fieldsInitializedInConstructor), inTryBlock = other.inTryBlock || inTryBlock, @@ -1330,15 +1375,19 @@ isThisExposed = other.isThisExposed; TypeMask use(Element local) { - if (capturedAndBoxed.contains(local)) { - return inferrer.typeOfElement(local); + if (capturedAndBoxed.containsKey(local)) { + return inferrer.typeOfElement(capturedAndBoxed[local]); } return locals[local]; } void update(Element local, TypeMask type) { assert(type != null); - if (capturedAndBoxed.contains(local) || inTryBlock) { + if (inferrer.compiler.trustTypeAnnotations + || inferrer.compiler.enableTypeAssertions) { + type = inferrer.narrowType(type, local.computeType(inferrer.compiler)); + } + if (capturedAndBoxed.containsKey(local) || inTryBlock) { // If a local is captured and boxed, or is set in a try block, // we compute the LUB of its assignments. // @@ -1350,22 +1399,23 @@ locals[local] = type; } - void setCapturedAndBoxed(Element local) { - capturedAndBoxed.add(local); + void setCapturedAndBoxed(Element local, Element field) { + capturedAndBoxed[local] = field; } /** * Merge handlers [first] and [second] into [:this:] and returns * whether the merge changed one of the variables types in [first]. */ - bool merge(LocalsHandler other) { + bool merge(LocalsHandler other, {bool discardIfAborts: true}) { bool changed = false; List<Element> toRemove = <Element>[]; // Iterating over a map and just updating its entries is OK. locals.forEach((Element local, TypeMask oldType) { TypeMask otherType = other.locals[local]; + bool isCaptured = capturedAndBoxed.containsKey(local); if (otherType == null) { - if (!capturedAndBoxed.contains(local)) { + if (!isCaptured) { // If [local] is not in the other map and is not captured // and boxed, we know it is not a // local we want to keep. For example, in an if/else, we don't @@ -1375,9 +1425,15 @@ } return; } - TypeMask type = inferrer.computeLUB(oldType, otherType); - if (type != oldType) changed = true; - locals[local] = type; + if (!isCaptured && aborts && discardIfAborts) { + locals[local] = otherType; + } else if (!isCaptured && other.aborts && discardIfAborts) { + // Don't do anything. + } else { + TypeMask type = inferrer.computeLUB(oldType, otherType); + if (type != oldType) changed = true; + locals[local] = type; + } }); // Remove locals that will not be used anymore. @@ -1388,12 +1444,12 @@ // Update the locals that are captured and boxed. We // unconditionally add them to [this] because we register the type // of boxed variables after analyzing all closures. - other.capturedAndBoxed.forEach((Element element) { - capturedAndBoxed.add(element); + other.capturedAndBoxed.forEach((Element local, Element field) { + capturedAndBoxed[local] = field; // If [element] is not in our [locals], we need to update it. // Otherwise, we have already computed the LUB of it. - if (locals[element] == null) { - locals[element] = other.locals[element]; + if (locals[local] == null) { + locals[local] = other.locals[local]; } }); @@ -1419,6 +1475,7 @@ }); isThisExposed = isThisExposed || other.isThisExposed; seenReturn = seenReturn && other.seenReturn; + seenBreakOrContinue = seenBreakOrContinue && other.seenBreakOrContinue; return changed; } @@ -1434,6 +1491,10 @@ final Element outermostElement; final InternalSimpleTypesInferrer inferrer; final Compiler compiler; + final Map<TargetElement, List<LocalsHandler>> breaksFor = + new Map<TargetElement, List<LocalsHandler>>(); + final Map<TargetElement, List<LocalsHandler>> continuesFor = + new Map<TargetElement, List<LocalsHandler>>(); LocalsHandler locals; TypeMask returnType; @@ -1481,14 +1542,14 @@ // Update the locals that are boxed in [locals]. These locals will // be handled specially, in that we are computing their LUB at // each update, and reading them yields the type that was found in a - // previous analysis ouf [outermostElement]. + // previous analysis of [outermostElement]. ClosureClassMap closureData = compiler.closureToClassMapper.computeClosureToClassMapping( analyzedElement, node, elements); ClosureScope scopeData = closureData.capturingScopes[node]; if (scopeData != null) { - scopeData.capturedVariableMapping.forEach((Element variable, _) { - locals.setCapturedAndBoxed(variable); + scopeData.capturedVariableMapping.forEach((variable, field) { + locals.setCapturedAndBoxed(variable, field); }); } if (analyzedElement.isField()) { @@ -1586,14 +1647,16 @@ if (analyzedElement == outermostElement) { bool changed = false; - locals.capturedAndBoxed.forEach((Element local) { - if (inferrer.recordType(local, locals.locals[local])) { + locals.capturedAndBoxed.forEach((Element local, Element field) { + if (inferrer.recordType(field, locals.locals[local])) { changed = true; } }); // TODO(ngeoffray): Re-analyze method if [changed]? } compiler.world.registerSideEffects(analyzedElement, sideEffects); + assert(breaksFor.isEmpty); + assert(continuesFor.isEmpty); return returnType; } @@ -1654,11 +1717,11 @@ // same as [newType]. ClosureClassMap nestedClosureData = compiler.closureToClassMapper.getMappingForNestedFunction(node); - nestedClosureData.forEachNonBoxedCapturedVariable((Element variable) { + nestedClosureData.forEachNonBoxedCapturedVariable((variable, field) { // The type may be null for instance contexts (this and type // parameters), as well as captured argument checks. if (locals.locals[variable] == null) return; - inferrer.recordType(variable, locals.locals[variable]); + inferrer.recordType(field, locals.locals[variable]); }); return inferrer.functionType; @@ -1848,9 +1911,8 @@ ArgumentsTypes operatorArguments = new ArgumentsTypes([rhsType], null); if (Elements.isStaticOrTopLevelField(element)) { Element getterElement = elements[node.selector]; - getterType = getterElement.isField() - ? inferrer.typeOfElement(element) - : inferrer.returnTypeOfElement(element); + getterType = + inferrer.typeOfElementWithSelector(getterElement, getterSelector); handleStaticSend(node, getterSelector, getterElement, null); newType = handleDynamicSend( node, operatorSelector, getterType, operatorArguments); @@ -1955,7 +2017,7 @@ isThisExposed = true; if (node.isPropertyAccess) { handleStaticSend(node, selector, element, null); - return inferrer.typeOfElement(element); + return inferrer.typeOfElementWithSelector(element, selector); } else if (element.isFunction()) { if (!selector.applies(element, compiler)) return inferrer.dynamicType; ArgumentsTypes arguments = analyzeArguments(node.arguments); @@ -2120,7 +2182,7 @@ Selector selector = elements.getSelector(node); if (Elements.isStaticOrTopLevelField(element)) { handleStaticSend(node, selector, element, null); - return inferrer.typeOfElement(element); + return inferrer.typeOfElementWithSelector(element, selector); } else if (Elements.isInstanceSend(node, elements)) { return visitDynamicSend(node); } else if (Elements.isStaticOrTopLevelFunction(element)) { @@ -2314,51 +2376,77 @@ return inferrer.dynamicType; } - TypeMask visitWhile(While node) { + void setupBreaksAndContinues(TargetElement element) { + if (element == null) return; + if (element.isContinueTarget) continuesFor[element] = <LocalsHandler>[]; + if (element.isBreakTarget) breaksFor[element] = <LocalsHandler>[]; + } + + void clearBreaksAndContinues(TargetElement element) { + continuesFor.remove(element); + breaksFor.remove(element); + } + + void mergeBreaks(TargetElement element) { + if (element == null) return; + if (!element.isBreakTarget) return; + for (LocalsHandler handler in breaksFor[element]) { + locals.merge(handler, discardIfAborts: false); + } + } + + bool mergeContinues(TargetElement element) { + if (element == null) return false; + if (!element.isContinueTarget) return false; + bool changed = false; + for (LocalsHandler handler in continuesFor[element]) { + changed = locals.merge(handler, discardIfAborts: false) || changed; + } + return changed; + } + + TypeMask handleLoop(Node node, void logic()) { loopLevel++; bool changed = false; + TargetElement target = elements[node]; + setupBreaksAndContinues(target); do { LocalsHandler saved = new LocalsHandler.from(locals); + logic(); + changed = saved.merge(locals); + locals = saved; + changed = mergeContinues(target) || changed; + } while (changed); + loopLevel--; + mergeBreaks(target); + clearBreaksAndContinues(target); + return inferrer.dynamicType; + } + + TypeMask visitWhile(While node) { + return handleLoop(node, () { List<Send> tests = handleCondition(node.condition); updateIsChecks(tests, usePositive: true); visit(node.body); - changed = saved.merge(locals); - locals = saved; - } while (changed); - loopLevel--; - return inferrer.dynamicType; + }); } TypeMask visitDoWhile(DoWhile node) { - loopLevel++; - bool changed = false; - do { - LocalsHandler saved = new LocalsHandler.from(locals); + return handleLoop(node, () { visit(node.body); List<Send> tests = handleCondition(node.condition); updateIsChecks(tests, usePositive: true); - changed = saved.merge(locals); - locals = saved; - } while (changed); - loopLevel--; - return inferrer.dynamicType; + }); } TypeMask visitFor(For node) { - bool changed = false; visit(node.initializer); - loopLevel++; - do { - LocalsHandler saved = new LocalsHandler.from(locals); + return handleLoop(node, () { List<Send> tests = handleCondition(node.condition); updateIsChecks(tests, usePositive: true); visit(node.body); visit(node.update); - changed = saved.merge(locals); - locals = saved; - } while (changed); - loopLevel--; - return inferrer.dynamicType; + }); } TypeMask visitForIn(ForIn node) { @@ -2380,15 +2468,9 @@ handlePlainAssignment(identifier, variable, selector, inferrer.dynamicType, inferrer.dynamicType, node.expression); - loopLevel++; - do { - LocalsHandler saved = new LocalsHandler.from(locals); + return handleLoop(node, () { visit(node.body); - changed = saved.merge(locals); - locals = saved; - } while (changed); - loopLevel--; - return inferrer.dynamicType; + }); } TypeMask visitTryStatement(TryStatement node) { @@ -2434,6 +2516,48 @@ return visit(node.expression); } + TypeMask visitBlock(Block node) { + if (node.statements != null) { + for (Node statement in node.statements) { + visit(statement); + if (locals.aborts) break; + } + } + return inferrer.dynamicType; + } + + TypeMask visitLabeledStatement(LabeledStatement node) { + Statement body = node.statement; + if (body is Loop + || body is SwitchStatement + || Elements.isUnusedLabel(node, elements)) { + // Loops and switches handle their own labels. + visit(body); + return inferrer.dynamicType; + } + + TargetElement targetElement = elements[body]; + setupBreaksAndContinues(targetElement); + visit(body); + mergeBreaks(targetElement); + clearBreaksAndContinues(targetElement); + return inferrer.dynamicType; + } + + TypeMask visitBreakStatement(BreakStatement node) { + TargetElement target = elements[node]; + breaksFor[target].add(locals); + locals.seenBreakOrContinue = true; + return inferrer.dynamicType; + } + + TypeMask visitContinueStatement(ContinueStatement node) { + TargetElement target = elements[node]; + continuesFor[target].add(locals); + locals.seenBreakOrContinue = true; + return inferrer.dynamicType; + } + void internalError(String reason, {Node node}) { compiler.internalError(reason, node: node); } @@ -2441,7 +2565,24 @@ TypeMask visitSwitchStatement(SwitchStatement node) { visit(node.parenthesizedExpression); + setupBreaksAndContinues(elements[node]); if (Elements.switchStatementHasContinue(node, elements)) { + void forEachLabeledCase(void action(TargetElement target)) { + for (SwitchCase switchCase in node.cases) { + for (Node labelOrCase in switchCase.labelsAndCases) { + if (labelOrCase.asLabel() == null) continue; + LabelElement labelElement = elements[labelOrCase]; + if (labelElement != null) { + action(labelElement.target); + } + } + } + } + + forEachLabeledCase((TargetElement target) { + setupBreaksAndContinues(target); + }); + // If the switch statement has a continue, we conservatively // visit all cases and update [locals] until we have reached a // fixed point. @@ -2451,10 +2592,14 @@ for (Node switchCase in node.cases) { LocalsHandler saved = new LocalsHandler.from(locals); visit(switchCase); - changed = saved.merge(locals) || changed; + changed = saved.merge(locals, discardIfAborts: false) || changed; locals = saved; } } while (changed); + + forEachLabeledCase((TargetElement target) { + clearBreaksAndContinues(target); + }); } else { LocalsHandler saved = new LocalsHandler.from(locals); // If there is a default case, the current values of the local @@ -2465,17 +2610,17 @@ : new LocalsHandler.from(locals); for (Node switchCase in node.cases) { - locals = saved; + locals = new LocalsHandler.from(saved); visit(switchCase); if (result == null) { result = locals; } else { - result.merge(locals); + result.merge(locals, discardIfAborts: false); } } - locals = result; } + clearBreaksAndContinues(elements[node]); return inferrer.dynamicType; } }
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart index 47740ea..905021c 100644 --- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart +++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -28,6 +28,10 @@ factory TypeMask.nonNullSubtype(DartType base) => new FlatTypeMask.nonNullSubtype(base); + factory TypeMask.unionOf(Iterable<TypeMask> masks, Compiler compiler) { + return UnionTypeMask.unionOf(masks, compiler); + } + /** * Returns a nullable variant of [this] type mask. */ @@ -38,9 +42,12 @@ */ TypeMask nonNullable(); + TypeMask simplify(Compiler compiler); + bool get isEmpty; bool get isNullable; bool get isExact; + bool get isUnion; bool containsOnlyInt(Compiler compiler); bool containsOnlyDouble(Compiler compiler); @@ -49,6 +56,11 @@ bool containsOnlyBool(Compiler compiler); bool containsOnlyString(Compiler compiler); bool containsOnly(ClassElement element); + + /** + * Returns whether this type mask is an instance of [cls]. + */ + bool satisfies(ClassElement cls, Compiler compiler); /** * Returns whether or not this type mask contains the given type.
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart index 34444fd..5813cfe 100644 --- a/sdk/lib/_internal/compiler/implementation/types/types.dart +++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -19,6 +19,7 @@ part 'concrete_types_inferrer.dart'; part 'flat_type_mask.dart'; part 'type_mask.dart'; +part 'union_type_mask.dart'; /** * Common super class for our type inferrers. @@ -91,6 +92,9 @@ * is for debugging purposes only and can be omitted. */ TypeMask best(var type1, var type2, [element]) { + // TODO(polux): Handle [UnionTypeMask]. + if (type1 != null) type1 = type1.simplify(compiler); + if (type2 != null) type2 = type2.simplify(compiler); final result = _best(type1, type2); // Tests type1 and type2 for equality modulo normalization of native types. // Only called when DUMP_SURPRISING_RESULTS is true.
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart new file mode 100644 index 0000000..82865d5 --- /dev/null +++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -0,0 +1,259 @@ +// 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. + +part of types; + +class UnionTypeMask implements TypeMask { + final Iterable<FlatTypeMask> disjointMasks; + + static const int MAX_UNION_LENGTH = 4; + + UnionTypeMask._(this.disjointMasks); + + static TypeMask unionOf(Iterable<TypeMask> masks, Compiler compiler) { + List<FlatTypeMask> disjoint = <FlatTypeMask>[]; + unionOfHelper(masks, disjoint, compiler); + if (disjoint.isEmpty) return new TypeMask.nonNullEmpty(); + if (disjoint.length > MAX_UNION_LENGTH) return flatten(disjoint, compiler); + if (disjoint.length == 1) return disjoint[0]; + return new UnionTypeMask._(disjoint); + } + + static void unionOfHelper(Iterable<TypeMask> masks, + List<FlatTypeMask> disjoint, + Compiler compiler) { + for (TypeMask mask in masks) { + if (mask.isUnion) { + UnionTypeMask union = mask; + unionOfHelper(union.disjointMasks, disjoint, compiler); + } else if (mask.isEmpty && !mask.isNullable) { + continue; + } else { + FlatTypeMask flatMask = mask; + assert(flatMask.base == null + || flatMask.base.element != compiler.dynamicClass); + int inListIndex = -1; + bool covered = false; + + // Iterate over [disjoint] to find out if one of the mask + // already covers [mask]. + for (int i = 0; i < disjoint.length; i++) { + FlatTypeMask current = disjoint[i]; + if (current == null) continue; + TypeMask newMask = mask.union(current, compiler); + // If we have found a disjoint union, continue iterating. + if (newMask.isUnion) continue; + covered = true; + // We found a mask that is either equal to [mask] or is a + // supertype of [mask]. + if (current == newMask) break; + + // [mask] is a supertype of [current], replace the [disjoint] + // list with [newMask] instead of [current]. Note that + // [newMask] may contain different information than [mask], + // like nullability. + disjoint[i] = newMask; + mask = newMask; + + if (inListIndex != -1) { + // If the mask was already covered, we remove the previous + // place where it was inserted. This new mask subsumes the + // previously covered one. + disjoint.removeAt(inListIndex); + i--; + } + // Record where the mask was inserted. + inListIndex = i; + } + // If none of the masks in [disjoint] covers [mask], we just + // add [mask] to the list. + if (!covered) disjoint.add(mask); + } + } + } + + static TypeMask flatten(List<FlatTypeMask> masks, Compiler compiler) { + assert(masks.length > 1); + // If either type mask is a subtype type mask, we cannot use a + // subclass type mask to represent their union. + bool useSubclass = masks.every((e) => !e.isSubtype); + bool isNullable = masks.any((e) => e.isNullable); + + // Compute the common supertypes of the two types. + ClassElement firstElement = masks[0].base.element; + ClassElement secondElement = masks[1].base.element; + Iterable<ClassElement> candidates = + compiler.world.commonSupertypesOf(firstElement, secondElement); + bool unseenType = false; + for (int i = 2; i < masks.length; i++) { + ClassElement element = masks[i].base.element; + Set<ClassElement> supertypes = compiler.world.supertypesOf(element); + if (supertypes == null) { + unseenType = true; + break; + } + candidates = candidates.where((e) => supertypes.contains(e)); + } + + if (candidates.isEmpty || unseenType) { + // TODO(kasperl): Get rid of this check. It can only happen when + // at least one of the two base types is 'unseen'. + return new TypeMask(compiler.objectClass.rawType, + FlatTypeMask.SUBCLASS, + isNullable); + } + // Compute the best candidate and its kind. + ClassElement bestElement; + int bestKind; + int bestSize; + for (ClassElement candidate in candidates) { + Set<ClassElement> subclasses = useSubclass + ? compiler.world.subclassesOf(candidate) + : null; + int size; + int kind; + if (subclasses != null + && masks.every((t) => subclasses.contains(t.base.element))) { + // If both [this] and [other] are subclasses of the supertype, + // then we prefer to construct a subclass type mask because it + // will always be at least as small as the corresponding + // subtype type mask. + kind = FlatTypeMask.SUBCLASS; + size = subclasses.length; + assert(size <= compiler.world.subtypesOf(candidate).length); + } else { + kind = FlatTypeMask.SUBTYPE; + size = compiler.world.subtypesOf(candidate).length; + } + // Update the best candidate if the new one is better. + if (bestElement == null || size < bestSize) { + bestElement = candidate; + bestSize = size; + bestKind = kind; + } + } + if (bestElement == compiler.objectClass) bestKind = FlatTypeMask.SUBCLASS; + return new TypeMask(bestElement.computeType(compiler), + bestKind, + isNullable); + } + + TypeMask union(var other, Compiler compiler) { + if (!other.isUnion && disjointMasks.contains(other)) return this; + + List<FlatTypeMask> newList = + new List<FlatTypeMask>.from(disjointMasks); + if (!other.isUnion) { + newList.add(other); + } else { + assert(other is UnionTypeMask); + newList.addAll(other.disjointMasks); + } + return new TypeMask.unionOf(newList, compiler); + } + + TypeMask intersection(var other, Compiler compiler) { + if (!other.isUnion && disjointMasks.contains(other)) return other; + + List<TypeMask> intersections = <TypeMask>[]; + for (TypeMask current in disjointMasks) { + if (other.isUnion) { + for (FlatTypeMask flatOther in other.disjointMasks) { + intersections.add(current.intersection(flatOther, compiler)); + } + } else { + intersections.add(current.intersection(other, compiler)); + } + } + return new TypeMask.unionOf(intersections, compiler); + } + + TypeMask nullable() { + if (isNullable) return this; + List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks); + newList[0] = newList[0].nullable(); + return new UnionTypeMask._(newList); + } + + TypeMask nonNullable() { + if (!isNullable) return this; + Iterable<FlatTypeMask> newIterable = + disjointMasks.map((e) => e.nonNullable()); + return new UnionTypeMask._(newIterable); + } + + TypeMask simplify(Compiler compiler) => flatten(disjointMasks, compiler); + + bool get isEmpty => false; + bool get isNullable => disjointMasks.any((e) => e.isNullable); + bool get isExact => false; + bool get isUnion => true; + + bool containsOnlyInt(Compiler compiler) => false; + bool containsOnlyDouble(Compiler compiler) => false; + bool containsOnlyNum(Compiler compiler) { + return disjointMasks.every((mask) { + return mask.containsOnlyInt(compiler) + || mask.containsOnlyDouble(compiler) + || mask.containsOnlyNum(compiler); + }); + } + bool containsOnlyNull(Compiler compiler) => false; + bool containsOnlyBool(Compiler compiler) => false; + bool containsOnlyString(Compiler compiler) => false; + bool containsOnly(ClassElement element) => false; + bool satisfies(ClassElement cls, Compiler compiler) { + return disjointMasks.every((mask) => mask.satisfies(cls, compiler)); + } + + bool contains(DartType type, Compiler compiler) { + return disjointMasks.any((e) => e.contains(type, compiler)); + } + + bool containsAll(Compiler compiler) => false; + + ClassElement singleClass(Compiler compiler) => null; + + Set<ClassElement> containedClasses(Compiler compiler) { + Set<ClassElement> set = new Set<ClassElement>(); + disjointMasks.forEach((e) => set.addAll(e.containedClasses(compiler))); + return set; + } + + /** + * Returns whether a [selector] call will hit a method at runtime, + * and not go through [noSuchMethod]. + */ + bool willHit(Selector selector, Compiler compiler) { + return disjointMasks.every((e) => e.willHit(selector, compiler)); + } + + bool canHit(Element element, Selector selector, Compiler compiler) { + return disjointMasks.any((e) => e.canHit(element, selector, compiler)); + } + + Element locateSingleElement(Selector selector, Compiler compiler) { + Element candidate; + for (FlatTypeMask mask in disjointMasks) { + Element current = mask.locateSingleElement(selector, compiler); + if (current == null) { + return null; + } else if (candidate == null) { + candidate = current; + } else if (candidate != current) { + return null; + } + } + return candidate; + } + + String toString() => 'Union of $disjointMasks'; + + bool operator==(other) { + if (identical(this, other)) return true; + return other is UnionTypeMask + && other.disjointMasks.length == disjointMasks.length + && other.disjointMasks.every((e) => disjointMasks.contains(e)); + } +}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart index c8ad568..268fce6 100644 --- a/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart +++ b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
@@ -59,7 +59,7 @@ ClassElement single = classes[0]; // Return true if the single class in our list does not have a // single instantiated subclass. - Set<ClassElement> subtypes = compiler.world.subtypes[single]; + Set<ClassElement> subtypes = compiler.world.subtypesOf(single); return subtypes == null || subtypes.every((ClassElement each) => !each.isSubclassOf(single)); }
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart index 7dcebd8..c609c17 100644 --- a/sdk/lib/_internal/compiler/implementation/warnings.dart +++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -28,6 +28,10 @@ "no named argument '#{argumentName}' found on method"); static const METHOD_NOT_FOUND = const MessageKind( 'no method named #{memberName} in class #{className}'); + static const OPERATOR_NOT_FOUND = const MessageKind( + 'no operator #{memberName} in class #{className}'); + static const PROPERTY_NOT_FOUND = const MessageKind( + 'no property named #{memberName} in class #{className}'); static const NOT_CALLABLE = const MessageKind( "'#{elementName}' is not callable"); static const MEMBER_NOT_STATIC = const MessageKind( @@ -35,6 +39,9 @@ static const NO_INSTANCE_AVAILABLE = const MessageKind( '#{name} is only available in instance methods'); + static const THIS_IS_THE_METHOD = const MessageKind( + "This is the method declaration."); + static const UNREACHABLE_CODE = const MessageKind( 'unreachable code'); static const MISSING_RETURN = const MessageKind(
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart index f0bd537..122bd9e 100644 --- a/sdk/lib/_internal/compiler/implementation/world.dart +++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -6,32 +6,54 @@ class World { final Compiler compiler; - final Map<ClassElement, Set<MixinApplicationElement>> mixinUses; - final Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses; final FullFunctionSet allFunctions; final Set<Element> functionsCalledInLoop = new Set<Element>(); final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); - // We keep track of subtype and subclass relationships in four - // 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 = + final Map<ClassElement, Set<MixinApplicationElement>> mixinUses = + new Map<ClassElement, Set<MixinApplicationElement>>(); + + final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses = new Map<ClassElement, Set<ClassElement>>(); + // We keep track of subtype and subclass relationships in four + // 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 = + new Map<ClassElement, Set<ClassElement>>(); + + Set<ClassElement> subclassesOf(ClassElement cls) { + return _subclasses[cls.declaration]; + } + + Set<ClassElement> subtypesOf(ClassElement cls) { + return _subtypes[cls.declaration]; + } + + Set<ClassElement> superclassesOf(ClassElement cls) { + return _superclasses[cls.declaration]; + } + + Set<ClassElement> supertypesOf(ClassElement cls) { + return _supertypes[cls.declaration]; + } + + Set<ClassElement> typesImplementedBySubclassesOf(ClassElement cls) { + return _typesImplementedBySubclasses[cls]; + } + World(Compiler compiler) - : mixinUses = new Map<ClassElement, Set<MixinApplicationElement>>(), - typesImplementedBySubclasses = - new Map<ClassElement, Set<ClassElement>>(), - allFunctions = new FullFunctionSet(compiler), + : allFunctions = new FullFunctionSet(compiler), this.compiler = compiler; void populate() { void addSubtypes(ClassElement cls) { + assert(cls.isDeclaration); if (cls.resolutionState != STATE_DONE) { compiler.internalErrorOnElement( cls, 'Class "${cls.name.slowToString()}" is not resolved.'); @@ -39,9 +61,9 @@ for (DartType type in cls.allSupertypes) { Set<Element> supertypesOfClass = - supertypes.putIfAbsent(cls, () => new Set<ClassElement>()); + _supertypes.putIfAbsent(cls, () => new Set<ClassElement>()); Set<Element> subtypesOfSupertype = - subtypes.putIfAbsent(type.element, () => new Set<ClassElement>()); + _subtypes.putIfAbsent(type.element, () => new Set<ClassElement>()); supertypesOfClass.add(type.element); subtypesOfSupertype.add(cls); } @@ -51,14 +73,14 @@ DartType type = cls.supertype; while (type != null) { Set<Element> superclassesOfClass = - superclasses.putIfAbsent(cls, () => new Set<ClassElement>()); + _superclasses.putIfAbsent(cls, () => new Set<ClassElement>()); Set<Element> subclassesOfSuperclass = - subclasses.putIfAbsent(type.element, () => new Set<ClassElement>()); + _subclasses.putIfAbsent(type.element, () => new Set<ClassElement>()); superclassesOfClass.add(type.element); subclassesOfSuperclass.add(cls); Set<Element> typesImplementedBySubclassesOfCls = - typesImplementedBySubclasses.putIfAbsent( + _typesImplementedBySubclasses.putIfAbsent( type.element, () => new Set<ClassElement>()); for (DartType current in cls.allSupertypes) { typesImplementedBySubclassesOfCls.add(current.element); @@ -76,9 +98,9 @@ } Iterable<ClassElement> commonSupertypesOf(ClassElement x, ClassElement y) { - Set<ClassElement> xSet = supertypes[x]; + Set<ClassElement> xSet = supertypesOf(x); if (xSet == null) return const <ClassElement>[]; - Set<ClassElement> ySet = supertypes[y]; + Set<ClassElement> ySet = supertypesOf(y); if (ySet == null) return const <ClassElement>[]; Set<ClassElement> smallSet, largeSet; if (xSet.length <= ySet.length) { @@ -93,6 +115,8 @@ void registerMixinUse(MixinApplicationElement mixinApplication, ClassElement mixin) { + // We don't support patch classes as mixin. + assert(mixin.isDeclaration); Set<MixinApplicationElement> users = mixinUses.putIfAbsent(mixin, () => new Set<MixinApplicationElement>()); @@ -105,12 +129,12 @@ } bool hasAnySubclass(ClassElement cls) { - Set<ClassElement> classes = subclasses[cls]; + Set<ClassElement> classes = subclassesOf(cls); return classes != null && !classes.isEmpty; } bool hasAnySubtype(ClassElement cls) { - Set<ClassElement> classes = subtypes[cls]; + Set<ClassElement> classes = subtypesOf(cls); return classes != null && !classes.isEmpty; } @@ -124,7 +148,7 @@ // Returns whether a subclass of [superclass] implements [type]. bool hasAnySubclassThatImplements(ClassElement superclass, DartType type) { - Set<ClassElement> subclasses = typesImplementedBySubclasses[superclass]; + Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass); if (subclasses == null) return false; return subclasses.contains(type.element); } @@ -182,6 +206,13 @@ } SideEffects getSideEffectsOfElement(Element element) { + // The type inferrer (where the side effects are being computed), + // does not see generative constructor bodies because they are + // created by the backend. Also, it does not make any distinction + // between a constructor and its body for side effects. This + // implies that currently, the side effects of a constructor body + // contain the side effects of the initializers. + assert(!element.isGenerativeConstructorBody()); return sideEffects.putIfAbsent(element.declaration, () { return new SideEffects(); });
diff --git a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart new file mode 100644 index 0000000..cb0e64b --- /dev/null +++ b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
@@ -0,0 +1,77 @@ +// 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 sample demonstrates how to run the compiler in a loop reading +// all sources from memory, instead of using dart:io. +library sample.compile_loop; + +import 'dart:async'; +import 'dart:uri'; + +import '../../compiler.dart' as compiler; + +// If this file is missing, generate it using ../jsonify/jsonify.dart. +import 'sdk.dart'; + +Future<String> compile(source) { + Future<String> inputProvider(Uri uri) { + if (uri.scheme == 'sdk') { + var value = SDK_SOURCES['$uri']; + if (value == null) { + // TODO(ahe): Use new Future.error. + throw new Exception('Error: Cannot read: $uri'); + } + return new Future.value(value); + } else if ('$uri' == 'memory:/main.dart') { + return new Future.value(source); + } + // TODO(ahe): Use new Future.error. + throw new Exception('Error: Cannot read: $uri'); + } + void handler(Uri uri, int begin, int end, + String message, compiler.Diagnostic kind) { + // TODO(ahe): Remove dart:io import from + // ../../implementation/source_file_provider.dart and use + // FormattingDiagnosticHandler instead. + print({ 'uri': '$uri', + 'begin': begin, + 'end': end, + 'message': message, + 'kind': kind.name }); + if (kind == compiler.Diagnostic.ERROR) { + throw new Exception('Unexpected error occurred.'); + } + } + return compiler.compile( + new Uri('memory:/main.dart'), + Uri.parse('sdk:/sdk/'), + null, + inputProvider, + handler, + []); +} + +int iterations = 10; + +main() { + compile(EXAMPLE_HELLO_HTML).then((jsResult) { + if (jsResult == null) throw 'Compilation failed'; + if (--iterations > 0) main(); + }); +} + +const String EXAMPLE_HELLO_HTML = r''' +// Go ahead and modify this example. + +import "dart:html"; + +var greeting = "Hello, World!"; + +// Displays a greeting. +void main() { + // This example uses HTML to display the greeting and it will appear + // in a nested HTML frame (an iframe). + document.body.append(new HeadingElement.h1()..appendText(greeting)); +} +''';
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart new file mode 100644 index 0000000..891f505 --- /dev/null +++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -0,0 +1,99 @@ +// 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:io'; +import 'dart:json'; +import 'dart:uri'; + +// TODO(ahe): Should be dart:mirrors. +import '../../implementation/mirrors/mirrors.dart'; + +import '../../../libraries.dart' + show LIBRARIES, LibraryInfo; + +import '../../implementation/mirrors/dart2js_mirror.dart' + show analyze, BackDoor; + +import '../../implementation/filenames.dart'; +import '../../implementation/source_file.dart'; +import '../../implementation/source_file_provider.dart'; +import '../../implementation/util/uri_extras.dart'; + +const DART2JS = '../../implementation/dart2js.dart'; +const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirror.dart'; +const SDK_ROOT = '../../../../../'; + +bool isPublicDart2jsLibrary(String name) { + return !name.startsWith('_') && LIBRARIES[name].isDart2jsLibrary; +} + +var handler; +RandomAccessFile output; +Uri outputUri; +Uri sdkRoot; + +main() { + mainWithOptions(new Options()); +} + +mainWithOptions(Options options) { + handler = new FormattingDiagnosticHandler() + ..throwOnError = true; + + outputUri = + handler.provider.cwd.resolve(nativeToUriPath(options.arguments.first)); + output = new File(options.arguments.first).openSync(mode: FileMode.WRITE); + + Uri myLocation = + handler.provider.cwd.resolve(nativeToUriPath(options.script)); + + sdkRoot = myLocation.resolve(SDK_ROOT).resolve('../'); + + // Get the names of public dart2js libraries. + Iterable<String> names = LIBRARIES.keys.where(isPublicDart2jsLibrary); + + // Turn the names into uris by prepending dart: to them. + List<Uri> uris = names.map((String name) => Uri.parse('dart:$name')).toList(); + + analyze(uris, myLocation.resolve(SDK_ROOT), null, handler.provider, handler) + .then(jsonify); +} + +jsonify(MirrorSystem mirrors) { + var map = {}; + + 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; + }); + }); + + LIBRARIES.forEach((name, info) { + var patch = info.dart2jsPatchPath; + if (patch != null) { + Uri uri = sdkRoot.resolve('sdk/lib/$patch'); + String filename = relativize(sdkRoot, uri, false); + SourceFile file = handler.provider.sourceFiles['$uri']; + map['sdk:/$filename'] = file.text; + } + }); + + output.writeStringSync(''' +// 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. + +// DO NOT EDIT. +// This file is generated by jsonify.dart. + +library dart.sdk_sources; + +const Map<String, String> SDK_SOURCES = const <String, String>'''); + output.writeStringSync(stringify(map).replaceAll(r'$', r'\$')); + output.writeStringSync(';\n'); + output.closeSync(); +}
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart index edfffba..a10a0c1 100644 --- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart +++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -63,15 +63,17 @@ /// using the `package:` scheme. /// /// This will automatically install the package to the system-wide cache as - /// well if it requires network access to retrieve (specifically, if - /// `id.source.shouldCache` is true). + /// well if it requires network access to retrieve (specifically, if the + /// package's source has [shouldCache] as `true`). /// /// See also [installDependencies]. Future<PackageId> install(PackageId id) { - var pendingOrCompleted = _installs[id]; - if (pendingOrCompleted != null) return pendingOrCompleted; + var pending = _installs[id]; + if (pending != null) return pending; var packageDir = path.join(packagesDir, id.name); + var source; + var future = new Future.sync(() { ensureDir(path.dirname(packageDir)); @@ -82,16 +84,18 @@ deleteEntry(packageDir); } - if (id.source.shouldCache) { + source = cache.sources[id.source]; + + if (source.shouldCache) { return cache.install(id).then( (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); } else { - return id.source.install(id, packageDir).then((found) { + return source.install(id, packageDir).then((found) { if (found) return null; - fail('Package ${id.name} not found in source "${id.source.name}".'); + fail('Package ${id.name} not found in source "${id.source}".'); }); } - }).then((_) => id.resolved); + }).then((_) => source.resolveId(id)); _installs[id] = future;
diff --git a/sdk/lib/_internal/pub/lib/src/git_source.dart b/sdk/lib/_internal/pub/lib/src/git_source.dart index c98616d..bccae27 100644 --- a/sdk/lib/_internal/pub/lib/src/git_source.dart +++ b/sdk/lib/_internal/pub/lib/src/git_source.dart
@@ -112,12 +112,12 @@ return _revisionAt(id).then((revision) { var description = {'url': _getUrl(id), 'ref': _getRef(id)}; description['resolved-ref'] = revision; - return new PackageId(id.name, this, id.version, description); + return new PackageId(id.name, name, id.version, description); }); } // TODO(keertip): Implement getCachedPackages(). - + /// Ensure that the canonical clone of the repository referred to by [id] (the /// one in `<system cache>/git/cache`) exists and is up-to-date. Returns a /// future that completes once this is finished and throws an exception if it
diff --git a/sdk/lib/_internal/pub/lib/src/hosted_source.dart b/sdk/lib/_internal/pub/lib/src/hosted_source.dart index 17b1839..62503fe 100644 --- a/sdk/lib/_internal/pub/lib/src/hosted_source.dart +++ b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
@@ -48,7 +48,7 @@ /// Downloads and parses the pubspec for a specific version of a package that /// is available from the site. - Future<Pubspec> describe(PackageId id) { + Future<Pubspec> describeUncached(PackageId id) { // Request it from the server. var url = _makeVersionUrl(id, (server, package, version) => "$server/packages/$package/versions/$version.yaml"); @@ -191,9 +191,9 @@ throw new UnsupportedError("Cannot install packages when offline."); } - Future<Pubspec> describe(PackageId id) { + Future<Pubspec> describeUncached(PackageId id) { // [getVersions()] will only return packages that are already cached. - // SystemCache should only call [describe()] on a package after it has + // Source should only call [describeUncached()] on a package after it has // failed to find it in the cache, so this code should not be reached. throw new UnsupportedError("Cannot describe packages when offline."); }
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart index 1e85a4d..316e8b5 100644 --- a/sdk/lib/_internal/pub/lib/src/lock_file.dart +++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -58,21 +58,20 @@ throw new FormatException('Package $name is missing a source.'); } var sourceName = spec['source']; - if (!sources.contains(sourceName)) { - throw new FormatException( - 'Could not find a source named $sourceName.'); - } - var source = sources[sourceName]; - // Parse the description. if (!spec.containsKey('description')) { throw new FormatException('Package $name is missing a description.'); } var description = spec['description']; - description = source.parseDescription(filePath, description, - fromLockFile: true); - var id = new PackageId(name, source, version, description); + // Parse the description if we know the source. + if (sources.contains(sourceName)) { + var source = sources[sourceName]; + description = source.parseDescription(filePath, description, + fromLockFile: true); + } + + var id = new PackageId(name, sourceName, version, description); // Validate the name. if (name != id.name) { @@ -97,7 +96,7 @@ sortedKeys.forEach((name) { packagesObj[name] = { 'version': packages[name].version.toString(), - 'source': packages[name].source.name, + 'source': packages[name].source, 'description': packages[name].description }; });
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart index 62a2a98..a2a1b12 100644 --- a/sdk/lib/_internal/pub/lib/src/package.dart +++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -10,7 +10,6 @@ import 'io.dart'; import 'pubspec.dart'; -import 'source.dart'; import 'source_registry.dart'; import 'version.dart'; @@ -87,9 +86,9 @@ /// The name of the package being identified. final String name; - /// The [Source] used to look up this package given its [description]. If - /// this is a root package, this will be `null`. - final Source source; + /// The name of the [Source] used to look up this package given its + /// [description]. If this is a root package, this will be `null`. + final String source; /// The metadata used by the package's [source] to identify and locate it. It /// contains whatever [Source]-specific data it needs to be able to install @@ -100,13 +99,8 @@ /// Whether this package is the root package. bool get isRoot => source == null; - /// Gets the directory where this package is or would be found in the - /// [SystemCache]. - Future<String> get systemCacheDirectory => source.systemCacheDirectory(this); - String toString() { if (isRoot) return "$name (root)"; - if (source.isDefault) return name; return "$name from $source"; } @@ -117,16 +111,11 @@ /// Returns a [PackageId] for this package with the given concrete version. PackageId atVersion(Version version) => new PackageId(name, source, version, description); - - /// Returns `true` if this package's description matches [other]'s. - bool descriptionEquals(PackageDep other) { - return source.descriptionsEqual(description, other.description); - } } /// A reference to a [Package], but not any particular version(s) of it. class PackageRef extends _PackageName { - PackageRef(String name, Source source, description) + PackageRef(String name, String source, description) : super(name, source, description); int get hashCode => name.hashCode ^ source.hashCode; @@ -138,18 +127,6 @@ other.name == name && other.source == source; } - - /// Gets the list of ids of all versions of the package that are described by - /// this reference. - Future<List<PackageId>> getVersions() { - if (isRoot) { - throw new StateError("Cannot get versions for the root package."); - } - - return source.getVersions(name, description).then((versions) { - return versions.map((version) => atVersion(version)).toList(); - }); - } } /// A reference to a specific version of a package. A package ID contains @@ -163,7 +140,7 @@ /// The package's version. final Version version; - PackageId(String name, Source source, this.version, description) + PackageId(String name, String source, this.version, description) : super(name, source, description); /// Creates an ID for the given root package. @@ -184,15 +161,8 @@ String toString() { if (isRoot) return "$name $version (root)"; - if (source.isDefault) return "$name $version"; return "$name $version from $source"; } - - /// Returns the pubspec for this package. - Future<Pubspec> describe() => source.systemCache.describe(this); - - /// Returns a future that completes to the resolved [PackageId] for this id. - Future<PackageId> get resolved => source.resolveId(this); } /// A reference to a constrained range of versions of one package. @@ -200,7 +170,7 @@ /// The allowed package versions. final VersionConstraint constraint; - PackageDep(String name, Source source, this.constraint, description) + PackageDep(String name, String source, this.constraint, description) : super(name, source, description); String toString() {
diff --git a/sdk/lib/_internal/pub/lib/src/path_source.dart b/sdk/lib/_internal/pub/lib/src/path_source.dart index 2b66e3b..5972050 100644 --- a/sdk/lib/_internal/pub/lib/src/path_source.dart +++ b/sdk/lib/_internal/pub/lib/src/path_source.dart
@@ -23,7 +23,7 @@ final name = 'path'; final shouldCache = false; - Future<Pubspec> describe(PackageId id) { + Future<Pubspec> describeUncached(PackageId id) { return new Future.sync(() { _validatePath(id.name, id.description); return new Pubspec.load(id.name, id.description["path"],
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart index 69dc880..e01cab1 100644 --- a/sdk/lib/_internal/pub/lib/src/pubspec.dart +++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -214,11 +214,9 @@ } } -/** - * Evaluates whether the given [url] for [field] is valid. - * - * Throws [FormatException] on an invalid url. - */ +/// Evaluates whether the given [url] for [field] is valid. +/// +/// Throws [FormatException] on an invalid url. void _validateFieldUrl(url, String field) { if (url is! String) { throw new FormatException( @@ -247,14 +245,16 @@ } yaml.forEach((name, spec) { - var description, source; + var description; + var sourceName; + var versionConstraint = new VersionRange(); if (spec == null) { description = name; - source = sources.defaultSource; + sourceName = sources.defaultSource.name; } else if (spec is String) { description = name; - source = sources.defaultSource; + sourceName = sources.defaultSource.name; versionConstraint = new VersionConstraint.parse(spec); } else if (spec is Map) { if (spec.containsKey('version')) { @@ -267,24 +267,27 @@ 'Dependency $name may only have one source: $sourceNames.'); } - var sourceName = only(sourceNames); + sourceName = only(sourceNames); if (sourceName is! String) { throw new FormatException( 'Source name $sourceName should be a string.'); } - source = sources[sourceName]; description = spec[sourceName]; } else { throw new FormatException( 'Dependency specification $spec should be a string or a mapping.'); } - description = source.parseDescription(pubspecPath, description, - fromLockFile: false); + // If we have a valid source, use it to process the description. Allow + // unknown sources so pub doesn't choke on old pubspecs. + if (sources.contains(sourceName)) { + description = sources[sourceName].parseDescription( + pubspecPath, description, fromLockFile: false); + } dependencies.add(new PackageDep( - name, source, versionConstraint, description)); + name, sourceName, versionConstraint, description)); }); return dependencies;
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 97d35da..1338b63 100644 --- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart +++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -387,6 +387,14 @@ // Include dev dependencies of the root package. if (id.isRoot) deps.addAll(pubspec.devDependencies); + // Make sure the package doesn't have any bad dependencies. + for (var dep in deps) { + if (!dep.isRoot && !_solver.sources.contains(dep.source)) { + throw new UnknownSourceException(id.name, + [new Dependency(id.name, dep)]); + } + } + // Given a package dep, returns a future that completes to a pair of the // dep and the number of versions available for it. getNumVersions(PackageDep dep) { @@ -433,8 +441,8 @@ }); } - /// Traverses the references that [depender] depends on, stored in [refs]. - /// Desctructively modifies [refs]. Completes to a list of packages if the + /// Traverses the references that [depender] depends on, stored in [deps]. + /// Desctructively modifies [deps]. Completes to a list of packages if the /// traversal is complete. Completes it to an error if a failure occurred. /// Otherwise, recurses. Future<List<PackageId>> _traverseDeps(String depender, @@ -465,7 +473,7 @@ } /// Ensures that dependency [dep] from [depender] is consistent with the - /// other dependencies on the same package. Throws a [SolverFailure] + /// other dependencies on the same package. Throws a [SolveFailure] /// exception if not. Only validates sources and descriptions, not the /// version. void _validateDependency(PackageDep dep, String depender) { @@ -474,7 +482,7 @@ if (required == null) return; // Make sure all of the existing sources match the new reference. - if (required.dep.source.name != dep.source.name) { + if (required.dep.source != dep.source) { _solver.logSolve('source mismatch on ${dep.name}: ${required.dep.source} ' '!= ${dep.source}'); throw new SourceMismatchException(dep.name, @@ -482,7 +490,8 @@ } // Make sure all of the existing descriptions match the new reference. - if (!dep.descriptionEquals(required.dep)) { + var source = _solver.sources[dep.source]; + if (!source.descriptionsEqual(dep.description, required.dep.description)) { _solver.logSolve('description mismatch on ${dep.name}: ' '${required.dep.description} != ${dep.description}'); throw new DescriptionMismatchException(dep.name, @@ -492,7 +501,7 @@ /// Adds the version constraint that [depender] places on [dep] to the /// overall constraint that all shared dependencies place on [dep]. Throws a - /// [SolverFailure] if that results in an unsolvable constraints. + /// [SolveFailure] if that results in an unsolvable constraints. /// /// Returns the combined [VersionConstraint] that all dependers place on the /// package. @@ -517,7 +526,7 @@ /// Validates the currently selected package against the new dependency that /// [dep] and [constraint] place on it. Returns `null` if there is no - /// currently selected package, throws a [SolverFailure] if the new reference + /// currently selected package, throws a [SolveFailure] if the new reference /// it not does not allow the previously selected version, or returns the /// selected package if successful. PackageId _validateSelected(PackageDep dep, VersionConstraint constraint) { @@ -538,7 +547,7 @@ /// the solver state so that we can backtrack from this decision if it turns /// out wrong, but continues traversing with the new selection. /// - /// Returns a future that completes with a [SolverFailure] if a version + /// Returns a future that completes with a [SolveFailure] if a version /// could not be selected or that completes successfully if a package was /// selected and traversing should continue. Future _selectPackage(PackageDep dep, VersionConstraint constraint) { @@ -608,8 +617,11 @@ var required = _getRequired(name); if (required != null) { - if (package.source.name != required.dep.source.name) return null; - if (!package.descriptionEquals(required.dep)) return null; + if (package.source != required.dep.source) return null; + + var source = _solver.sources[package.source]; + if (!source.descriptionsEqual( + package.description, required.dep.description)) return null; } return package; @@ -617,7 +629,7 @@ } /// Ensures that if [pubspec] has an SDK constraint, then it is compatible -/// with the current SDK. Throws a [SolverFailure] if not. +/// with the current SDK. Throws a [SolveFailure] if not. void _validateSdkConstraint(Pubspec pubspec) { // If the user is running a continouous build of the SDK, just disable SDK // constraint checking entirely. The actual version number you get is
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart index 885acdc..1ae8d3e 100644 --- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart +++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -14,6 +14,7 @@ import '../source.dart'; import '../source_registry.dart'; import '../version.dart'; +import '../utils.dart'; import 'backtracking_solver.dart'; /// Attempts to select the best concrete versions for all of the transitive @@ -70,7 +71,11 @@ /// Used to avoid requesting the same pubspec from the server repeatedly. class PubspecCache { final SourceRegistry _sources; + + /// The already-requested cached version lists. final _versions = new Map<PackageRef, List<PackageId>>(); + + /// The already-requested cached pubspecs. final _pubspecs = new Map<PackageId, Pubspec>(); /// The number of times a version list was requested and it wasn't cached and @@ -105,10 +110,9 @@ } pubspecCacheMisses++; - return id.describe().then((pubspec) { - log.solver('requested $id pubspec'); - // Cache it. + var source = _sources[id.source]; + return source.describe(id).then((pubspec) { _pubspecs[id] = pubspec; return pubspec; }); @@ -120,6 +124,10 @@ /// Gets the list of versions for [package] in descending order. Future<List<PackageId>> getVersions(PackageRef package) { + if (package.isRoot) { + throw new StateError("Cannot get versions for root package $package."); + } + // See if we have it cached. var versions = _versions[package]; if (versions != null) { @@ -128,11 +136,14 @@ } versionCacheMisses++; - return package.getVersions().then((ids) { - // Sort by descending version so we try newer versions first. - ids.sort((a, b) => b.version.compareTo(a.version)); - log.solver('requested $package version list'); + var source = _sources[package.source]; + return source.getVersions(package.name, package.description) + .then((versions) { + // Sort by descending version so we try newer versions first. + versions.sort((a, b) => b.compareTo(a)); + + var ids = versions.map((version) => package.atVersion(version)).toList(); _versions[package] = ids; return ids; }); @@ -153,7 +164,7 @@ } /// Base class for all failures that can occur while trying to resolve versions. -class SolveFailure implements Exception { +abstract class SolveFailure implements ApplicationException { /// The name of the package whose version could not be solved. Will be `null` /// if the failure is not specific to one package. final String package; @@ -270,7 +281,6 @@ /// Exception thrown when two packages with the same name but different sources /// are depended upon. class SourceMismatchException extends SolveFailure { - SourceMismatchException(String package, Iterable<Dependency> dependencies) : super(package, dependencies); @@ -280,6 +290,18 @@ "depends on it from source ${dep.source}"; } +/// Exception thrown when a dependency on an unknown source name is found. +class UnknownSourceException extends SolveFailure { + UnknownSourceException(String package, Iterable<Dependency> dependencies) + : super(package, dependencies); + + String toString() { + var dep = only(dependencies); + return "Package '${dep.depender}' depends on '${dep.dep.name}' from " + "unknown source '${dep.dep.source}'."; + } +} + /// Exception thrown when two packages with the same name and source but /// different descriptions are depended upon. class DescriptionMismatchException extends SolveFailure {
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart index 2486e78..f72f173 100644 --- a/sdk/lib/_internal/pub/lib/src/source.dart +++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -68,20 +68,54 @@ /// By default, this assumes that each description has a single version and /// uses [describe] to get that version. Future<List<Version>> getVersions(String name, description) { - return describe(new PackageId(name, this, Version.none, description)) - .then((pubspec) => [pubspec.version]); + var id = new PackageId(name, this.name, Version.none, description); + return describeUncached(id).then((pubspec) => [pubspec.version]); } /// Loads the (possibly remote) pubspec for the package version identified by /// [id]. This may be called for packages that have not yet been installed /// during the version resolution process. /// + /// If the package has been installed to the system cache, the cached pubspec + /// will be used. Otherwise, it delegates to host-specific lookup behavior. + /// /// For cached sources, by default this uses [installToSystemCache] to get the /// pubspec. There is no default implementation for non-cached sources; they /// must implement it manually. Future<Pubspec> describe(PackageId id) { + if (id.isRoot) throw new ArgumentError("Cannot describe the root package."); + if (id.source != name) { + throw new ArgumentError("Package $id does not use source $name."); + } + + // Try to get it from the system cache first. + if (shouldCache) { + return systemCacheDirectory(id).then((packageDir) { + if (!fileExists(path.join(packageDir, "pubspec.yaml"))) { + return describeUncached(id); + } + + return new Pubspec.load(id.name, packageDir, _systemCache.sources); + }); + } + + // Not cached, so get it from the source. + return describeUncached(id); + } + + /// Loads the pubspec for the package version identified by [id] which is not + /// already in the system cache. + /// + /// For cached sources, by default this uses [installToSystemCache] to get + /// the pubspec. There is no default implementation for non-cached sources; + /// they must implement it manually. + /// + /// This method is effectively protected. Derived classes may override it, + /// but external code should not call it. Call [describe()] instead. + Future<Pubspec> describeUncached(PackageId id) { if (!shouldCache) { - throw new UnimplementedError("Source $name must implement describe(id)."); + throw new UnimplementedError( + "Source $name must implement describeUncached(id)."); } return installToSystemCache(id).then((package) => package.pubspec); }
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart index 567803b..63de5dc 100644 --- a/sdk/lib/_internal/pub/lib/src/system_cache.dart +++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -70,41 +70,25 @@ sources.register(source); } - /// Gets the package identified by [id]. If the package is already cached, - /// reads it from the cache. Otherwise, requests it from the source. - Future<Pubspec> describe(PackageId id) { - if (id.isRoot) throw new ArgumentError("Cannot describe the root package."); - - // Try to get it from the system cache first. - if (id.source.shouldCache) { - return id.systemCacheDirectory.then((packageDir) { - if (!fileExists(path.join(packageDir, "pubspec.yaml"))) { - return id.source.describe(id); - } - - return new Pubspec.load(id.name, packageDir, sources); - }); - } - - // Not cached, so get it from the source. - return id.source.describe(id); - } - /// Ensures that the package identified by [id] is installed to the cache, /// loads it, and returns it. /// - /// It is an error to try installing a package from a source with `shouldCache - /// == false` to the system cache. + /// It is an error to try installing a package from a source with + /// `shouldCache == false` to the system cache. Future<Package> install(PackageId id) { - if (!id.source.shouldCache) { + var source = sources[id.source]; + + if (!source.shouldCache) { throw new ArgumentError("Package $id is not cacheable."); } var pending = _pendingInstalls[id]; if (pending != null) return pending; - var future = id.source.installToSystemCache(id) - .whenComplete(() { _pendingInstalls.remove(id); }); + var future = source.installToSystemCache(id).whenComplete(() { + _pendingInstalls.remove(id); + }); + _pendingInstalls[id] = future; return future; }
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart index c147f7b..a1a8f99 100644 --- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart +++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -22,7 +22,7 @@ Future validate() { return Future.forEach(entrypoint.root.pubspec.dependencies, (dependency) { - if (dependency.source is! HostedSource) { + if (dependency.source != "hosted") { return _warnAboutSource(dependency); } @@ -59,11 +59,11 @@ // Path sources are errors. Other sources are just warnings. var messages = warnings; - if (dep.source is PathSource) { + if (dep.source == "path") { messages = errors; } - messages.add('Don\'t depend on "${dep.name}" from the ${dep.source.name} ' + messages.add('Don\'t depend on "${dep.name}" from the ${dep.source} ' 'source. Use the hosted source instead. For example:\n' '\n' 'dependencies:\n'
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart index 50d1bfe..16b202f 100644 --- a/sdk/lib/_internal/pub/lib/src/validator/license.dart +++ b/sdk/lib/_internal/pub/lib/src/validator/license.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 pubspec_field_validator; +library license_validator; import 'dart:async';
diff --git a/sdk/lib/_internal/pub/test/install/unknown_source_test.dart b/sdk/lib/_internal/pub/test/install/unknown_source_test.dart new file mode 100644 index 0000000..e8250c5 --- /dev/null +++ b/sdk/lib/_internal/pub/test/install/unknown_source_test.dart
@@ -0,0 +1,80 @@ +// Copyright (c) 2012, 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 d.file. + +library pub_tests; + +import 'dart:io'; +import 'dart:json' as json; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +main() { + initConfig(); + integration('fails gracefully on a dependency from an unknown source', () { + d.appDir([{"bad": "foo"}]).create(); + + schedulePub(args: ['install'], + error: new RegExp("Package 'myapp' depends on 'foo' from unknown " + "source 'bad'.\$"), + exitCode: 1); + }); + + integration('fails gracefully on transitive dependency from an unknown ' + 'source', () { + d.dir('foo', [ + d.libDir('foo', 'foo 0.0.1'), + d.libPubspec('foo', '0.0.1', deps: [{"bad": "bar"}]) + ]).create(); + + d.appDir([{"path": "../foo"}]).create(); + + schedulePub(args: ['install'], + error: new RegExp("Package 'foo' depends on 'bar' from unknown " + "source 'bad'.\$"), + exitCode: 1); + }); + + integration('ignores unknown source in lockfile', () { + d.dir('foo', [ + d.libDir('foo'), + d.libPubspec('foo', '0.0.1') + ]).create(); + + // Depend on "foo" from a valid source. + d.dir(appPath, [ + d.pubspec({ + "name": "myapp", + "dependencies": { + "foo": {"path": "../foo"} + } + }) + ]).create(); + + // But lock it to a bad one. + d.dir(appPath, [ + d.file("pubspec.lock", json.stringify({ + 'packages': { + 'foo': { + 'version': '0.0.0', + 'source': 'bad', + 'description': { + 'name': 'foo' + } + } + } + })) + ]).create(); + + schedulePub(args: ['install'], + output: new RegExp(r"Dependencies installed!$")); + + // Should update to the new one. + d.dir(packagesPath, [ + d.dir("foo", [ + d.file("foo.dart", 'main() => "foo";') + ]) + ]).validate(); + }); +}
diff --git a/sdk/lib/_internal/pub/test/lock_file_test.dart b/sdk/lib/_internal/pub/test/lock_file_test.dart index 0f7fe53..8b05d9d 100644 --- a/sdk/lib/_internal/pub/test/lock_file_test.dart +++ b/sdk/lib/_internal/pub/test/lock_file_test.dart
@@ -13,6 +13,7 @@ import '../lib/src/source_registry.dart'; import '../lib/src/utils.dart'; import '../lib/src/version.dart'; +import 'test_pub.dart'; class MockSource extends Source { final String name = 'mock'; @@ -31,6 +32,8 @@ } main() { + initConfig(); + var sources = new SourceRegistry(); var mockSource = new MockSource(); sources.register(mockSource); @@ -65,16 +68,28 @@ var bar = lockFile.packages['bar']; expect(bar.name, equals('bar')); expect(bar.version, equals(new Version(1, 2, 3))); - expect(bar.source, equals(mockSource)); + expect(bar.source, equals(mockSource.name)); expect(bar.description, equals('bar desc')); var foo = lockFile.packages['foo']; expect(foo.name, equals('foo')); expect(foo.version, equals(new Version(2, 3, 4))); - expect(foo.source, equals(mockSource)); + expect(foo.source, equals(mockSource.name)); expect(foo.description, equals('foo desc')); }); + test("allows an unknown source", () { + var lockFile = new LockFile.parse(''' +packages: + foo: + source: bad + version: 1.2.3 + description: foo desc +''', sources); + var foo = lockFile.packages['foo']; + expect(foo.source, equals('bad')); + }); + test("throws if the version is missing", () { expect(() { new LockFile.parse(''' @@ -109,18 +124,6 @@ }, throwsFormatException); }); - test("throws if the source is unknown", () { - expect(() { - new LockFile.parse(''' -packages: - foo: - version: 1.2.3 - source: notreal - description: foo desc -''', sources); - }, throwsFormatException); - }); - test("throws if the description is missing", () { expect(() { new LockFile.parse(''' @@ -166,9 +169,9 @@ test('dumps the lockfile to YAML', () { lockfile.packages['foo'] = new PackageId( - 'foo', mockSource, new Version.parse('1.2.3'), 'foo desc'); + 'foo', mockSource.name, new Version.parse('1.2.3'), 'foo desc'); lockfile.packages['bar'] = new PackageId( - 'bar', mockSource, new Version.parse('3.2.1'), 'bar desc'); + 'bar', mockSource.name, new Version.parse('3.2.1'), 'bar desc'); expect(loadYaml(lockfile.serialize()), equals({ 'packages': { @@ -189,7 +192,7 @@ test('lockfile is alphabetized by package name', () { var testNames = ['baz', 'Qwe', 'Q', 'B', 'Bar', 'bar', 'foo']; testNames.forEach((name) { - lockfile.packages[name] = new PackageId(name, mockSource, + lockfile.packages[name] = new PackageId(name, mockSource.name, new Version.parse('5.5.5'), '$name desc'); });
diff --git a/sdk/lib/_internal/pub/test/pub_cache_test.dart b/sdk/lib/_internal/pub/test/pub_cache_test.dart index 6166514..cb38da7 100644 --- a/sdk/lib/_internal/pub/test/pub_cache_test.dart +++ b/sdk/lib/_internal/pub/test/pub_cache_test.dart
@@ -15,9 +15,9 @@ main() { initConfig(); - + integration('running pub cache displays error message', () { - schedulePub(args: ['cache'], + schedulePub(args: ['cache'], output: ''' Inspect the system cache. @@ -26,9 +26,9 @@ error: 'The cache command expects one argument.', exitCode: 64); }); - + integration('running pub cache foo displays error message', () { - schedulePub(args: ['cache' ,'foo'], + schedulePub(args: ['cache' ,'foo'], output: ''' Inspect the system cache. @@ -37,12 +37,12 @@ error: 'Unknown cache command "foo".', exitCode: 64); }); - - integration('running pub cache list when there is no cache', () { + + integration('running pub cache list when there is no cache', () { schedulePub(args: ['cache', 'list'], output: '{"packages":{}}'); }); - - integration('running pub cache list on empty cache', () { + + integration('running pub cache list on empty cache', () { // Set up a cache. d.dir(cachePath, [ d.dir('hosted', [ @@ -50,10 +50,10 @@ ]) ]) ]).create(); - + schedulePub(args: ['cache', 'list'], output: '{"packages":{}}'); }); - + integration('running pub cache list', () { // Set up a cache. d.dir(cachePath, [ @@ -69,11 +69,28 @@ ]) ]) ]).create(); - - schedulePub(args: ['cache', 'list'], output: + + schedulePub(args: ['cache', 'list'], output: new RegExp(r'\{"packages":\{"bar":\{"version":"2\.0\.0","location":' r'"[^"]+bar-2\.0\.0"\},"foo":\{"version":"1\.2\.3","location":' r'"[^"]+foo-1\.2\.3"\}\}\}$')); }); - + + integration('includes packages containing deps with bad sources', () { + // Set up a cache. + d.dir(cachePath, [ + d.dir('hosted', [ + d.dir('pub.dartlang.org', [ + d.dir("foo-1.2.3", [ + d.libPubspec("foo", "1.2.3", deps: [{"bad": "bar"}]), + d.libDir("foo") + ]) + ]) + ]) + ]).create(); + + schedulePub(args: ['cache', 'list'], output: + new RegExp(r'\{"packages":\{"foo":\{"version":"1\.2\.3","location":' + r'"[^"]+foo-1\.2\.3"\}\}\}$')); + }); } \ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart index 19f62d4..45413db 100644 --- a/sdk/lib/_internal/pub/test/pubspec_test.dart +++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -81,6 +81,18 @@ expect(pubspec.devDependencies, isEmpty); }); + test("allows an unknown source", () { + var pubspec = new Pubspec.parse(null, ''' +dependencies: + foo: + unknown: blah +''', sources); + + var foo = pubspec.dependencies[0]; + expect(foo.name, equals('foo')); + expect(foo.source, equals('unknown')); + }); + test("throws if a package is in dependencies and dev_dependencies", () { expectFormatError(''' dependencies:
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart index 8d417ed..37bf6d0 100644 --- a/sdk/lib/_internal/pub/test/test_pub.dart +++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -545,20 +545,6 @@ for (var dependency in resolvedDependencies) { var keys = dependency.keys.where((key) => key != "version"); var sourceName = only(keys); - var source; - switch (sourceName) { - case "git": - source = new GitSource(); - break; - case "hosted": - source = new HostedSource(); - break; - case "path": - source = new PathSource(); - break; - default: - throw new Exception('Unknown source "$sourceName"'); - } result[_packageName(sourceName, dependency[sourceName])] = dependency; }
diff --git a/sdk/lib/_internal/pub/test/update/unknown_source_test.dart b/sdk/lib/_internal/pub/test/update/unknown_source_test.dart new file mode 100644 index 0000000..92dfe1f --- /dev/null +++ b/sdk/lib/_internal/pub/test/update/unknown_source_test.dart
@@ -0,0 +1,80 @@ +// Copyright (c) 2012, 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 d.file. + +library pub_tests; + +import 'dart:io'; +import 'dart:json' as json; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +main() { + initConfig(); + integration('fails gracefully on a dependency from an unknown source', () { + d.appDir([{"bad": "foo"}]).create(); + + schedulePub(args: ['update'], + error: new RegExp("Package 'myapp' depends on 'foo' from unknown " + "source 'bad'.\$"), + exitCode: 1); + }); + + integration('fails gracefully on transitive dependency from an unknown ' + 'source', () { + d.dir('foo', [ + d.libDir('foo', 'foo 0.0.1'), + d.libPubspec('foo', '0.0.1', deps: [{"bad": "bar"}]) + ]).create(); + + d.appDir([{"path": "../foo"}]).create(); + + schedulePub(args: ['update'], + error: new RegExp("Package 'foo' depends on 'bar' from unknown " + "source 'bad'.\$"), + exitCode: 1); + }); + + integration('ignores unknown source in lockfile', () { + d.dir('foo', [ + d.libDir('foo'), + d.libPubspec('foo', '0.0.1') + ]).create(); + + // Depend on "foo" from a valid source. + d.dir(appPath, [ + d.pubspec({ + "name": "myapp", + "dependencies": { + "foo": {"path": "../foo"} + } + }) + ]).create(); + + // But lock it to a bad one. + d.dir(appPath, [ + d.file("pubspec.lock", json.stringify({ + 'packages': { + 'foo': { + 'version': '0.0.0', + 'source': 'bad', + 'description': { + 'name': 'foo' + } + } + } + })) + ]).create(); + + schedulePub(args: ['update'], + output: new RegExp(r"Dependencies updated!$")); + + // Should update to the new one. + d.dir(packagesPath, [ + d.dir("foo", [ + d.file("foo.dart", 'main() => "foo";') + ]) + ]).validate(); + }); +}
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart index 35af3ac..47d7198 100644 --- a/sdk/lib/_internal/pub/test/version_solver_test.dart +++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -40,6 +40,7 @@ group('root dependency', rootDependency); group('dev dependency', devDependency); group('unsolvable', unsolvable); + group('bad source', badSource); group('backtracking', backtracking); group('SDK constraint', sdkConstraint); } @@ -404,6 +405,55 @@ }, error: couldNotSolve, maxTries: 4); } +badSource() { + testResolve('fail if the root package has a bad source in dep', { + 'myapp 0.0.0': { + 'foo from bad': 'any' + }, + }, error: unknownSource('myapp', 'foo', 'bad')); + + testResolve('fail if the root package has a bad source in dev dep', { + 'myapp 0.0.0': { + '(dev) foo from bad': 'any' + }, + }, error: unknownSource('myapp', 'foo', 'bad')); + + testResolve('fail if all versions have bad source in dep', { + 'myapp 0.0.0': { + 'foo': 'any' + }, + 'foo 1.0.0': { + 'bar from bad': 'any' + }, + 'foo 1.0.1': { + 'baz from bad': 'any' + }, + 'foo 1.0.3': { + 'bang from bad': 'any' + }, + }, error: unknownSource('foo', 'bar', 'bad'), maxTries: 3); + + testResolve('ignore versions with bad source in dep', { + 'myapp 1.0.0': { + 'foo': 'any' + }, + 'foo 1.0.0': { + 'bar': 'any' + }, + 'foo 1.0.1': { + 'bar from bad': 'any' + }, + 'foo 1.0.3': { + 'bar from bad': 'any' + }, + 'bar 1.0.0': {} + }, result: { + 'myapp from root': '1.0.0', + 'foo': '1.0.0', + 'bar': '1.0.0' + }, maxTries: 3); +} + backtracking() { testResolve('circular dependency on older version', { 'myapp 0.0.0': { @@ -775,7 +825,7 @@ // remote server. root = package; } else { - source.addPackage(name, package); + cache.sources[source].addPackage(name, package); } }); }); @@ -797,7 +847,7 @@ lockfile.forEach((name, version) { version = new Version.parse(version); realLockFile.packages[name] = - new PackageId(name, source1, version, name); + new PackageId(name, source1.name, version, name); }); } @@ -856,6 +906,11 @@ SourceMismatchException); } +unknownSource(String depender, String dependency, String source) { + return (maxTries) => new SolveFailMatcher([depender, dependency, source], + maxTries, UnknownSourceException); +} + class SolveSuccessMatcher implements Matcher { /// The expected concrete package selections. final Map<String, PackageId> _expected; @@ -877,7 +932,7 @@ MatchState state, bool verbose) { if (!result.succeeded) { description.add('Solver failed with:\n${result.error}'); - return; + return null; } description.add('Resolved:\n${_listPackages(result.packages)}\n'); @@ -1033,6 +1088,7 @@ throw new Exception('MockSource does not have a package matching ' '"$description".'); } + return _packages[description].keys.toList(); }); } @@ -1098,7 +1154,7 @@ } void parseSource(String description, - callback(bool isDev, String name, Source source)) { + callback(bool isDev, String name, String source)) { var isDev = false; if (description.startsWith("(dev) ")) { @@ -1107,18 +1163,12 @@ } var name = description; - var source = source1; - - var sourceNames = { - 'mock1': source1, - 'mock2': source2, - 'root': null - }; - + var source = "mock1"; var match = new RegExp(r"(.*) from (.*)").firstMatch(description); if (match != null) { name = match[1]; - source = sourceNames[match[2]]; + source = match[2]; + if (source == "root") source = null; } callback(isDev, name, source);
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart index 3e7dbdc..6ff3ee2 100644 --- a/sdk/lib/async/stream_controller.dart +++ b/sdk/lib/async/stream_controller.dart
@@ -50,11 +50,6 @@ final _StreamImpl<T> stream; /** - * - * If the stream is canceled before the controller needs new data the - * [onResume] call might not be executed. - : stream = new _MultiControllerStream<T>( - onListen, onPause, onResume, onCancel); * A controller with a [stream] that supports only one single subscriber. * * The controller will buffer all incoming events until the subscriber is
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index 9a0bf6f..ef6239a 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart
@@ -39,7 +39,7 @@ Iterator<E> get iterator; /** - * Returns a lazy [Iterable] where each element [:e:] of [this] is replaced + * Returns a lazy [Iterable] where each element [:e:] of `this` is replaced * by the result of [:f(e):]. * * This method returns a view of the mapped elements. As long as the @@ -112,7 +112,7 @@ /** * Returns true if every elements of this collection satisify the - * predicate [f]. Returns false otherwise. + * predicate [f]. Returns `false` otherwise. */ bool every(bool f(E element)); @@ -164,7 +164,7 @@ /** * Returns an [Iterable] with at most [n] elements. * - * The returned [Iterable] may contain fewer than [n] elements, if [this] + * The returned [Iterable] may contain fewer than [n] elements, if `this` * contains fewer than [n] elements. */ Iterable<E> take(int n); @@ -173,9 +173,10 @@ * Returns an [Iterable] that stops once [test] is not satisfied anymore. * * The filtering happens lazily. Every new [Iterator] of the returned - * [Iterable] will start iterating over the elements of [this]. - * When the iterator encounters an element [:e:] that does not satisfy [test], - * it discards [:e:] and moves into the finished state. That is, it will not + * [Iterable] will start iterating over the elements of `this`. + * + * When the iterator encounters an element `e` that does not satisfy [test], + * it discards `e` and moves into the finished state. That is, it will not * ask or provide any more elements. */ Iterable<E> takeWhile(bool test(E value)); @@ -183,7 +184,7 @@ /** * Returns an [Iterable] that skips the first [n] elements. * - * If [this] has fewer than [n] elements, then the resulting [Iterable] will + * If `this` has fewer than [n] elements, then the resulting [Iterable] will * be empty. */ Iterable<E> skip(int n); @@ -192,17 +193,20 @@ * Returns an [Iterable] that skips elements while [test] is satisfied. * * The filtering happens lazily. Every new [Iterator] of the returned - * [Iterable] will iterate over all elements of [this]. + * [Iterable] will iterate over all elements of `this`. + * * As long as the iterator's elements do not satisfy [test] they are * discarded. Once an element satisfies the [test] the iterator stops testing - * and uses every element unconditionally. + * and uses every element unconditionally. That is, the elements of the + * returned [Iterable] are the elements of `this` starting from the first + * element that doesn't satisfy [test]. */ Iterable<E> skipWhile(bool test(E value)); /** * Returns the first element. * - * If [this] is empty throws a [StateError]. Otherwise this method is + * If `this` is empty throws a [StateError]. Otherwise this method is * equivalent to [:this.elementAt(0):] */ E get first; @@ -210,14 +214,14 @@ /** * Returns the last element. * - * If [this] is empty throws a [StateError]. + * If `this` is empty throws a [StateError]. */ E get last; /** - * Returns the single element in [this]. + * Returns the single element in `this`. * - * If [this] is empty or has more than one element throws a [StateError]. + * If `this` is empty or has more than one element throws a [StateError]. */ E get single; @@ -234,7 +238,7 @@ * Returns the last element that satisfies the given predicate [f]. * * If none matches, the result of invoking the [orElse] function is - * returned. By default, when [orElse] is [:null:], a [StateError] is + * returned. By default, when [orElse] is `null`, a [StateError] is * thrown. */ E lastWhere(bool test(E value), {E orElse()}); @@ -248,12 +252,11 @@ /** * Returns the [index]th element. * - * If [this] [Iterable] has fewer than [index] elements throws a - * [RangeError]. + * If `this` has fewer than [index] elements throws a [RangeError]. * - * Note: if [this] does not have a deterministic iteration order then the + * Note: if `this` does not have a deterministic iteration order then the * function may simply return any element without any iteration if there are - * at least [index] elements in [this]. + * at least [index] elements in `this`. */ E elementAt(int index); }
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart index 59a1563..672c8b8 100644 --- a/sdk/lib/core/list.dart +++ b/sdk/lib/core/list.dart
@@ -21,18 +21,18 @@ * * Example: * - * var fixedLengthList = new List(5); - * fixedLengthList.length = 0; // throws. - * fixedLengthList.add(499); // throws - * fixedLengthList[0] = 87; - * var growableList = [1, 2]; - * growableList.length = 0; - * growableList.add(499); - * growableList[0] = 87; - * var unmodifiableList = const [1, 2]; - * unmodifiableList.length = 0; // throws. - * unmodifiableList.add(499); // throws - * unmodifiableList[0] = 87; // throws. + * var fixedLengthList = new List(5); + * fixedLengthList.length = 0; // throws. + * fixedLengthList.add(499); // throws + * fixedLengthList[0] = 87; + * var growableList = [1, 2]; + * growableList.length = 0; + * growableList.add(499); + * growableList[0] = 87; + * var unmodifiableList = const [1, 2]; + * unmodifiableList.length = 0; // throws. + * unmodifiableList.add(499); // throws + * unmodifiableList[0] = 87; // throws. * * Lists are [Iterable]. * List iteration iterates over values in index order. @@ -94,7 +94,7 @@ * for each index in the range `0` .. `[length] - 1` * in increasing order. * - * The created length's length is fixed unless [growable] is true. + * The created list's length is fixed unless [growable] is true. */ factory List.generate(int length, E generator(int index), { bool growable: true }) { @@ -118,6 +118,7 @@ /** * Sets the entry at the given [index] in the list to [value]. + * * Throws an [RangeError] if [index] is out of bounds. */ void operator []=(int index, E value); @@ -131,20 +132,23 @@ /** * Changes the length of the list. If [newLength] is greater than - * the current [length], entries are initialized to [:null:]. Throws - * an [UnsupportedError] if the list is not extendable. + * the current [length], entries are initialized to [:null:]. + * + * Throws an [UnsupportedError] if the list is not extendable. */ void set length(int newLength); /** * Adds [value] at the end of the list, extending the length by - * one. Throws an [UnsupportedError] if the list is not - * extendable. + * one. + * + * Throws an [UnsupportedError] if the list is not extendable. */ void add(E value); /** * Appends all elements of the [iterable] to the end of this list. + * * Extends the length of the list by the number of elements in [iterable]. * Throws an [UnsupportedError] if this list is not extensible. */ @@ -159,6 +163,7 @@ * Sorts the list according to the order specified by the [compare] function. * * The [compare] function must act as a [Comparator]. + * * The default [List] implementations use [Comparable.compare] if * [compare] is omitted. */ @@ -178,9 +183,12 @@ * Returns the last index of [element] in the list. * * Searches the list backwards from index [start] (inclusive) to 0. + * * The first time an element [:e:] is encountered so that [:e == element:], * the index of [:e:] is returned. - * If start is not provided, it defaults to [:this.length - 1:] . + * + * If start is not provided, it defaults to [:this.length - 1:]. + * * Returns -1 if [element] is not found. */ int lastIndexOf(E element, [int start]); @@ -189,6 +197,7 @@ * Removes all elements in the list. * * The length of the list becomes zero. + * * Throws an [UnsupportedError], and retains all elements, if the * length of the list cannot be changed. */ @@ -220,7 +229,7 @@ * Overwrites elements of `this` with the elemenst of [iterable] starting * at position [index] in the list. * - * This operation does not increase the length of the list. + * This operation does not increase the length of `this`. * * It is an error if the [index] does not point inside the list or at the * position after the last element. @@ -239,14 +248,18 @@ /** * Removes the element at position [index] from the list. * - * This reduces the length of the list by one and moves all later elements + * This reduces the length of `this` by one and moves all later elements * down by one position. + * * Returns the removed element. + * * Throws an [ArgumentError] if [index] is not an [int]. + * * Throws an [RangeError] if the [index] does not point inside * the list. + * * Throws an [UnsupportedError], and doesn't remove the element, - * if the length of the list cannot be changed. + * if the length of `this` cannot be changed. */ E removeAt(int index); @@ -274,9 +287,9 @@ /** * Returns a new list containing the elements from [start] to [end]. * - * If [end] is omitted, the [length] of the list is used. + * If [end] is omitted, the [length] of `this` is used. * - * It is an error if [start] or [end] are not list indices for this list, + * It is an error if [start] or [end] are not indices into `this`, * or if [end] is before [start]. */ List<E> sublist(int start, [int end]); @@ -304,17 +317,24 @@ Iterable<E> getRange(int start, int end); /** - * Copies the elements of [iterable], skipping the [skipCount] first elements + * Copies the elements of [iterable], skipping the [skipCount] first elements, * into the range [start] to [end] exclusive of `this`. * - * If [start] equals [end] and represent a legal range, this method has - * no effect. + * If [start] equals [end] and [start]..[end] represents a legal range, this + * method has no effect. * * It is an error if [start]..[end] is not a valid range pointing into the * `this`. * * It is an error if the [iterable] does not have enough elements after * skipping [skipCount] elements. + * + * Example: + * + * var list = [1, 2, 3, 4]; + * var list2 = [5, 6, 7, 8, 9]; + * list.setRange(1, 3, list2, 3); + * print(list); // => [1, 8, 9, 4] */ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]);
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart index ebcfe10..7db20f3 100644 --- a/sdk/lib/core/string.dart +++ b/sdk/lib/core/string.dart
@@ -145,13 +145,31 @@ String substring(int startIndex, [int endIndex]); /** - * Removes leading and trailing whitespace from a string. If the string - * contains leading or trailing whitespace a new string with no leading and - * no trailing whitespace is returned. Otherwise, the string itself is - * returned. Whitespace is defined as every Unicode character in the Zs, Zl - * and Zp categories (this includes no-break space), the spacing control - * characters from 9 to 13 (tab, lf, vtab, ff and cr), and 0xfeff the BOM - * character. + * Removes leading and trailing whitespace from a string. + * + * If the string contains leading or trailing whitespace a new string with no + * leading and no trailing whitespace is returned. Otherwise, the string + * itself is returned. + * + * Whitespace is defined by the Unicode White_Space property (as defined in + * version 6.2 or later) and the BOM character, 0xFEFF. + * + * Here is the list of trimmed characters (following version 6.2): + * + * 0009..000D ; White_Space # Cc <control-0009>..<control-000D> + * 0020 ; White_Space # Zs SPACE + * 0085 ; White_Space # Cc <control-0085> + * 00A0 ; White_Space # Zs NO-BREAK SPACE + * 1680 ; White_Space # Zs OGHAM SPACE MARK + * 180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR + * 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE + * 2028 ; White_Space # Zl LINE SEPARATOR + * 2029 ; White_Space # Zp PARAGRAPH SEPARATOR + * 202F ; White_Space # Zs NARROW NO-BREAK SPACE + * 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE + * 3000 ; White_Space # Zs IDEOGRAPHIC SPACE + * + * FEFF ; BOM ZERO WIDTH NO_BREAK SPACE */ String trim();
diff --git a/sdk/lib/crypto/sha1.dart b/sdk/lib/crypto/sha1.dart index 83e9217..8ee28ce 100644 --- a/sdk/lib/crypto/sha1.dart +++ b/sdk/lib/crypto/sha1.dart
@@ -38,15 +38,15 @@ var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16]; _w[i] = _rotl32(n, 1); } - var t = _rotl32(a, 5) + e + _w[i]; + var t = _add32(_add32(_rotl32(a, 5), e), _w[i]); if (i < 20) { - t = t + ((b & c) | (~b & d)) + 0x5A827999; + t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999); } else if (i < 40) { - t = t + (b ^ c ^ d) + 0x6ED9EBA1; + t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1); } else if (i < 60) { - t = t + ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC; + t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC); } else { - t = t + (b ^ c ^ d) + 0xCA62C1D6; + t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6); } e = d;
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart index fc77a39..3bb3ec2 100644 --- a/sdk/lib/html/dart2js/html_dart2js.dart +++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -65,7 +65,7 @@ return JS('var', r'ReceivePortSync.dispatchCall(#, #)', id, message); } -spawnDomFunction(f) => IsolateNatives.spawnDomFunction(f); +spawnDomFunction(Function f) => IsolateNatives.spawnDomFunction(f); // 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. @@ -1535,7 +1535,7 @@ '#.lineDashOffset || #.webkitLineDashOffset', this, this); @DomName('CanvasRenderingContext2D.lineDashOffset') - void set lineDashOffset(num value) => JS('void', + void set lineDashOffset(num value) => JS('void', 'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : ' '#.webkitLineDashOffset = #', this, this, value, this, value); } @@ -1662,7 +1662,7 @@ @DomName('Console') class Console { - static Console safeConsole = new Console(); + static Console _safeConsole = new Console(); bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"'); @@ -1735,8 +1735,8 @@ JS('void', 'console.time(#)', title) : null; @DomName('Console.timeEnd') - void timeEnd(String timerName) => _isConsoleDefined ? - JS('void', 'console.timeEnd(#)', timerName) : null; + void timeEnd(String title) => _isConsoleDefined ? + JS('void', 'console.timeEnd(#)', title) : null; @DomName('Console.timeStamp') void timeStamp(Object arg) => _isConsoleDefined ? @@ -6110,6 +6110,10 @@ @DocsEditable static const EventStreamProvider<Event> readyStateChangeEvent = const EventStreamProvider<Event>('readystatechange'); + @DomName('Document.securitypolicyviolationEvent') + @DocsEditable + static const EventStreamProvider<SecurityPolicyViolationEvent> securityPolicyViolationEvent = const EventStreamProvider<SecurityPolicyViolationEvent>('securitypolicyviolation'); + @DomName('Document.selectionchangeEvent') @DocsEditable static const EventStreamProvider<Event> selectionChangeEvent = const EventStreamProvider<Event>('selectionchange'); @@ -6634,6 +6638,10 @@ @DocsEditable Stream<Event> get onSearch => Element.searchEvent.forTarget(this); + @DomName('Document.onsecuritypolicyviolation') + @DocsEditable + Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation => securityPolicyViolationEvent.forTarget(this); + @DomName('Document.onselect') @DocsEditable Stream<Event> get onSelect => Element.selectEvent.forTarget(this); @@ -7590,11 +7598,11 @@ * * [insertAdjacentText] * * [insertAdjacentElement] */ - void insertAdjacentHtml(String where, String text) { + void insertAdjacentHtml(String where, String html) { if (JS('bool', '!!#.insertAdjacentHtml', this)) { - _insertAdjacentHtml(where, text); + _insertAdjacentHtml(where, html); } else { - _insertAdjacentNode(where, new DocumentFragment.html(text)); + _insertAdjacentNode(where, new DocumentFragment.html(html)); } } @@ -7660,7 +7668,7 @@ throw new UnsupportedError("Not supported on this platform"); } - @Creates('Null') + @Creates('Null') // Set from Dart code; does not instantiate a native type. Map<String, StreamSubscription> _attributeBindings; // TODO(jmesserly): I'm concerned about adding these to every element. @@ -10039,7 +10047,19 @@ @DomName('FontLoader.loadEvent') @DocsEditable - static const EventStreamProvider<Event> loadEvent = const EventStreamProvider<Event>('load'); + static const EventStreamProvider<CssFontFaceLoadEvent> loadEvent = const EventStreamProvider<CssFontFaceLoadEvent>('load'); + + @DomName('FontLoader.loadingEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadingEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loading'); + + @DomName('FontLoader.loadingdoneEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadingDoneEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadingdone'); + + @DomName('FontLoader.loadstartEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadStartEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadstart'); @DomName('FontLoader.loading') @DocsEditable @@ -10085,7 +10105,19 @@ @DomName('FontLoader.onload') @DocsEditable - Stream<Event> get onLoad => loadEvent.forTarget(this); + Stream<CssFontFaceLoadEvent> get onLoad => loadEvent.forTarget(this); + + @DomName('FontLoader.onloading') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoading => loadingEvent.forTarget(this); + + @DomName('FontLoader.onloadingdone') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoadingDone => loadingDoneEvent.forTarget(this); + + @DomName('FontLoader.onloadstart') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoadStart => loadStartEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -10127,6 +10159,14 @@ @DomName('HTMLFormElement') class FormElement extends Element native "HTMLFormElement" { + @DomName('HTMLFormElement.autocompleteEvent') + @DocsEditable + static const EventStreamProvider<Event> autocompleteEvent = const EventStreamProvider<Event>('autocomplete'); + + @DomName('HTMLFormElement.autocompleteerrorEvent') + @DocsEditable + static const EventStreamProvider<AutocompleteErrorEvent> autocompleteErrorEvent = const EventStreamProvider<AutocompleteErrorEvent>('autocompleteerror'); + @DomName('HTMLFormElement.HTMLFormElement') @DocsEditable factory FormElement() => document.$dom_createElement("form"); @@ -10186,6 +10226,14 @@ @DomName('HTMLFormElement.submit') @DocsEditable void submit() native; + + @DomName('HTMLFormElement.onautocomplete') + @DocsEditable + Stream<Event> get onAutocomplete => autocompleteEvent.forTarget(this); + + @DomName('HTMLFormElement.onautocompleteerror') + @DocsEditable + Stream<AutocompleteErrorEvent> get onAutocompleteError => autocompleteErrorEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -11372,39 +11420,6 @@ @DocsEditable -@DomName('XMLHttpRequestException') -class HttpRequestException native "XMLHttpRequestException" { - - @DomName('XMLHttpRequestException.ABORT_ERR') - @DocsEditable - static const int ABORT_ERR = 102; - - @DomName('XMLHttpRequestException.NETWORK_ERR') - @DocsEditable - static const int NETWORK_ERR = 101; - - @DomName('XMLHttpRequestException.code') - @DocsEditable - final int code; - - @DomName('XMLHttpRequestException.message') - @DocsEditable - final String message; - - @DomName('XMLHttpRequestException.name') - @DocsEditable - final String name; - - @DomName('XMLHttpRequestException.toString') - @DocsEditable - String toString() native; -} -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - - -@DocsEditable @DomName('XMLHttpRequestProgressEvent') @SupportedBrowser(SupportedBrowser.CHROME) @SupportedBrowser(SupportedBrowser.SAFARI) @@ -14253,6 +14268,15 @@ @DocsEditable +@DomName('MIDIInput') +class MidiInput extends MidiPort implements EventTarget native "MIDIInput" { +} +// 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. + + +@DocsEditable @DomName('MIDIMessageEvent') class MidiMessageEvent extends Event native "MIDIMessageEvent" { @@ -14273,6 +14297,10 @@ @DomName('MIDIPort') class MidiPort extends EventTarget native "MIDIPort" { + @DomName('MIDIPort.disconnectEvent') + @DocsEditable + static const EventStreamProvider<MidiConnectionEvent> disconnectEvent = const EventStreamProvider<MidiConnectionEvent>('disconnect'); + @DomName('MIDIPort.id') @DocsEditable final String id; @@ -14306,6 +14334,10 @@ @DomName('MIDIPort.removeEventListener') @DocsEditable void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native; + + @DomName('MIDIPort.ondisconnect') + @DocsEditable + Stream<MidiConnectionEvent> get onDisconnect => disconnectEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -14568,13 +14600,12 @@ return new Point(x, y); } else { // Firefox does not support offsetX. - var target = this.target; - if (!(target is Element)) { + if (!(this.target is Element)) { throw new UnsupportedError( 'offsetX is only supported on elements'); } - return (this.client - - this.target.getBoundingClientRect().topLeft).toInt(); + Element target = this.target; + return (this.client - target.getBoundingClientRect().topLeft).toInt(); } } @@ -15127,11 +15158,12 @@ void addAll(Iterable<Node> iterable) { if (iterable is _ChildNodeListLazy) { - if (!identical(iterable._this, _this)) { + _ChildNodeListLazy otherList = iterable; + if (!identical(otherList._this, _this)) { // Optimized route for copying between nodes. - for (var i = 0, len = iterable.length; i < len; ++i) { + for (var i = 0, len = otherList.length; i < len; ++i) { // Should use $dom_firstChild, Bug 8886. - _this.append(iterable[0]); + _this.append(otherList[0]); } } return; @@ -16287,6 +16319,13 @@ @SupportedBrowser(SupportedBrowser.IE) class Performance extends EventTarget native "Performance" { + @DomName('Performance.webkitresourcetimingbufferfullEvent') + @DocsEditable + @SupportedBrowser(SupportedBrowser.CHROME) + @SupportedBrowser(SupportedBrowser.SAFARI) + @Experimental + static const EventStreamProvider<Event> resourceTimingBufferFullEvent = const EventStreamProvider<Event>('webkitresourcetimingbufferfull'); + /// Checks if this type is supported on the current platform. static bool get supported => JS('bool', '!!(window.performance)'); @@ -16349,6 +16388,10 @@ @SupportedBrowser(SupportedBrowser.SAFARI) @Experimental void setResourceTimingBufferSize(int maxSize) native; + + @DomName('Performance.onwebkitresourcetimingbufferfull') + @DocsEditable + Stream<Event> get onResourceTimingBufferFull => resourceTimingBufferFullEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -17063,39 +17106,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. - -@DocsEditable -@DomName('RangeException') -class RangeException native "RangeException" { - - @DomName('RangeException.BAD_BOUNDARYPOINTS_ERR') - @DocsEditable - static const int BAD_BOUNDARYPOINTS_ERR = 1; - - @DomName('RangeException.INVALID_NODE_TYPE_ERR') - @DocsEditable - static const int INVALID_NODE_TYPE_ERR = 2; - - @DomName('RangeException.code') - @DocsEditable - final int code; - - @DomName('RangeException.message') - @DocsEditable - final String message; - - @DomName('RangeException.name') - @DocsEditable - final String name; - - @DomName('RangeException.toString') - @DocsEditable - String toString() native; -} -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - // WARNING: Do not edit - generated code. @@ -18881,14 +18891,34 @@ @DomName('SpeechSynthesisUtterance') class SpeechSynthesisUtterance extends EventTarget native "SpeechSynthesisUtterance" { + @DomName('SpeechSynthesisUtterance.boundaryEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent = const EventStreamProvider<SpeechSynthesisEvent>('boundary'); + + @DomName('SpeechSynthesisUtterance.endEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> endEvent = const EventStreamProvider<SpeechSynthesisEvent>('end'); + @DomName('SpeechSynthesisUtterance.errorEvent') @DocsEditable static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error'); + @DomName('SpeechSynthesisUtterance.markEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> markEvent = const EventStreamProvider<SpeechSynthesisEvent>('mark'); + @DomName('SpeechSynthesisUtterance.pauseEvent') @DocsEditable static const EventStreamProvider<Event> pauseEvent = const EventStreamProvider<Event>('pause'); + @DomName('SpeechSynthesisUtterance.resumeEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent = const EventStreamProvider<SpeechSynthesisEvent>('resume'); + + @DomName('SpeechSynthesisUtterance.startEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> startEvent = const EventStreamProvider<SpeechSynthesisEvent>('start'); + @DomName('SpeechSynthesisUtterance.SpeechSynthesisUtterance') @DocsEditable factory SpeechSynthesisUtterance([String text]) { @@ -18924,13 +18954,33 @@ @DocsEditable num volume; + @DomName('SpeechSynthesisUtterance.onboundary') + @DocsEditable + Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this); + + @DomName('SpeechSynthesisUtterance.onend') + @DocsEditable + Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onerror') @DocsEditable Stream<Event> get onError => errorEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onmark') + @DocsEditable + Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onpause') @DocsEditable Stream<Event> get onPause => pauseEvent.forTarget(this); + + @DomName('SpeechSynthesisUtterance.onresume') + @DocsEditable + Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this); + + @DomName('SpeechSynthesisUtterance.onstart') + @DocsEditable + Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -20822,9 +20872,9 @@ '(self.URL || self.webkitURL).createObjectURL(#)', blob_OR_source_OR_stream); - static void revokeObjectUrl(String objectUrl) => + static void revokeObjectUrl(String url) => JS('void', - '(self.URL || self.webkitURL).revokeObjectURL(#)', objectUrl); + '(self.URL || self.webkitURL).revokeObjectURL(#)', url); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file @@ -21535,7 +21585,7 @@ return _requestAnimationFrame(callback); } - void cancelAnimationFrame(id) { + void cancelAnimationFrame(int id) { _ensureRequestAnimationFrame(); _cancelAnimationFrame(id); } @@ -21588,7 +21638,7 @@ this, this, this); @DomName('Window.console') - Console get console => Console.safeConsole; + Console get console => Console._safeConsole; /// Checks if _setImmediate is supported. static bool get _supportsSetImmediate => @@ -24450,16 +24500,16 @@ } } - bool get _paused => _pauseCount > 0; + bool get isPaused => _pauseCount > 0; void resume() { - if (_canceled || !_paused) return; + if (_canceled || !isPaused) return; --_pauseCount; _tryResume(); } void _tryResume() { - if (_onData != null && !_paused) { + if (_onData != null && !isPaused) { _target.$dom_addEventListener(_eventType, _onData, _useCapture); } } @@ -24583,7 +24633,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void remove(Object object) { + bool remove(Object object) { throw new UnsupportedError("Cannot remove from immutable List."); } @@ -24595,7 +24645,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) { + void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { throw new UnsupportedError("Cannot setRange on immutable List."); } @@ -26667,7 +26717,7 @@ } // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner - static Document _getTemplateContentsOwner(Document doc) { + static Document _getTemplateContentsOwner(HtmlDocument doc) { if (doc.window == null) { return doc; } @@ -26745,7 +26795,7 @@ // template. // TODO(jmesserly): node is DocumentFragment or Element var descendents = (node as dynamic).queryAll(_allTemplatesSelectors); - if (node is Element && node.isTemplate) bootstrap(node); + if (node is Element && (node as Element).isTemplate) bootstrap(node); descendents.forEach(bootstrap); } @@ -26899,7 +26949,7 @@ static void _removeChild(Node parent, Node child) { child._templateInstance = null; - if (child is Element && child.isTemplate) { + if (child is Element && (child as Element).isTemplate) { // Make sure we stop observing when we remove an element. var templateIterator = child._templateIterator; if (templateIterator != null) { @@ -27734,7 +27784,7 @@ void add(E element) { _list.add(element); } - void remove(Object element) { _list.remove(element); } + bool remove(Object element) => _list.remove(element); void clear() { _list.clear(); } @@ -27869,8 +27919,14 @@ // Assume it's a Window if it contains the setInterval property. It may be // from a different frame - without a patched prototype - so we cannot // rely on Dart type checking. - if (JS('bool', r'"setInterval" in #', e)) - return _DOMWindowCrossFrame._createSafe(e); + if (JS('bool', r'"setInterval" in #', e)) { + var window = _DOMWindowCrossFrame._createSafe(e); + // If it's a native window. + if (window is EventTarget) { + return window; + } + return null; + } else return e; }
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart index 6c139d5..0a9d8af 100644 --- a/sdk/lib/html/dartium/html_dartium.dart +++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1435,7 +1435,7 @@ @DocsEditable CanvasGradient createRadialGradient(num x0, num y0, num r0, num x1, num y1, num r1) native "CanvasRenderingContext2D_createRadialGradient_Callback"; - void $dom_drawImage(canvas_OR_image_OR_video, num sx_OR_x, num sy_OR_y, [num sw_OR_width, num height_OR_sh, num dx, num dy, num dw, num dh]) { + void _drawImage(canvas_OR_image_OR_video, num sx_OR_x, num sy_OR_y, [num sw_OR_width, num height_OR_sh, num dx, num dy, num dw, num dh]) { if ((canvas_OR_image_OR_video is ImageElement || canvas_OR_image_OR_video == null) && (sx_OR_x is num || sx_OR_x == null) && (sy_OR_y is num || sy_OR_y == null) && !?sw_OR_width && !?height_OR_sh && !?dx && !?dy && !?dw && !?dh) { _drawImage_1(canvas_OR_image_OR_video, sx_OR_x, sy_OR_y); return; @@ -1758,13 +1758,13 @@ void drawImageToRect(CanvasImageSource source, Rect destRect, {Rect sourceRect}) { if (sourceRect == null) { - $dom_drawImage(source, + _drawImage(source, destRect.left, destRect.top, destRect.width, destRect.height); } else { - $dom_drawImage(source, + _drawImage(source, sourceRect.left, sourceRect.top, sourceRect.width, @@ -1807,7 +1807,7 @@ */ @DomName('CanvasRenderingContext2D.drawImage') void drawImage(CanvasImageSource source, num destX, num destY) { - $dom_drawImage(source, destX, destY); + _drawImage(source, destX, destY); } /** @@ -1839,7 +1839,7 @@ @DomName('CanvasRenderingContext2D.drawImage') void drawImageScaled(CanvasImageSource source, num destX, num destY, num destWidth, num destHeight) { - $dom_drawImage(source, destX, destY, destWidth, destHeight); + _drawImage(source, destX, destY, destWidth, destHeight); } /** @@ -1875,7 +1875,7 @@ void drawImageScaledFromSource(CanvasImageSource source, num sourceX, num sourceY, num sourceWidth, num sourceHeight, num destX, num destY, num destWidth, num destHeight) { - $dom_drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, + _drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight); } @@ -6572,6 +6572,10 @@ @DocsEditable static const EventStreamProvider<Event> readyStateChangeEvent = const EventStreamProvider<Event>('readystatechange'); + @DomName('Document.securitypolicyviolationEvent') + @DocsEditable + static const EventStreamProvider<SecurityPolicyViolationEvent> securityPolicyViolationEvent = const EventStreamProvider<SecurityPolicyViolationEvent>('securitypolicyviolation'); + @DomName('Document.selectionchangeEvent') @DocsEditable static const EventStreamProvider<Event> selectionChangeEvent = const EventStreamProvider<Event>('selectionchange'); @@ -7062,6 +7066,10 @@ @DocsEditable Stream<Event> get onSearch => Element.searchEvent.forTarget(this); + @DomName('Document.onsecuritypolicyviolation') + @DocsEditable + Stream<SecurityPolicyViolationEvent> get onSecurityPolicyViolation => securityPolicyViolationEvent.forTarget(this); + @DomName('Document.onselect') @DocsEditable Stream<Event> get onSelect => Element.selectEvent.forTarget(this); @@ -7975,7 +7983,6 @@ } - @Creates('Null') Map<String, StreamSubscription> _attributeBindings; // TODO(jmesserly): I'm concerned about adding these to every element. @@ -10425,7 +10432,19 @@ @DomName('FontLoader.loadEvent') @DocsEditable - static const EventStreamProvider<Event> loadEvent = const EventStreamProvider<Event>('load'); + static const EventStreamProvider<CssFontFaceLoadEvent> loadEvent = const EventStreamProvider<CssFontFaceLoadEvent>('load'); + + @DomName('FontLoader.loadingEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadingEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loading'); + + @DomName('FontLoader.loadingdoneEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadingDoneEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadingdone'); + + @DomName('FontLoader.loadstartEvent') + @DocsEditable + static const EventStreamProvider<CssFontFaceLoadEvent> loadStartEvent = const EventStreamProvider<CssFontFaceLoadEvent>('loadstart'); @DomName('FontLoader.loading') @DocsEditable @@ -10461,7 +10480,19 @@ @DomName('FontLoader.onload') @DocsEditable - Stream<Event> get onLoad => loadEvent.forTarget(this); + Stream<CssFontFaceLoadEvent> get onLoad => loadEvent.forTarget(this); + + @DomName('FontLoader.onloading') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoading => loadingEvent.forTarget(this); + + @DomName('FontLoader.onloadingdone') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoadingDone => loadingDoneEvent.forTarget(this); + + @DomName('FontLoader.onloadstart') + @DocsEditable + Stream<CssFontFaceLoadEvent> get onLoadStart => loadStartEvent.forTarget(this); } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file @@ -10504,6 +10535,14 @@ class FormElement extends _Element_Merged { FormElement.internal() : super.internal(); + @DomName('HTMLFormElement.autocompleteEvent') + @DocsEditable + static const EventStreamProvider<Event> autocompleteEvent = const EventStreamProvider<Event>('autocomplete'); + + @DomName('HTMLFormElement.autocompleteerrorEvent') + @DocsEditable + static const EventStreamProvider<AutocompleteErrorEvent> autocompleteErrorEvent = const EventStreamProvider<AutocompleteErrorEvent>('autocompleteerror'); + @DomName('HTMLFormElement.HTMLFormElement') @DocsEditable factory FormElement() => document.$dom_createElement("form"); @@ -10600,6 +10639,14 @@ @DocsEditable void submit() native "HTMLFormElement_submit_Callback"; + @DomName('HTMLFormElement.onautocomplete') + @DocsEditable + Stream<Event> get onAutocomplete => autocompleteEvent.forTarget(this); + + @DomName('HTMLFormElement.onautocompleteerror') + @DocsEditable + Stream<AutocompleteErrorEvent> get onAutocompleteError => autocompleteErrorEvent.forTarget(this); + } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -11815,43 +11862,6 @@ @DocsEditable -@DomName('XMLHttpRequestException') -class HttpRequestException extends NativeFieldWrapperClass1 { - HttpRequestException.internal(); - - @DomName('XMLHttpRequestException.ABORT_ERR') - @DocsEditable - static const int ABORT_ERR = 102; - - @DomName('XMLHttpRequestException.NETWORK_ERR') - @DocsEditable - static const int NETWORK_ERR = 101; - - @DomName('XMLHttpRequestException.code') - @DocsEditable - int get code native "XMLHttpRequestException_code_Getter"; - - @DomName('XMLHttpRequestException.message') - @DocsEditable - String get message native "XMLHttpRequestException_message_Getter"; - - @DomName('XMLHttpRequestException.name') - @DocsEditable - String get name native "XMLHttpRequestException_name_Getter"; - - @DomName('XMLHttpRequestException.toString') - @DocsEditable - String toString() native "XMLHttpRequestException_toString_Callback"; - -} -// 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. - -// WARNING: Do not edit - generated code. - - -@DocsEditable @DomName('XMLHttpRequestProgressEvent') @SupportedBrowser(SupportedBrowser.CHROME) @SupportedBrowser(SupportedBrowser.SAFARI) @@ -15267,6 +15277,19 @@ @DocsEditable +@DomName('MIDIInput') +class MidiInput extends MidiPort implements EventTarget { + MidiInput.internal() : super.internal(); + +} +// 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. + +// WARNING: Do not edit - generated code. + + +@DocsEditable @DomName('MIDIMessageEvent') class MidiMessageEvent extends Event { MidiMessageEvent.internal() : super.internal(); @@ -15292,6 +15315,10 @@ class MidiPort extends EventTarget { MidiPort.internal() : super.internal(); + @DomName('MIDIPort.disconnectEvent') + @DocsEditable + static const EventStreamProvider<MidiConnectionEvent> disconnectEvent = const EventStreamProvider<MidiConnectionEvent>('disconnect'); + @DomName('MIDIPort.id') @DocsEditable String get id native "MIDIPort_id_Getter"; @@ -15324,6 +15351,10 @@ @DocsEditable void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native "MIDIPort_removeEventListener_Callback"; + @DomName('MIDIPort.ondisconnect') + @DocsEditable + Stream<MidiConnectionEvent> get onDisconnect => disconnectEvent.forTarget(this); + } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -16123,11 +16154,12 @@ void addAll(Iterable<Node> iterable) { if (iterable is _ChildNodeListLazy) { - if (!identical(iterable._this, _this)) { + _ChildNodeListLazy otherList = iterable; + if (!identical(otherList._this, _this)) { // Optimized route for copying between nodes. - for (var i = 0, len = iterable.length; i < len; ++i) { + for (var i = 0, len = otherList.length; i < len; ++i) { // Should use $dom_firstChild, Bug 8886. - _this.append(iterable[0]); + _this.append(otherList[0]); } } return; @@ -17409,6 +17441,13 @@ class Performance extends EventTarget { Performance.internal() : super.internal(); + @DomName('Performance.webkitresourcetimingbufferfullEvent') + @DocsEditable + @SupportedBrowser(SupportedBrowser.CHROME) + @SupportedBrowser(SupportedBrowser.SAFARI) + @Experimental + static const EventStreamProvider<Event> resourceTimingBufferFullEvent = const EventStreamProvider<Event>('webkitresourcetimingbufferfull'); + /// Checks if this type is supported on the current platform. static bool get supported => true; @@ -17470,6 +17509,10 @@ @Experimental void setResourceTimingBufferSize(int maxSize) native "Performance_webkitSetResourceTimingBufferSize_Callback"; + @DomName('Performance.onwebkitresourcetimingbufferfull') + @DocsEditable + Stream<Event> get onResourceTimingBufferFull => resourceTimingBufferFullEvent.forTarget(this); + } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -18260,43 +18303,6 @@ // WARNING: Do not edit - generated code. -@DocsEditable -@DomName('RangeException') -class RangeException extends NativeFieldWrapperClass1 { - RangeException.internal(); - - @DomName('RangeException.BAD_BOUNDARYPOINTS_ERR') - @DocsEditable - static const int BAD_BOUNDARYPOINTS_ERR = 1; - - @DomName('RangeException.INVALID_NODE_TYPE_ERR') - @DocsEditable - static const int INVALID_NODE_TYPE_ERR = 2; - - @DomName('RangeException.code') - @DocsEditable - int get code native "RangeException_code_Getter"; - - @DomName('RangeException.message') - @DocsEditable - String get message native "RangeException_message_Getter"; - - @DomName('RangeException.name') - @DocsEditable - String get name native "RangeException_name_Getter"; - - @DomName('RangeException.toString') - @DocsEditable - String toString() native "RangeException_toString_Callback"; - -} -// 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. - -// WARNING: Do not edit - generated code. - - typedef void RequestAnimationFrameCallback(num highResTime); // 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 @@ -20286,14 +20292,34 @@ class SpeechSynthesisUtterance extends EventTarget { SpeechSynthesisUtterance.internal() : super.internal(); + @DomName('SpeechSynthesisUtterance.boundaryEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> boundaryEvent = const EventStreamProvider<SpeechSynthesisEvent>('boundary'); + + @DomName('SpeechSynthesisUtterance.endEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> endEvent = const EventStreamProvider<SpeechSynthesisEvent>('end'); + @DomName('SpeechSynthesisUtterance.errorEvent') @DocsEditable static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error'); + @DomName('SpeechSynthesisUtterance.markEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> markEvent = const EventStreamProvider<SpeechSynthesisEvent>('mark'); + @DomName('SpeechSynthesisUtterance.pauseEvent') @DocsEditable static const EventStreamProvider<Event> pauseEvent = const EventStreamProvider<Event>('pause'); + @DomName('SpeechSynthesisUtterance.resumeEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> resumeEvent = const EventStreamProvider<SpeechSynthesisEvent>('resume'); + + @DomName('SpeechSynthesisUtterance.startEvent') + @DocsEditable + static const EventStreamProvider<SpeechSynthesisEvent> startEvent = const EventStreamProvider<SpeechSynthesisEvent>('start'); + @DomName('SpeechSynthesisUtterance.SpeechSynthesisUtterance') @DocsEditable factory SpeechSynthesisUtterance([String text]) { @@ -20351,14 +20377,34 @@ @DocsEditable void set volume(num value) native "SpeechSynthesisUtterance_volume_Setter"; + @DomName('SpeechSynthesisUtterance.onboundary') + @DocsEditable + Stream<SpeechSynthesisEvent> get onBoundary => boundaryEvent.forTarget(this); + + @DomName('SpeechSynthesisUtterance.onend') + @DocsEditable + Stream<SpeechSynthesisEvent> get onEnd => endEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onerror') @DocsEditable Stream<Event> get onError => errorEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onmark') + @DocsEditable + Stream<SpeechSynthesisEvent> get onMark => markEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onpause') @DocsEditable Stream<Event> get onPause => pauseEvent.forTarget(this); + @DomName('SpeechSynthesisUtterance.onresume') + @DocsEditable + Stream<SpeechSynthesisEvent> get onResume => resumeEvent.forTarget(this); + + @DomName('SpeechSynthesisUtterance.onstart') + @DocsEditable + Stream<SpeechSynthesisEvent> get onStart => startEvent.forTarget(this); + } // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -22936,11 +22982,11 @@ @DomName('WheelEvent.wheelDeltaX') @DocsEditable - int get $dom_wheelDeltaX native "WheelEvent_wheelDeltaX_Getter"; + int get _wheelDeltaX native "WheelEvent_wheelDeltaX_Getter"; @DomName('WheelEvent.wheelDeltaY') @DocsEditable - int get $dom_wheelDeltaY native "WheelEvent_wheelDeltaY_Getter"; + int get _wheelDeltaY native "WheelEvent_wheelDeltaY_Getter"; @DomName('WheelEvent.initWebKitWheelEvent') @DocsEditable @@ -22956,7 +23002,7 @@ * * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C. */ @DomName('WheelEvent.deltaX') - num get deltaX => -$dom_wheelDeltaX; + num get deltaX => -_wheelDeltaX; /** * The amount that is expected to scroll vertically, in units determined by @@ -22967,7 +23013,7 @@ * * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C. */ @DomName('WheelEvent.deltaY') - num get deltaY => -$dom_wheelDeltaY; + num get deltaY => -_wheelDeltaY; } // 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 @@ -26243,16 +26289,16 @@ } } - bool get _paused => _pauseCount > 0; + bool get isPaused => _pauseCount > 0; void resume() { - if (_canceled || !_paused) return; + if (_canceled || !isPaused) return; --_pauseCount; _tryResume(); } void _tryResume() { - if (_onData != null && !_paused) { + if (_onData != null && !isPaused) { _target.$dom_addEventListener(_eventType, _onData, _useCapture); } } @@ -26376,7 +26422,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void remove(Object object) { + bool remove(Object object) { throw new UnsupportedError("Cannot remove from immutable List."); } @@ -26388,7 +26434,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) { + void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { throw new UnsupportedError("Cannot setRange on immutable List."); } @@ -28460,7 +28506,7 @@ } // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner - static Document _getTemplateContentsOwner(Document doc) { + static Document _getTemplateContentsOwner(HtmlDocument doc) { if (doc.window == null) { return doc; } @@ -28538,7 +28584,7 @@ // template. // TODO(jmesserly): node is DocumentFragment or Element var descendents = (node as dynamic).queryAll(_allTemplatesSelectors); - if (node is Element && node.isTemplate) bootstrap(node); + if (node is Element && (node as Element).isTemplate) bootstrap(node); descendents.forEach(bootstrap); } @@ -28692,7 +28738,7 @@ static void _removeChild(Node parent, Node child) { child._templateInstance = null; - if (child is Element && child.isTemplate) { + if (child is Element && (child as Element).isTemplate) { // Make sure we stop observing when we remove an element. var templateIterator = child._templateIterator; if (templateIterator != null) { @@ -28945,7 +28991,7 @@ void add(E element) { _list.add(element); } - void remove(Object element) { _list.remove(element); } + bool remove(Object element) => _list.remove(element); void clear() { _list.clear(); } @@ -29141,6 +29187,8 @@ /** True if the altGraphKey is pressed during this event. */ bool get altGraphKey => _parent.altGraphKey; + /** Accessor to the clipboardData available for this event. */ + DataTransfer get clipboardData => _parent.clipboardData; /** True if the ctrl key is pressed during this event. */ bool get ctrlKey => _parent.ctrlKey; int get detail => _parent.detail;
diff --git a/sdk/lib/io/base64.dart b/sdk/lib/io/base64.dart deleted file mode 100644 index 1469c8d..0000000 --- a/sdk/lib/io/base64.dart +++ /dev/null
@@ -1,106 +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. - -part of dart.io; - -class _Base64 { - static const List<String> _encodingTable = const [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/']; - - /** - * Base64 transfer encoding for MIME (RFC 2045) - */ - static String _encode(List<int> data) { - List<String> characters = new List<String>(); - int i; - for (i = 0; i + 3 <= data.length; i += 3) { - int value = 0; - value |= data[i + 2]; - value |= data[i + 1] << 8; - value |= data[i] << 16; - for (int j = 0; j < 4; j++) { - int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1); - characters.add(_encodingTable[index]); - } - } - // Remainders. - if (i + 2 == data.length) { - int value = 0; - value |= data[i + 1] << 8; - value |= data[i] << 16; - for (int j = 0; j < 3; j++) { - int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1); - characters.add(_encodingTable[index]); - } - characters.add("="); - } else if (i + 1 == data.length) { - int value = 0; - value |= data[i] << 16; - for (int j = 0; j < 2; j++) { - int index = (value >> ((3 - j) * 6)) & ((1 << 6) - 1); - characters.add(_encodingTable[index]); - } - characters.add("="); - characters.add("="); - } - StringBuffer output = new StringBuffer(); - for (i = 0; i < characters.length; i++) { - if (i > 0 && i % 76 == 0) { - output.write("\r\n"); - } - output.write(characters[i]); - } - return output.toString(); - } - - - /** - * Base64 transfer decoding for MIME (RFC 2045). - */ - static List<int> _decode(String data) { - List<int> result = new List<int>(); - int padCount = 0; - int charCount = 0; - int value = 0; - for (int i = 0; i < data.length; i++) { - int char = data.codeUnitAt(i); - if (65 <= char && char <= 90) { // "A" - "Z". - value = (value << 6) | char - 65; - charCount++; - } else if (97 <= char && char <= 122) { // "a" - "z". - value = (value << 6) | char - 97 + 26; - charCount++; - } else if (48 <= char && char <= 57) { // "0" - "9". - value = (value << 6) | char - 48 + 52; - charCount++; - } else if (char == 43) { // "+". - value = (value << 6) | 62; - charCount++; - } else if (char == 47) { // "/". - value = (value << 6) | 63; - charCount++; - } else if (char == 61) { // "=". - value = (value << 6); - charCount++; - padCount++; - } - if (charCount == 4) { - result.add((value & 0xFF0000) >> 16); - if (padCount < 2) { - result.add((value & 0xFF00) >> 8); - } - if (padCount == 0) { - result.add(value & 0xFF); - } - charCount = 0; - value = 0; - } - } - return result; - } -}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart index 20110af..eb3dcd7 100644 --- a/sdk/lib/io/file.dart +++ b/sdk/lib/io/file.dart
@@ -180,14 +180,19 @@ String fullPathSync(); /** - * Create a new independent [Stream](../dart_async/Stream.html) for the - * contents of this file. + * Create a new independent [Stream] for the contents of this file. + * + * If [start] is present, the file will be read from byte-offset [start]. + * Otherwise from the beginning (index 0). + * + * If [end] is present, only up to byte-index [end] will be read. Otherwise, + * until end of file. * * In order to make sure that system resources are freed, the stream * must be read to completion or the subscription on the stream must * be cancelled. */ - Stream<List<int>> openRead(); + Stream<List<int>> openRead([int start, int end]); /** * Creates a new independent [IOSink] for the file. The
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart index 15fbded..fb6b272 100644 --- a/sdk/lib/io/file_impl.dart +++ b/sdk/lib/io/file_impl.dart
@@ -16,6 +16,7 @@ String _path; RandomAccessFile _openedFile; int _position; + int _end; // Has the stream been paused or unsubscribed? bool _paused = false; @@ -27,7 +28,7 @@ // Block read but not yet send because stream is paused. List<int> _currentBlock; - _FileStream(String this._path) : _position = 0 { + _FileStream(String this._path, this._position, this._end) { _setupController(); } @@ -71,7 +72,19 @@ // Don't start a new read if one is already in progress. if (_readInProgress) return; _readInProgress = true; - _openedFile.read(_BLOCK_SIZE) + int readBytes = _BLOCK_SIZE; + if (_end != null) { + readBytes = min(readBytes, _end - _position); + if (readBytes < 0) { + if (!_unsubscribed) { + _controller.addError(new RangeError("Bad end position: $_end")); + _closeFile().then((_) { _controller.close(); }); + _unsubscribed = true; + } + return; + } + } + _openedFile.read(readBytes) .then((block) { _readInProgress = false; if (block.length == 0) { @@ -99,6 +112,13 @@ } void _start() { + if (_position == null) { + _position = 0; + } else if (_position < 0) { + _controller.addError(new RangeError("Bad start position: $_position")); + _controller.close(); + return; + } Future<RandomAccessFile> openFuture; if (_path != null) { openFuture = new File(_path).open(mode: FileMode.READ); @@ -108,8 +128,11 @@ openFuture .then((RandomAccessFile opened) { _openedFile = opened; - _readBlock(); + if (_position > 0) { + return opened.setPosition(_position); + } }) + .then((_) => _readBlock()) .catchError((e) { _controller.addError(e); _controller.close(); @@ -315,14 +338,10 @@ Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) { _ensureFileService(); - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); if (mode != FileMode.READ && mode != FileMode.WRITE && mode != FileMode.APPEND) { - Timer.run(() { - completer.completeError(new ArgumentError()); - }); - return completer.future; + return new Future.error(new ArgumentError()); } List request = new List(3); request[0] = _OPEN_REQUEST; @@ -430,8 +449,8 @@ return result; } - Stream<List<int>> openRead() { - return new _FileStream(_path); + Stream<List<int>> openRead([int start, int end]) { + return new _FileStream(_path, start, end); } IOSink openWrite({FileMode mode: FileMode.WRITE, @@ -500,7 +519,6 @@ Future<List<String>> readAsLines({Encoding encoding: Encoding.UTF_8}) { _ensureFileService(); - Completer<List<String>> completer = new Completer<List<String>>(); return readAsBytes().then((bytes) { return _decodeLines(bytes, encoding); }); @@ -534,9 +552,7 @@ try { return writeAsBytes(_encodeString(contents, encoding), mode: mode); } catch (e) { - var completer = new Completer(); - Timer.run(() => completer.completeError(e)); - return completer.future; + return new Future.error(e); } } @@ -572,8 +588,7 @@ _RandomAccessFile(int this._id, String this._path); Future<RandomAccessFile> close() { - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); _ensureFileService(); List request = new List(2); request[0] = _CLOSE_REQUEST; @@ -604,8 +619,7 @@ Future<int> readByte() { _ensureFileService(); - Completer<int> completer = new Completer<int>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(2); request[0] = _READ_BYTE_REQUEST; request[1] = _id; @@ -631,18 +645,11 @@ Future<List<int>> read(int bytes) { _ensureFileService(); - Completer<List<int>> completer = new Completer<List<int>>(); if (bytes is !int) { - // Complete asynchronously so the user has a chance to setup - // handlers without getting exceptions when registering the - // then handler. - Timer.run(() { - completer.completeError(new FileIOException( - "Invalid arguments to read for file '$_path'")); - }); - return completer.future; - }; - if (closed) return _completeWithClosedException(completer); + return new Future.error(new FileIOException( + "Invalid arguments to read for file '$_path'")); + } + if (closed) return _closedException(); List request = new List(3); request[0] = _READ_REQUEST; request[1] = _id; @@ -680,8 +687,7 @@ return new Future.error(new FileIOException( "Invalid arguments to readInto for file '$_path'")); }; - Completer<int> completer = new Completer<int>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(3); if (start == null) start = 0; if (end == null) end = buffer.length; @@ -732,18 +738,11 @@ Future<RandomAccessFile> writeByte(int value) { _ensureFileService(); - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); if (value is !int) { - // Complete asynchronously so the user has a chance to setup - // handlers without getting exceptions when registering the - // then handler. - Timer.run(() { - completer.completeError(new FileIOException( - "Invalid argument to writeByte for file '$_path'")); - }); - return completer.future; + return new Future.error(new FileIOException( + "Invalid argument to writeByte for file '$_path'")); } - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(3); request[0] = _WRITE_BYTE_REQUEST; request[1] = _id; @@ -781,9 +780,8 @@ return new Future.error(new FileIOException( "Invalid arguments to writeFrom for file '$_path'")); } - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); _BufferAndStart result; try { @@ -835,12 +833,8 @@ Future<RandomAccessFile> writeString(String string, {Encoding encoding: Encoding.UTF_8}) { if (encoding is! Encoding) { - var completer = new Completer(); - Timer.run(() { - completer.completeError(new FileIOException( - "Invalid encoding in writeString: $encoding")); - }); - return completer.future; + return new Future.error(new FileIOException( + "Invalid encoding in writeString: $encoding")); } var data = _encodeString(string, encoding); return writeFrom(data, 0, data.length); @@ -857,8 +851,7 @@ Future<int> position() { _ensureFileService(); - Completer<int> completer = new Completer<int>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(2); request[0] = _POSITION_REQUEST; request[1] = _id; @@ -884,8 +877,7 @@ Future<RandomAccessFile> setPosition(int position) { _ensureFileService(); - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(3); request[0] = _SET_POSITION_REQUEST; request[1] = _id; @@ -911,8 +903,7 @@ Future<RandomAccessFile> truncate(int length) { _ensureFileService(); - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(3); request[0] = _TRUNCATE_REQUEST; request[1] = _id; @@ -938,8 +929,7 @@ Future<int> length() { _ensureFileService(); - Completer<int> completer = new Completer<int>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(2); request[0] = _LENGTH_REQUEST; request[1] = _id; @@ -965,8 +955,7 @@ Future<RandomAccessFile> flush() { _ensureFileService(); - Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); - if (closed) return _completeWithClosedException(completer); + if (closed) return _closedException(); List request = new List(2); request[0] = _FLUSH_REQUEST; request[1] = _id; @@ -1005,12 +994,8 @@ } } - Future _completeWithClosedException(Completer completer) { - Timer.run(() { - completer.completeError( - new FileIOException("File closed '$_path'")); - }); - return completer.future; + Future _closedException() { + return new Future.error(new FileIOException("File closed '$_path'")); } final String _path;
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart index 47be232..5dc5738 100644 --- a/sdk/lib/io/http.dart +++ b/sdk/lib/io/http.dart
@@ -873,6 +873,12 @@ static const int DEFAULT_HTTP_PORT = 80; static const int DEFAULT_HTTPS_PORT = 443; + /** + * Get and set the idle timeout of non-active persistent (keep-alive) + * connections. The default value is 15 seconds. + */ + Duration idleTimeout; + factory HttpClient() => new _HttpClient(); /**
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart index 8153850..cabdfb0 100644 --- a/sdk/lib/io/http_headers.dart +++ b/sdk/lib/io/http_headers.dart
@@ -23,7 +23,7 @@ return values[0]; } - void add(String name, Object value) { + void add(String name, value) { _checkMutable(); if (value is List) { for (int i = 0; i < value.length; i++) {
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart index 73acb00..c749ceb 100644 --- a/sdk/lib/io/http_impl.dart +++ b/sdk/lib/io/http_impl.dart
@@ -47,9 +47,9 @@ // Is completed once all data have been received. Future get dataDone => _dataCompleter.future; - void close() { + void close(bool closing) { fullBodyRead = true; - _dataCompleter.complete(); + _dataCompleter.complete(closing); } } @@ -580,13 +580,12 @@ bool _done([error]) { if (_completer == null) return false; - var tmp = _completer; - _completer = null; if (error != null) { - tmp.completeError(error); + _completer.completeError(error); } else { - tmp.complete(_outbound); + _completer.complete(_outbound); } + _completer = null; return true; } @@ -1071,6 +1070,7 @@ StreamSubscription _subscription; final _HttpClient _httpClient; bool _dispose = false; + Timer _idleTimer; bool closed = false; Completer<_HttpIncoming> _nextResponseCompleter; @@ -1285,6 +1285,22 @@ return isSecure ? "ssh:$host:$port" : "$host:$port"; } + void stopTimer() { + if (_idleTimer != null) { + _idleTimer.cancel(); + _idleTimer = null; + } + } + + void startTimer() { + assert(_idleTimer == null); + _idleTimer = new Timer( + _httpClient.idleTimeout, + () { + _idleTimer = null; + close(); + }); + } } class _ConnnectionInfo { @@ -1296,7 +1312,6 @@ class _HttpClient implements HttpClient { // TODO(ajohnsen): Use eviction timeout. - static const int DEFAULT_EVICTION_TIMEOUT = 60000; bool _closing = false; final Map<String, Set<_HttpClientConnection>> _idleConnections @@ -1308,6 +1323,21 @@ Function _authenticate; Function _authenticateProxy; Function _findProxy = HttpClient.findProxyFromEnvironment; + Duration _idleTimeout = const Duration(seconds: 15); + + Timer _noActiveTimer; + + Duration get idleTimeout => _idleTimeout; + + void set idleTimeout(Duration timeout) { + _idleTimeout = timeout; + _idleConnections.values.forEach( + (l) => l.forEach((c) { + // Reset timer. This is fine, as it's not happening often. + c.stopTimer(); + c.startTimer(); + })); + } Future<HttpClientRequest> open(String method, String host, @@ -1485,15 +1515,17 @@ connection.close(); return; } - // TODO(ajohnsen): Listen for socket close events. if (!_idleConnections.containsKey(connection.key)) { _idleConnections[connection.key] = new LinkedHashSet(); } _idleConnections[connection.key].add(connection); + connection.startTimer(); + _updateTimers(); } // Remove a closed connnection from the active set. void _connectionClosed(_HttpClientConnection connection) { + connection.stopTimer(); _activeConnections.remove(connection); if (_idleConnections.containsKey(connection.key)) { _idleConnections[connection.key].remove(connection); @@ -1501,6 +1533,24 @@ _idleConnections.remove(connection.key); } } + _updateTimers(); + } + + void _updateTimers() { + if (_activeConnections.isEmpty) { + if (!_idleConnections.isEmpty && _noActiveTimer == null) { + _noActiveTimer = new Timer(const Duration(milliseconds: 100), () { + _noActiveTimer = null; + if (_activeConnections.isEmpty) { + close(); + _closing = false; + } + }); + } + } else if (_noActiveTimer != null) { + _noActiveTimer.cancel(); + _noActiveTimer = null; + } } // Get a new _HttpClientConnection, either from the idle pool or created from @@ -1523,7 +1573,9 @@ if (_idleConnections[key].isEmpty) { _idleConnections.remove(key); } + connection.stopTimer(); _activeConnections.add(connection); + _updateTimers(); return new Future.value(new _ConnnectionInfo(connection, proxy)); } return (isSecure && proxy.isDirect @@ -1668,6 +1720,10 @@ _socket.pipe(_httpParser); _subscription = _httpParser.listen( (incoming) { + // If the incoming was closed, close the connection. + incoming.dataDone.then((closing) { + if (closing) destroy(); + }); // Only handle one incoming request at the time. Keep the // stream paused until the request has been send. _subscription.pause();
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart index af937e9..58622cf 100644 --- a/sdk/lib/io/http_parser.dart +++ b/sdk/lib/io/http_parser.dart
@@ -105,8 +105,7 @@ Completer resumeCompleter; _HttpDetachedIncoming(StreamSubscription this.subscription, - List<int> this.carryOverData, - Completer oldResumeCompleter) { + List<int> this.carryOverData) { controller = new StreamController<List<int>>( onListen: resume, onPause: pause, @@ -118,7 +117,6 @@ controller.close(); } else { pause(); - if (oldResumeCompleter != null) oldResumeCompleter.complete(); subscription.resume(); subscription.onData(controller.add); subscription.onDone(controller.close); @@ -729,7 +727,7 @@ new HttpParserException( "Connection closed while receiving data")); } - _closeIncoming(); + _closeIncoming(true); _controller.close(); return; } @@ -792,11 +790,8 @@ void set responseToMethod(String method) { _responseToMethod = method; } _HttpDetachedIncoming detachIncoming() { - var completer = _pauseCompleter; - _pauseCompleter = null; return new _HttpDetachedIncoming(_socketSubscription, - readUnparsedData(), - completer); + readUnparsedData()); } List<int> readUnparsedData() { @@ -909,7 +904,7 @@ if (_socketSubscription != null) { _socketSubscription.cancel(); } - _closeIncoming(); + _closeIncoming(true); _controller.close(); }); incoming = _incoming = new _HttpIncoming( @@ -918,11 +913,11 @@ _pauseStateChanged(); } - void _closeIncoming() { + void _closeIncoming([bool closing = false]) { // Ignore multiple close (can happend in re-entrance). if (_incoming == null) return; var tmp = _incoming; - tmp.close(); + tmp.close(closing); _incoming = null; if (_bodyController != null) { _bodyController.close(); @@ -993,7 +988,6 @@ StreamSubscription _socketSubscription; bool _paused = true; bool _bodyPaused = false; - Completer _pauseCompleter; StreamController<_HttpIncoming> _controller; StreamController<List<int>> _bodyController; }
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart index fee6a12..c44f6ba 100644 --- a/sdk/lib/io/io.dart +++ b/sdk/lib/io/io.dart
@@ -25,7 +25,6 @@ import 'dart:utf'; import 'dart:typed_data'; -part 'base64.dart'; part 'buffer_list.dart'; part 'common.dart'; part 'data_transformer.dart';
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart index c6a82f0..8e8b71f 100644 --- a/sdk/lib/io/io_sink.dart +++ b/sdk/lib/io/io_sink.dart
@@ -116,13 +116,12 @@ void _completeDone({value, error}) { if (_doneCompleter == null) return; - var tmp = _doneCompleter; - _doneCompleter = null; if (error == null) { - tmp.complete(value); + _doneCompleter.complete(value); } else { - tmp.completeError(error); + _doneCompleter.completeError(error); } + _doneCompleter = null; } StreamController<T> get _controller { @@ -140,10 +139,9 @@ (_) { if (_isBound) { // A new stream takes over - forward values to that stream. - var completer = _controllerCompleter; + _controllerCompleter.complete(); _controllerCompleter = null; _controllerInstance = null; - completer.complete(); } else { // No new stream, .close was called. Close _target. _closeTarget(); @@ -152,10 +150,9 @@ onError: (error) { if (_isBound) { // A new stream takes over - forward errors to that stream. - var completer = _controllerCompleter; + _controllerCompleter.completeError(error); _controllerCompleter = null; _controllerInstance = null; - completer.completeError(error); } else { // No new stream. No need to close target, as it have already // failed.
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/iolib_sources.gypi index 2eab1d9..5225dc1 100644 --- a/sdk/lib/io/iolib_sources.gypi +++ b/sdk/lib/io/iolib_sources.gypi
@@ -4,7 +4,6 @@ { 'sources': [ - 'base64.dart', 'buffer_list.dart', 'common.dart', 'data_transformer.dart',
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart index c1a060a..6e9b1cd 100644 --- a/sdk/lib/io/process.dart +++ b/sdk/lib/io/process.dart
@@ -100,6 +100,57 @@ [ProcessOptions options]); /** + * Starts a process in the system shell and runs it non-interactively to + * completion. + * + * On Linux and Mac OS, [:/bin/sh:] is used to execute the [executable]. + * On Windows, [:%WINDIR%\system32\cmd.exe:] is used. + * + * An optional [ProcessOptions] object can be passed to specify + * options other than the executable and the arguments. + * + * Returns a [:Future<ProcessResult>:] that completes with the + * result of running the process, i.e., exit code, standard out and + * standard in. + */ + static Future<ProcessResult> runShell(String executable, + List<String> arguments, + [ProcessOptions options]) + => run(_getShellCommand(), + _getShellArguments(executable, arguments), + options); + + static String _getShellCommand() { + if (Platform.operatingSystem == 'windows') { + return 'cmd.exe'; + } + return '/bin/sh'; + } + + static List<String> _getShellArguments(String executable, + List<String> arguments) { + List<String> shellArguments = []; + if (Platform.operatingSystem == 'windows') { + shellArguments.add('/c'); + shellArguments.add(executable); + for (var arg in arguments) { + arg = arg.replaceAll('"', r'\"'); + shellArguments.add(arg); + } + } else { + var commandLine = new StringBuffer(); + commandLine.write(executable); + shellArguments.add("-c"); + for (var arg in arguments) { + arg = arg.replaceAll("'", "'\"'\"'"); + commandLine.write(" '$arg'"); + } + shellArguments.add(commandLine.toString()); + } + return shellArguments; + } + + /** * Returns the standard output stream of the process as a [:Stream:]. * * Throws an [UnsupportedError] if the process is
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart index 74df425..3cef0ad 100644 --- a/sdk/lib/io/websocket_impl.dart +++ b/sdk/lib/io/websocket_impl.dart
@@ -408,7 +408,7 @@ String key = request.headers.value("Sec-WebSocket-Key"); SHA1 sha1 = new SHA1(); sha1.add("$key$_webSocketGUID".codeUnits); - String accept = _Base64._encode(sha1.close()); + String accept = CryptoUtils.bytesToBase64(sha1.close()); response.headers.add("Sec-WebSocket-Accept", accept); response.headers.contentLength = 0; return response.detachSocket() @@ -585,13 +585,12 @@ bool _done([error]) { if (_completer == null) return false; - var tmp = _completer; - _completer = null; if (error != null) { - tmp.completeError(error); + _completer.completeError(error); } else { - tmp.complete(webSocket); + _completer.complete(webSocket); } + _completer = null; return true; } @@ -659,7 +658,7 @@ for (int i = 0; i < 16; i++) { nonceData[i] = random.nextInt(256); } - String nonce = _Base64._encode(nonceData); + String nonce = CryptoUtils.bytesToBase64(nonceData); uri = new Uri.fromComponents(scheme: uri.scheme == "wss" ? "https" : "http", userInfo: uri.userInfo, @@ -700,7 +699,7 @@ SHA1 sha1 = new SHA1(); sha1.add("$nonce$_webSocketGUID".codeUnits); List<int> expectedAccept = sha1.close(); - List<int> receivedAccept = _Base64._decode(accept); + List<int> receivedAccept = CryptoUtils.base64StringToBytes(accept); if (expectedAccept.length != receivedAccept.length) { error("Reasponse header 'Sec-WebSocket-Accept' is the wrong length"); }
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart index ae4f720..564670f 100644 --- a/sdk/lib/svg/dart2js/svg_dart2js.dart +++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -5365,7 +5365,7 @@ return _cssClassSet; } - List<Element> get children => new FilteredElementList(this); + List<Element> get children => new FilteredElementList<Element>(this); void set children(List<Element> value) { final children = this.children;
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart index bb2ad9b..d8d92c2 100644 --- a/sdk/lib/svg/dartium/svg_dartium.dart +++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -6110,7 +6110,7 @@ return _cssClassSet; } - List<Element> get children => new FilteredElementList(this); + List<Element> get children => new FilteredElementList<Element>(this); void set children(List<Element> value) { final children = this.children;
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status index 814b54d..2a350af 100644 --- a/tests/co19/co19-analyzer.status +++ b/tests/co19/co19-analyzer.status
@@ -3,16 +3,7 @@ # BSD-style license that can be found in the LICENSE file. [ $compiler == dartanalyzer ] -Language/03_Overview/1_Scoping_A01_t46: fail -Language/03_Overview/1_Scoping_A02_t07: fail -Language/03_Overview/1_Scoping_A02_t11: fail -Language/03_Overview/1_Scoping_A02_t12: fail -Language/03_Overview/1_Scoping_A02_t16: fail -Language/03_Overview/1_Scoping_A02_t28: fail -Language/05_Variables/05_Variables_A01_t09: fail -Language/05_Variables/05_Variables_A01_t11: fail Language/05_Variables/05_Variables_A05_t04: fail -Language/06_Functions/06_Functions_A01_t10: fail Language/06_Functions/06_Functions_A01_t31: fail Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t06: fail Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t07: fail @@ -20,11 +11,7 @@ Language/06_Functions/2_Formal_Parameters_A01_t02: fail Language/06_Functions/2_Formal_Parameters_A01_t09: fail Language/06_Functions/2_Formal_Parameters_A02_t02: fail -Language/07_Classes/07_Classes_A02_t02: fail -Language/07_Classes/07_Classes_A02_t04: fail -Language/07_Classes/07_Classes_A03_t02: fail -Language/07_Classes/07_Classes_A03_t07: fail -Language/07_Classes/07_Classes_A03_t08: fail +Language/07_Classes/07_Classes_A01_t20: fail Language/07_Classes/07_Classes_A09_t01: fail Language/07_Classes/07_Classes_A09_t02: fail Language/07_Classes/07_Classes_A09_t03: fail @@ -37,19 +24,15 @@ Language/07_Classes/3_Setters_A03_t04: fail Language/07_Classes/3_Setters_A03_t06: fail Language/07_Classes/3_Setters_A03_t08: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t04: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t06: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t11: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t04: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t06: fail -Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t07: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t09: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t01: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t04: fail Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t07: fail -Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t02: fail +Language/07_Classes/6_Constructors/2_Factories_A06_t01: fail +Language/07_Classes/6_Constructors/2_Factories_A06_t02: fail +Language/07_Classes/6_Constructors/2_Factories_A06_t04: fail Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t01: fail Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: fail Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: fail @@ -60,6 +43,7 @@ Language/08_Interfaces/5_Superinterfaces_A01_t03: fail Language/08_Interfaces/5_Superinterfaces_A01_t04: fail Language/08_Interfaces/5_Superinterfaces_A04_t03: fail +Language/09_Generics/09_Generics_A04_t07: fail Language/11_Expressions/01_Constants_A01_t01: fail Language/11_Expressions/01_Constants_A08_t02: fail Language/11_Expressions/01_Constants_A09_t02: fail @@ -78,20 +62,12 @@ Language/11_Expressions/03_Numbers_A01_t04: fail Language/11_Expressions/03_Numbers_A01_t08: fail Language/11_Expressions/03_Numbers_A01_t10: fail -Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t03: fail -Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t09: fail -Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t11: fail -Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t14: fail -Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t15: fail -Language/11_Expressions/05_Strings_A02_t34: fail -Language/11_Expressions/05_Strings_A02_t36: fail -Language/11_Expressions/05_Strings_A02_t42: fail -Language/11_Expressions/05_Strings_A02_t44: fail +Language/11_Expressions/05_Strings/1_String_Interpolation_A03_t01: fail +Language/11_Expressions/05_Strings/1_String_Interpolation_A04_t01: fail Language/11_Expressions/05_Strings_A02_t46: fail Language/11_Expressions/05_Strings_A02_t48: fail -Language/11_Expressions/06_Lists_A01_t03: fail -Language/11_Expressions/06_Lists_A01_t04: fail Language/11_Expressions/06_Lists_A03_t01: fail +Language/11_Expressions/06_Lists_A06_t01: fail Language/11_Expressions/07_Maps_A02_t02: fail Language/11_Expressions/08_Throw_A06_t01: fail Language/11_Expressions/08_Throw_A06_t02: fail @@ -99,110 +75,41 @@ Language/11_Expressions/08_Throw_A06_t04: fail Language/11_Expressions/08_Throw_A06_t05: fail Language/11_Expressions/08_Throw_A06_t06: fail -Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail +Language/11_Expressions/11_Instance_Creation/1_New_A13_t02: fail Language/11_Expressions/11_Instance_Creation/2_Const_A06_t01: fail Language/11_Expressions/11_Instance_Creation/2_Const_A06_t02: fail Language/11_Expressions/11_Instance_Creation/2_Const_A10_t01: fail Language/11_Expressions/11_Instance_Creation_A05_t02: fail -Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A01_t05: fail +Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A02_t01: fail Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A04_t01: fail -Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail -Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A01_t05: fail -Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A01_t05: fail -Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A01_t05: fail -Language/11_Expressions/19_Conditional_A01_t05: fail -Language/11_Expressions/19_Conditional_A01_t06: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t04: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t05: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t06: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t07: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t08: fail -Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t09: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t03: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t04: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t05: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t06: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t07: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t08: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t09: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t10: fail -Language/11_Expressions/21_Bitwise_Expressions_A01_t11: fail -Language/11_Expressions/22_Equality_A01_t03: fail -Language/11_Expressions/22_Equality_A01_t04: fail -Language/11_Expressions/22_Equality_A01_t07: fail -Language/11_Expressions/22_Equality_A01_t08: fail -Language/11_Expressions/22_Equality_A01_t11: fail -Language/11_Expressions/22_Equality_A01_t12: fail +Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t05: fail +Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A02_t01: fail +Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail +Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A04_t01: fail +Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A08_t01: fail +Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail +Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail +Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: fail +Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A06_t02: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t01: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t02: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t03: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t04: fail +Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A08_t02: fail Language/11_Expressions/22_Equality_A01_t15: fail Language/11_Expressions/22_Equality_A01_t16: fail -Language/11_Expressions/23_Relational_Expressions_A01_t03: fail -Language/11_Expressions/23_Relational_Expressions_A01_t04: fail -Language/11_Expressions/23_Relational_Expressions_A01_t05: fail -Language/11_Expressions/23_Relational_Expressions_A01_t06: fail -Language/11_Expressions/23_Relational_Expressions_A01_t07: fail -Language/11_Expressions/23_Relational_Expressions_A01_t08: fail -Language/11_Expressions/23_Relational_Expressions_A01_t09: fail -Language/11_Expressions/24_Shift_A01_t02: fail -Language/11_Expressions/24_Shift_A01_t03: fail -Language/11_Expressions/24_Shift_A01_t04: fail -Language/11_Expressions/24_Shift_A01_t05: fail -Language/11_Expressions/24_Shift_A01_t06: fail -Language/11_Expressions/24_Shift_A01_t07: fail -Language/11_Expressions/25_Additive_Expressions_A01_t02: fail -Language/11_Expressions/25_Additive_Expressions_A01_t03: fail -Language/11_Expressions/25_Additive_Expressions_A01_t06: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t02: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t03: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t04: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t05: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t06: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t07: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t08: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t18: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t19: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t20: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t21: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t22: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t23: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t24: fail -Language/11_Expressions/26_Multiplicative_Expressions_A01_t25: fail -Language/11_Expressions/27_Unary_Expressions_A01_t08: fail Language/11_Expressions/28_Postfix_Expressions_A01_t06: fail -Language/11_Expressions/28_Postfix_Expressions_A01_t09: fail -Language/11_Expressions/28_Postfix_Expressions_A01_t10: fail -Language/11_Expressions/28_Postfix_Expressions_A01_t11: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t10: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t11: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t12: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t13: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t15: fail -Language/11_Expressions/29_Assignable_Expressions_A01_t16: fail Language/11_Expressions/30_Identifier_Reference_A01_t07: fail Language/11_Expressions/30_Identifier_Reference_A01_t08: fail -Language/11_Expressions/31_Type_Test_A05_t01: fail -Language/11_Expressions/31_Type_Test_A05_t02: fail -Language/11_Expressions/31_Type_Test_A05_t03: fail -Language/11_Expressions/32_Type_Cast_A04_t01: fail -Language/11_Expressions/32_Type_Cast_A04_t02: fail Language/11_Expressions/33_Argument_Definition_Test_A01_t14: fail Language/11_Expressions/33_Argument_Definition_Test_A01_t18: fail Language/12_Statements/02_Expression_Statements_A01_t06: fail -Language/12_Statements/02_Expression_Statements_A01_t12: fail -Language/12_Statements/04_Local_Function_Declaration_A01_t01: fail -Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail -Language/12_Statements/05_If_A01_t01: fail -Language/12_Statements/06_For_A01_t10: fail -Language/12_Statements/07_While_A01_t04: fail -Language/12_Statements/08_Do_A01_t07: fail -Language/12_Statements/09_Switch_A01_t06: fail Language/12_Statements/09_Switch_A04_t01: fail -Language/12_Statements/15_Assert_A01_t03: fail Language/13_Libraries_and_Scripts/13_Libraries_and_Scripts_A03_t17: fail Language/13_Libraries_and_Scripts/1_Imports_A01_t46: fail -Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail -Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail Language/13_Libraries_and_Scripts/1_Imports_A04_t03: fail -Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail # co19 issue 411 +Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail Language/13_Libraries_and_Scripts/2_Exports_A05_t01: fail Language/13_Libraries_and_Scripts/5_URIs_A01_t24: fail Language/13_Libraries_and_Scripts/5_URIs_A01_t25: fail @@ -210,15 +117,82 @@ Language/14_Types/3_Type_Declarations/1_Typedef_A07_t02: fail Language/14_Types/3_Type_Declarations/1_Typedef_A07_t03: fail Language/14_Types/3_Type_Declarations/1_Typedef_A07_t04: fail +Language/14_Types/4_Interface_Types_A10_t03: fail +Language/14_Types/4_Interface_Types_A10_t04: fail +Language/14_Types/4_Interface_Types_A10_t09: fail Language/15_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: fail +Language/15_Reference/1_Lexical_Rules_A01_t10: fail Language/15_Reference/1_Lexical_Rules_A02_t06: fail +LibTest/core/AssertionError/column_A01_t02: fail +LibTest/core/AssertionError/failedAssertion_A01_t01: fail +LibTest/core/AssertionError/line_A01_t02: fail +LibTest/core/AssertionError/url_A01_t01: fail +LibTest/core/Iterable/where_A01_t07: fail +LibTest/core/List/List.fixedLength_A01_t01: fail +LibTest/core/List/List_A01_t02: fail +LibTest/core/List/addLast_A01_t01: fail +LibTest/core/List/addLast_A01_t03: fail +LibTest/core/List/addLast_A02_t01: fail +LibTest/core/List/every_A01_t01: fail +LibTest/core/List/insertRange_A01_t01: fail +LibTest/core/List/insertRange_A02_t01: fail +LibTest/core/List/insertRange_A03_t01: fail +LibTest/core/List/insertRange_A04_t01: fail +LibTest/core/List/insertRange_A05_t01: fail +LibTest/core/List/insertRange_A06_t01: fail +LibTest/core/List/insertRange_A07_t01: fail +LibTest/core/List/insertRange_A08_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t02: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A04_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A06_t02: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A07_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A08_t01: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A08_t02: fail +LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A09_t01: fail +LibTest/core/Set/isSubsetOf_A01_t01: fail +LibTest/core/Set/isSubsetOf_A01_t02: fail +LibTest/core/String/String_class_A01_t01: fail +LibTest/core/String/charCodeAt_A01_t01: fail +LibTest/core/String/charCodeAt_A02_t01: fail +LibTest/core/String/charCodeAt_A03_t01: fail +LibTest/core/String/charCodes_A01_t01: fail +LibTest/core/String/concat_A01_t01: fail +LibTest/core/String/concat_A02_t01: fail +LibTest/core/String/hashCode_A01_t01: fail +LibTest/core/String/splitChars_A01_t01: fail +LibTest/core/StringBuffer/addAll_A01_t01: fail +LibTest/core/StringBuffer/addAll_A01_t02: fail +LibTest/core/StringBuffer/addAll_A03_t01: fail +LibTest/core/StringBuffer/add_A01_t01: fail +LibTest/core/StringBuffer/add_A01_t02: fail +LibTest/core/StringBuffer/isEmpty_A01_t01: fail +LibTest/core/StringBuffer/toString_A01_t01: fail LibTest/core/double/ceil_A01_t05: fail LibTest/core/double/floor_A01_t05: fail +LibTest/core/int/operator_division_A01_t01: fail + +# fails locally, passes on bot +Language/13_Libraries_and_Scripts/3_Parts_A02_t03: skip # co19 issue #412, using 'null' as operand -Language/11_Expressions/01_Constants_A11_t01: fail -Language/11_Expressions/01_Constants_A12_t01: fail -Language/11_Expressions/01_Constants_A13_t06: fail +Language/11_Expressions/01_Constants_A11_t01: fail, OK +Language/11_Expressions/01_Constants_A12_t01: fail, OK +Language/11_Expressions/01_Constants_A13_t06: fail, OK + +# co19 issue #414, extra @compile-error +Language/03_Overview/1_Scoping_A02_t28: fail, OK + +# co19 issue #416, function name is declared the parameter scope +Language/03_Overview/1_Scoping_A02_t07: fail, OK +Language/12_Statements/04_Local_Function_Declaration_A01_t01: fail, OK + +# co19 issue $417, 'if', 'while' and 'do-while' don't create scope +Language/03_Overview/1_Scoping_A02_t11: fail, OK +Language/03_Overview/1_Scoping_A02_t12: fail, OK +Language/03_Overview/1_Scoping_A02_t16: fail, OK + [ $runtime == drt && $compiler == none ]
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status index 861ba7a..ecc143f 100644 --- a/tests/co19/co19-dart2js.status +++ b/tests/co19/co19-dart2js.status
@@ -230,10 +230,6 @@ [ $compiler == dart2js && $checked ] Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t03: Fail # TODO(ahe): Please triage this failure. Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t04: Fail # TODO(ahe): Please triage this failure. -Language/07_Classes/6_Constructors/2_Factories_A06_t01: Fail # TODO(ahe): Please triage this failure. -Language/07_Classes/6_Constructors/2_Factories_A06_t02: Fail # TODO(ahe): Please triage this failure. -Language/07_Classes/6_Constructors/2_Factories_A06_t03: Fail # TODO(ahe): Please triage this failure. -Language/07_Classes/6_Constructors/2_Factories_A06_t04: Fail # TODO(ahe): Please triage this failure. Language/09_Generics/09_Generics_A03_t01: Fail # TODO(ahe): Please triage this failure. Language/09_Generics/09_Generics_A04_t06: Fail # TODO(ahe): Please triage this failure. Language/11_Expressions/03_Numbers_A05_t02: Fail # TODO(ahe): Please triage this failure.
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart index 93ae53c..1cc88e4 100644 --- a/tests/compiler/dart2js/analyze_api_test.dart +++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -27,8 +27,13 @@ // TODO(johnniwinther): Support canonical URIs as keys and message kinds as // values. const Map<String,List<String>> WHITE_LIST = const { - 'html_dart2js.dart': const ['Warning: Using "new Symbol"', // Issue 10565. - 'Warning: unreachable code'], // Issue 10617. + 'html_dart2js.dart': + const ['Warning: Using "new Symbol"', // Issue 10565. + 'Warning: unreachable code', // Issue 10617. + // Issue 10688: + 'Warning: no property named', + "Warning: 'UnsupportedError' is not callable", + "Warning: no operator [] in class Iterable"], }; class CollectingDiagnosticHandler extends FormattingDiagnosticHandler {
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart index 28d2995..8ff09c7 100644 --- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart +++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -222,7 +222,7 @@ int index = 0; signature.forEachParameter((Element element) { Expect.equals(expectedTypes[index++], - inferrer.internal.typeOf[element]); + inferrer.internal.typeOf[element].simplify(inferrer.compiler)); }); Expect.equals(index, expectedTypes.length); }); @@ -245,14 +245,14 @@ runTest(TEST_5, (inferrer) => [inferrer.numType]); runTest(TEST_6, (inferrer) => [inferrer.numType]); runTest(TEST_7a, (inferrer) => [subclassOfInterceptor(inferrer)]); - runTest(TEST_7b, (inferrer) => [inferrer.dynamicType]); + runTest(TEST_7b, (inferrer) => [inferrer.dynamicType.nonNullable()]); // In the following tests, we can't infer the right types because we // have recursive calls with the same parameters. We should build a // constraint system for those, to find the types. runTest(TEST_8, (inferrer) => [inferrer.dynamicType, subclassOfInterceptor(inferrer), - inferrer.dynamicType]); + inferrer.dynamicType.nonNullable()]); runTest(TEST_9, (inferrer) => [inferrer.dynamicType, inferrer.dynamicType]); runTest(TEST_10, (inferrer) => [inferrer.dynamicType, inferrer.dynamicType]); runTest(TEST_11, (inferrer) => [subclassOfInterceptor(inferrer),
diff --git a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart index 2081157..5a77227 100644 --- a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart +++ b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
@@ -84,8 +84,9 @@ HTypeList types = compiler.backend.optimisticParameterTypes(x, null); if (expectedTypes != null) { Expect.isFalse(types.allUnknown); - Expect.listEquals(expectedTypes.map((f) => f(compiler)).toList(), - types.types); + Expect.listEquals( + expectedTypes.map((f) => f(compiler)).toList(), + types.types.map((e) => e.simplify(compiler)).toList()); } else { Expect.isTrue(types.allUnknown); }
diff --git a/tests/compiler/dart2js/call_site_type_inferer_test.dart b/tests/compiler/dart2js/call_site_type_inferer_test.dart index 4a04eff..bad589f 100644 --- a/tests/compiler/dart2js/call_site_type_inferer_test.dart +++ b/tests/compiler/dart2js/call_site_type_inferer_test.dart
@@ -228,7 +228,8 @@ .toList(); Expect.isFalse(types.allUnknown); Expect.equals(expectedTypes.length, types.types.length); - Expect.listEquals(expectedTypes, types.types); + Expect.listEquals(expectedTypes, + types.types.map((t) => t.simplify(compiler)).toList()); } else { Expect.isTrue(types.allUnknown); }
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart index 619f3bf..334d825 100644 --- a/tests/compiler/dart2js/cpa_inference_test.dart +++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -1255,8 +1255,9 @@ Expect.equals(convert(singleton(a).union(singleton(b)).union(nullSingleton)), new TypeMask.subclass(a.rawType)); - Expect.equals(convert(singleton(b).union(singleton(d))), - new TypeMask.nonNullSubtype(a.rawType)); + Expect.equals( + convert(singleton(b).union(singleton(d))).simplify(result.compiler), + new TypeMask.nonNullSubtype(a.rawType)); } testSelectors() { @@ -1302,7 +1303,7 @@ Selector foo = new Selector.call(buildSourceString("foo"), null, 0); Expect.equals( - inferredType(foo), + inferredType(foo).simplify(result.compiler), new TypeMask.nonNullSubclass(abc.rawType)); Expect.equals( inferredType(new TypedSelector.subclass(x.rawType, foo)), @@ -1314,7 +1315,8 @@ inferredType(new TypedSelector.subclass(z.rawType, foo)), new TypeMask.nonNullExact(a.rawType)); Expect.equals( - inferredType(new TypedSelector.subclass(xy.rawType, foo)), + inferredType(new TypedSelector.subclass( + xy.rawType, foo)).simplify(result.compiler), new TypeMask.nonNullSubclass(bc.rawType)); Selector bar = new Selector.call(buildSourceString("bar"), null, 0);
diff --git a/tests/compiler/dart2js/field_type_inferer_test.dart b/tests/compiler/dart2js/field_type_inferer_test.dart index 901b06e..59db184 100644 --- a/tests/compiler/dart2js/field_type_inferer_test.dart +++ b/tests/compiler/dart2js/field_type_inferer_test.dart
@@ -344,7 +344,8 @@ name, disableInlining, (backend, field) { - HType inferredType = backend.optimisticFieldType(field); + HType inferredType = + backend.optimisticFieldType(field).simplify(backend.compiler); if (type is Function) type = type(backend.compiler); Expect.equals(type, inferredType); });
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart index 5a2f27b..7422b80 100644 --- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart +++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -450,7 +450,8 @@ disableInlining, (inferrer, field) { TypeMask type = f(inferrer); - TypeMask inferredType = inferrer.internal.typeOf[field]; + TypeMask inferredType = + inferrer.internal.typeOf[field].simplify(inferrer.compiler); Expect.equals(type, inferredType, name); }); }); @@ -478,11 +479,10 @@ // code at the declaration site of the fields does not matter. runTest(TEST_5, {'f1': subclassOfInterceptor, 'f2': subclassOfInterceptor}); - // TODO(9415). These tests seem flaky. - //runTest(TEST_6, {'f1': subclassOfInterceptor, - // 'f2': subclassOfInterceptor}); - //runTest(TEST_7, {'f1': subclassOfInterceptor, - // 'f2': subclassOfInterceptor}); + runTest(TEST_6, {'f1': subclassOfInterceptor, + 'f2': subclassOfInterceptor}); + runTest(TEST_7, {'f1': subclassOfInterceptor, + 'f2': subclassOfInterceptor}); runTest(TEST_8, {'f': (inferrer) => inferrer.stringType.nullable()}); runTest(TEST_9, {'f': (inferrer) => inferrer.stringType.nullable()});
diff --git a/tests/compiler/dart2js/generate_at_use_site_test.dart b/tests/compiler/dart2js/generate_at_use_site_test.dart index d0955cb..8204f6a 100644 --- a/tests/compiler/dart2js/generate_at_use_site_test.dart +++ b/tests/compiler/dart2js/generate_at_use_site_test.dart
@@ -22,8 +22,23 @@ } """; +const String BAR = r""" +bar() { + var isLeaf = (bar() != null) && bar(); + // Because we're using a local variable, the graph gets an empty + // block between the [isLeaf] phi and the next instruction that uses + // it. The optimizer must take that new block into account in order + // to have the phi be generate at use uste. + if (isLeaf) return null; + return true; +} +"""; + main() { // Make sure we don't introduce a new variable. RegExp regexp = new RegExp("var $anyIdentifier ="); compileAndDoNotMatch(FIB, 'fib', regexp); + + regexp = new RegExp("isLeaf"); + compileAndDoNotMatch(BAR, 'bar', regexp); }
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart index 8e95867..9129573 100644 --- a/tests/compiler/dart2js/mock_compiler.dart +++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -173,6 +173,7 @@ class _WorkerBase {}'''; class MockCompiler extends Compiler { + api.DiagnosticHandler diagnosticHandler; List<WarningMessage> warnings; List<WarningMessage> errors; final Map<String, SourceFile> sourceFiles; @@ -256,6 +257,8 @@ void reportWarning(Node node, var message) { if (message is! Message) message = message.message; warnings.add(new WarningMessage(node, message)); + reportDiagnostic(spanFromNode(node), + 'Warning: $message', api.Diagnostic.WARNING); } void reportError(Node node, var message) { @@ -265,6 +268,8 @@ } if (message is! Message) message = message.message; errors.add(new WarningMessage(node, message)); + reportDiagnostic(spanFromNode(node), + 'Error: $message', api.Diagnostic.ERROR); } void reportMessage(SourceSpan span, var message, api.Diagnostic kind) { @@ -274,10 +279,17 @@ } else { warnings.add(diagnostic); } + reportDiagnostic(span, "$message", kind); } - void reportDiagnostic(SourceSpan span, String message, var kind) { - print(message); + void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind) { + if (diagnosticHandler != null) { + if (span != null) { + diagnosticHandler(span.uri, span.begin, span.end, message, kind); + } else { + diagnosticHandler(null, null, null, message, kind); + } + } } bool get compilationFailed => !errors.isEmpty; @@ -319,7 +331,7 @@ parseScript(String text, [LibraryElement library]) { if (library == null) library = mainApp; - parseUnit(text, this, library); + parseUnit(text, this, library, registerSource); } void scanBuiltinLibraries() {
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart index ec96f0e..3ba38e9 100644 --- a/tests/compiler/dart2js/parser_helper.dart +++ b/tests/compiler/dart2js/parser_helper.dart
@@ -78,10 +78,17 @@ : super('<string>', text); } +var sourceCounter = 0; + Link<Element> parseUnit(String text, Compiler compiler, - LibraryElement library) { + LibraryElement library, + [void registerSource(Uri uri, String source)]) { Token tokens = scan(text); - Uri uri = new Uri.fromComponents(scheme: "source"); + Uri uri = + new Uri.fromComponents(scheme: "source", path: '${++sourceCounter}'); + if (registerSource != null) { + registerSource(uri, text); + } var script = new Script(uri, new MockFile(text)); var unit = new CompilationUnitElementX(script, library); int id = 0;
diff --git a/tests/compiler/dart2js/return_type_inferer_test.dart b/tests/compiler/dart2js/return_type_inferer_test.dart index 7f50c98..30b854d 100644 --- a/tests/compiler/dart2js/return_type_inferer_test.dart +++ b/tests/compiler/dart2js/return_type_inferer_test.dart
@@ -72,7 +72,7 @@ var backend = compiler.backend; HType type = backend.optimisticReturnTypesWithRecompilationOnTypeChange(null, x); - Expect.equals(findExpectedType(compiler), type); + Expect.equals(findExpectedType(compiler), type.simplify(compiler)); }); }
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart index 14ef2d3..40c01a5 100644 --- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -62,7 +62,8 @@ checkReturn(String name, type) { var element = findElement(compiler, name); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element]); + Expect.equals(type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler)); } var subclassOfInterceptor = @@ -71,7 +72,7 @@ checkReturn('returnDyn1', subclassOfInterceptor); checkReturn('returnDyn2', subclassOfInterceptor); checkReturn('returnDyn3', subclassOfInterceptor); - checkReturn('returnDyn4', typesInferrer.dynamicType); - checkReturn('returnDyn5', typesInferrer.dynamicType); - checkReturn('returnDyn6', typesInferrer.dynamicType); + checkReturn('returnDyn4', typesInferrer.dynamicType.nonNullable()); + checkReturn('returnDyn5', typesInferrer.dynamicType.nonNullable()); + checkReturn('returnDyn6', typesInferrer.dynamicType.nonNullable()); }
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart index cf1b4aa..b43693e 100644 --- a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
@@ -31,7 +31,8 @@ checkFieldTypeInClass(String className, String fieldName, type) { var cls = findElement(compiler, className); var element = cls.lookupLocalMember(buildSourceString(fieldName)); - Expect.equals(type, typesInferrer.internal.typeOf[element]); + Expect.equals(type, + typesInferrer.internal.typeOf[element].simplify(compiler)); } checkFieldTypeInClass('A', 'dynamicField',
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart index 2e24c53..2e3cc4c 100644 --- a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
@@ -34,12 +34,14 @@ checkFieldTypeInClass(String className, String fieldName, type) { var cls = findElement(compiler, className); var element = cls.lookupLocalMember(buildSourceString(fieldName)); - Expect.equals(type, typesInferrer.internal.typeOf[element]); + Expect.equals(type, + typesInferrer.internal.typeOf[element].simplify(compiler)); } checkFieldTypeInClass('A', 'intField', typesInferrer.intType); checkFieldTypeInClass('A', 'giveUpField1', findTypeMask(compiler, 'Interceptor', 'nonNullSubclass')); - checkFieldTypeInClass('A', 'giveUpField2', typesInferrer.dynamicType); + checkFieldTypeInClass('A', 'giveUpField2', + typesInferrer.dynamicType.nonNullable()); checkFieldTypeInClass('A', 'fieldParameter', typesInferrer.intType); }
diff --git a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart index 5297520..91fb20d 100644 --- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -71,7 +71,7 @@ test8() => new C().bar(); test9() => (a ? new B() : new C()).bar(); -// Can hit A.noSuchMethod, D.noSuchMethod and Object.noSuchMethod. +// Can hit A.noSuchMethod and D.noSuchMethod. test10() => (a ? new B() : new D()).bar(); // Can hit D.noSuchMethod. @@ -101,15 +101,18 @@ checkReturn(String name, type) { var element = findElement(compiler, name); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element], name); + Expect.equals( + type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler), + name); } checkReturn('test1', typesInferrer.intType); checkReturn('test2', typesInferrer.dynamicType); checkReturn('test3', typesInferrer.intType); checkReturn('test4', typesInferrer.mapType); - checkReturn('test5', typesInferrer.dynamicType); - checkReturn('test6', typesInferrer.dynamicType); + checkReturn('test5', typesInferrer.dynamicType.nonNullable()); + checkReturn('test6', typesInferrer.dynamicType.nonNullable()); compiler = compilerFor(TEST2, uri); compiler.runCompiler(uri); @@ -129,6 +132,6 @@ checkReturn('test7', typesInferrer.intType); checkReturn('test8', typesInferrer.intType); checkReturn('test9', typesInferrer.intType); - checkReturn('test10', typesInferrer.numType.nullable()); + checkReturn('test10', typesInferrer.numType); checkReturn('test11', typesInferrer.doubleType); }
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart index a879e29..3c9aaa1 100644 --- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -69,7 +69,8 @@ checkReturnInClass(String className, String methodName, type) { var cls = findElement(compiler, className); var element = cls.lookupLocalMember(buildSourceString(methodName)); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element]); + Expect.equals(type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler)); } var subclassOfInterceptor =
diff --git a/tests/compiler/dart2js/simple_inferrer_relations_test.dart b/tests/compiler/dart2js/simple_inferrer_relations_test.dart index 1488c10..4b3af4a 100644 --- a/tests/compiler/dart2js/simple_inferrer_relations_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_relations_test.dart
@@ -52,7 +52,7 @@ void main() { String generated = compileAll(TEST); - if (!generated.contains(r'if ($.$eq(c, d))')) { + if (generated.contains(r'=== true')) { print(generated); Expect.fail("missing elision of '=== true'"); }
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart index 485896c..cc15222 100644 --- a/tests/compiler/dart2js/simple_inferrer_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -236,6 +236,24 @@ return topLevelGetter() as Foo; } +testDeadCode() { + return 42; + return 'foo'; +} + +testLabeledIf(a) { + var c; + L1: if (a > 1) { + if (a == 2) { + break L1; + } + c = 42; + } else { + c = 38; + } + return c; +} + testSwitch1() { var a = null; switch (topLevelGetter) { @@ -266,8 +284,57 @@ return b; } +testContinue1() { + var a = 42; + var b; + while (true) { + b = a + 54; + if (b == 42) continue; + a = 'foo'; + } + return b; +} + +testBreak1() { + var a = 42; + var b; + while (true) { + b = a + 54; + if (b == 42) break; + b = 'foo'; + } + return b; +} + +testContinue2() { + var a = 42; + var b; + while (true) { + b = a + 54; + if (b == 42) { + b = 'foo'; + continue; + } + } + return b; +} + +testBreak2() { + var a = 42; + var b; + while (true) { + b = a + 54; + if (b == 42) { + a = 'foo'; + break; + } + } + return b; +} + get topLevelGetter => 42; returnDynamic() => topLevelGetter(42); +returnTopLevelGetter() => topLevelGetter; class A { factory A() = A.generative; @@ -296,6 +363,7 @@ returnInt6() => super.myField += 4; returnInt7() => ++super[0]; returnInt8() => super[0] += 54; + returnInt9() => super.myField; } main() { @@ -337,9 +405,16 @@ returnAsString(); returnIntAsNum(); returnAsTypedef(); + returnTopLevelGetter(); + testDeadCode(); + testLabeledIf(); testSwitch1(); testSwitch2(); testSwitch3(); + testContinue1(); + testBreak1(); + testContinue2(); + testBreak2(); new A() == null; new A()..returnInt1() ..returnInt2() @@ -355,7 +430,8 @@ ..returnInt5() ..returnInt6() ..returnInt7() - ..returnInt8(); + ..returnInt8() + ..returnInt9(); } """; @@ -367,7 +443,10 @@ checkReturn(String name, type) { var element = findElement(compiler, name); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element], name); + Expect.equals( + type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler), + name); } var interceptorType = findTypeMask(compiler, 'Interceptor', 'nonNullSubclass'); @@ -412,15 +491,23 @@ new TypeMask.subtype(compiler.stringClass.computeType(compiler))); checkReturn('returnIntAsNum', typesInferrer.intType); checkReturn('returnAsTypedef', typesInferrer.functionType.nullable()); - checkReturn('testSwitch1', - typesInferrer.intType.union(typesInferrer.doubleType, compiler).nullable()); + checkReturn('returnTopLevelGetter', typesInferrer.intType); + checkReturn('testDeadCode', typesInferrer.intType); + checkReturn('testLabeledIf', typesInferrer.intType.nullable()); + checkReturn('testSwitch1', typesInferrer.intType + .union(typesInferrer.doubleType, compiler).nullable().simplify(compiler)); checkReturn('testSwitch2', typesInferrer.intType); checkReturn('testSwitch3', interceptorType.nullable()); + checkReturn('testContinue1', interceptorType.nullable()); + checkReturn('testBreak1', interceptorType.nullable()); + checkReturn('testContinue2', interceptorType.nullable()); + checkReturn('testBreak2', typesInferrer.intType.nullable()); checkReturnInClass(String className, String methodName, type) { var cls = findElement(compiler, className); var element = cls.lookupLocalMember(buildSourceString(methodName)); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element]); + Expect.equals(type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler)); } checkReturnInClass('A', 'returnInt1', typesInferrer.intType); @@ -439,6 +526,7 @@ checkReturnInClass('B', 'returnInt6', typesInferrer.intType); checkReturnInClass('B', 'returnInt7', typesInferrer.intType); checkReturnInClass('B', 'returnInt8', typesInferrer.intType); + checkReturnInClass('B', 'returnInt9', typesInferrer.intType); checkFactoryConstructor(String className) { var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart index a080d4d..2b6ebef 100644 --- a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart +++ b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
@@ -161,7 +161,8 @@ checkReturn(String name, type) { var element = findElement(compiler, name); - Expect.equals(type, typesInferrer.internal.returnTypeOf[element]); + Expect.equals(type, + typesInferrer.internal.returnTypeOf[element].simplify(compiler)); } checkReturn('returnInt1', typesInferrer.intType);
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart index 1381be8..6b813b0 100644 --- a/tests/compiler/dart2js/type_checker_test.dart +++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -3,14 +3,16 @@ // BSD-style license that can be found in the LICENSE file. import "package:expect/expect.dart"; +import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'; import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'; import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart'; +import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart'; import 'mock_compiler.dart'; import 'parser_helper.dart'; import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart' - show ElementX; + show ElementX, CompilationUnitElementX; import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart' hide SourceString; @@ -38,7 +40,8 @@ // testNewExpression, testConditionalExpression, testIfStatement, - testThis]; + testThis, + testOperatorsAssignability]; for (Function test in tests) { setup(); test(); @@ -111,19 +114,22 @@ analyze("{ var i = 1 ${op} 2; }"); analyze("{ var i = 1; i ${op}= 2; }"); analyze("{ int i; var j = (i = true) ${op} 2; }", - MessageKind.NOT_ASSIGNABLE); + [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]); analyze("{ int i; var j = 1 ${op} (i = true); }", - MessageKind.NOT_ASSIGNABLE); + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); } for (final op in ['-', '~']) { analyze("{ var i = ${op}1; }"); - analyze("{ int i; var j = ${op}(i = true); }", MessageKind.NOT_ASSIGNABLE); + analyze("{ int i; var j = ${op}(i = true); }", + [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]); } for (final op in ['++', '--']) { analyze("{ int i = 1; int j = i${op}; }"); analyze("{ int i = 1; bool j = i${op}; }", MessageKind.NOT_ASSIGNABLE); - analyze("{ bool b = true; bool j = b${op}; }"); - analyze("{ bool b = true; int j = ${op}b; }"); + analyze("{ bool b = true; bool j = b${op}; }", + MessageKind.OPERATOR_NOT_FOUND); + analyze("{ bool b = true; int j = ${op}b; }", + MessageKind.OPERATOR_NOT_FOUND); } for (final op in ['||', '&&']) { analyze("{ bool b = (true ${op} false); }"); @@ -131,13 +137,21 @@ analyze("{ bool b = (1 ${op} false); }", MessageKind.NOT_ASSIGNABLE); analyze("{ bool b = (true ${op} 2); }", MessageKind.NOT_ASSIGNABLE); } - for (final op in ['>', '<', '<=', '>=', '==', '!=']) { + for (final op in ['>', '<', '<=', '>=']) { analyze("{ bool b = 1 ${op} 2; }"); analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE); analyze("{ int i; bool b = (i = true) ${op} 2; }", - MessageKind.NOT_ASSIGNABLE); + [MessageKind.NOT_ASSIGNABLE, MessageKind.OPERATOR_NOT_FOUND]); analyze("{ int i; bool b = 1 ${op} (i = true); }", - MessageKind.NOT_ASSIGNABLE); + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + } + for (final op in ['==', '!=']) { + analyze("{ bool b = 1 ${op} 2; }"); + analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE); + analyze("{ int i; bool b = (i = true) ${op} 2; }", + MessageKind.NOT_ASSIGNABLE); + analyze("{ int i; bool b = 1 ${op} (i = true); }", + MessageKind.NOT_ASSIGNABLE); } } @@ -495,6 +509,281 @@ analyzeIn(foo, "{ Foo f = this; }"); } +const String CLASSES_WITH_OPERATORS = ''' +class Operators { + Operators operator +(Operators other) => this; + Operators operator -(Operators other) => this; + Operators operator -() => this; + Operators operator *(Operators other) => this; + Operators operator /(Operators other) => this; + Operators operator %(Operators other) => this; + Operators operator ~/(Operators other) => this; + + Operators operator &(Operators other) => this; + Operators operator |(Operators other) => this; + Operators operator ^(Operators other) => this; + + Operators operator ~() => this; + + Operators operator <(Operators other) => true; + Operators operator >(Operators other) => false; + Operators operator <=(Operators other) => this; + Operators operator >=(Operators other) => this; + + Operators operator <<(Operators other) => this; + Operators operator >>(Operators other) => this; + + bool operator ==(Operators other) => true; + + Operators operator [](Operators key) => this; + void operator []=(Operators key, Operators value) {} +} + +class MismatchA { + int operator+(MismatchA other) => 0; + MismatchA operator-(int other) => this; + + MismatchA operator[](int key) => this; + void operator[]=(int key, MismatchA value) {} +} + +class MismatchB { + MismatchB operator+(MismatchB other) => this; + + MismatchB operator[](int key) => this; + void operator[]=(String key, MismatchB value) {} +} + +class MismatchC { + MismatchC operator+(MismatchC other) => this; + + MismatchC operator[](int key) => this; + void operator[]=(int key, String value) {} +} +'''; + +testOperatorsAssignability() { + compiler.parseScript(CLASSES_WITH_OPERATORS); + + // Tests against Operators. + + String header = """{ + bool z; + Operators a; + Operators b; + Operators c; + """; + + check(String text, [expectedWarnings]) { + analyze('$header $text }', expectedWarnings); + } + + // Positive tests on operators. + + check('c = a + b;'); + check('c = a - b;'); + check('c = -a;'); + check('c = a * b;'); + check('c = a / b;'); + check('c = a % b;'); + check('c = a ~/ b;'); + + check('c = a & b;'); + check('c = a | b;'); + check('c = a ^ b;'); + + check('c = ~a;'); + + check('c = a < b;'); + check('c = a > b;'); + check('c = a <= b;'); + check('c = a >= b;'); + + check('c = a << b;'); + check('c = a >> b;'); + + check('c = a[b];'); + + check('a[b] = c;'); + check('a[b] += c;'); + check('a[b] -= c;'); + check('a[b] *= c;'); + check('a[b] /= c;'); + check('a[b] %= c;'); + check('a[b] ~/= c;'); + check('a[b] <<= c;'); + check('a[b] >>= c;'); + check('a[b] &= c;'); + check('a[b] |= c;'); + check('a[b] ^= c;'); + + check('a += b;'); + check('a -= b;'); + check('a *= b;'); + check('a /= b;'); + check('a %= b;'); + check('a ~/= b;'); + + check('a <<= b;'); + check('a >>= b;'); + + check('a &= b;'); + check('a |= b;'); + check('a ^= b;'); + + // Negative tests on operators. + + // For the sake of brevity we misuse the terminology in comments: + // 'e1 is not assignable to e2' should be read as + // 'the type of e1 is not assignable to the type of e2', and + // 'e1 is not assignable to operator o on e2' should be read as + // 'the type of e1 is not assignable to the argument type of operator o + // on e2'. + + // `0` is not assignable to operator + on `a`. + check('c = a + 0;', MessageKind.NOT_ASSIGNABLE); + // `a + b` is not assignable to `z`. + check('z = a + b;', MessageKind.NOT_ASSIGNABLE); + + // `-a` is not assignable to `z`. + check('z = -a;', MessageKind.NOT_ASSIGNABLE); + + // `0` is not assignable to operator [] on `a`. + check('c = a[0];', MessageKind.NOT_ASSIGNABLE); + // `a[b]` is not assignable to `z`. + check('z = a[b];', MessageKind.NOT_ASSIGNABLE); + + // `0` is not assignable to operator [] on `a`. + // Warning suppressed for `0` is not assignable to operator []= on `a`. + check('a[0] *= c;', MessageKind.NOT_ASSIGNABLE); + // `z` is not assignable to operator * on `a[0]`. + check('a[b] *= z;', MessageKind.NOT_ASSIGNABLE); + + check('b = a++;', MessageKind.NOT_ASSIGNABLE); + check('b = ++a;', MessageKind.NOT_ASSIGNABLE); + check('b = a--;', MessageKind.NOT_ASSIGNABLE); + check('b = --a;', MessageKind.NOT_ASSIGNABLE); + + check('c = a[b]++;', MessageKind.NOT_ASSIGNABLE); + check('c = ++a[b];', MessageKind.NOT_ASSIGNABLE); + check('c = a[b]--;', MessageKind.NOT_ASSIGNABLE); + check('c = --a[b];', MessageKind.NOT_ASSIGNABLE); + + check('z = a == b;'); + check('z = a != b;'); + + for (String o in ['&&', '||']) { + check('z = z $o z;'); + check('z = a $o z;', MessageKind.NOT_ASSIGNABLE); + check('z = z $o b;', MessageKind.NOT_ASSIGNABLE); + check('z = a $o b;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + check('a = a $o b;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE, + MessageKind.NOT_ASSIGNABLE]); + } + + check('z = !z;'); + check('z = !a;', MessageKind.NOT_ASSIGNABLE); + check('a = !z;', MessageKind.NOT_ASSIGNABLE); + check('a = !a;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + + + // Tests against MismatchA. + + header = """{ + MismatchA a; + MismatchA b; + MismatchA c; + """; + + // Tests against int operator +(MismatchA other) => 0; + + // `a + b` is not assignable to `c`. + check('c = a + b;', MessageKind.NOT_ASSIGNABLE); + // `a + b` is not assignable to `a`. + check('a += b;', MessageKind.NOT_ASSIGNABLE); + // `a[0] + b` is not assignable to `a[0]`. + check('a[0] += b;', MessageKind.NOT_ASSIGNABLE); + + // 1 is not applicable to operator +. + check('b = a++;', MessageKind.NOT_ASSIGNABLE); + // 1 is not applicable to operator +. + // `++a` of type int is not assignable to `b`. + check('b = ++a;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + + // 1 is not applicable to operator +. + check('b = a[0]++;', MessageKind.NOT_ASSIGNABLE); + // 1 is not applicable to operator +. + // `++a[0]` of type int is not assignable to `b`. + check('b = ++a[0];', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + + // Tests against: MismatchA operator -(int other) => this; + + // `a - b` is not assignable to `c`. + check('c = a + b;', MessageKind.NOT_ASSIGNABLE); + // `a - b` is not assignable to `a`. + check('a += b;', MessageKind.NOT_ASSIGNABLE); + // `a[0] - b` is not assignable to `a[0]`. + check('a[0] += b;', MessageKind.NOT_ASSIGNABLE); + + check('b = a--;'); + check('b = --a;'); + + check('b = a[0]--;'); + check('b = --a[0];'); + + // Tests against MismatchB. + + header = """{ + MismatchB a; + MismatchB b; + MismatchB c; + """; + + // Tests against: + // MismatchB operator [](int key) => this; + // void operator []=(String key, MismatchB value) {} + + // `0` is not applicable to operator []= on `a`. + check('a[0] = b;', MessageKind.NOT_ASSIGNABLE); + + // `0` is not applicable to operator []= on `a`. + check('a[0] += b;', MessageKind.NOT_ASSIGNABLE); + // `""` is not applicable to operator [] on `a`. + check('a[""] += b;', MessageKind.NOT_ASSIGNABLE); + // `c` is not applicable to operator [] on `a`. + // `c` is not applicable to operator []= on `a`. + check('a[c] += b;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + + + // Tests against MismatchB. + + header = """{ + MismatchC a; + MismatchC b; + MismatchC c; + """; + + // Tests against: + // MismatchC operator[](int key) => this; + // void operator[]=(int key, String value) {} + + // `b` is not assignable to `a[0]`. + check('a[0] += b;', MessageKind.NOT_ASSIGNABLE); + // `0` is not applicable to operator + on `a[0]`. + check('a[0] += "";', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); + // `true` is not applicable to operator + on `a[0]`. + // `true` is not assignable to `a[0]`. + check('a[0] += true;', + [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]); +} + const CLASS_WITH_METHODS = ''' class ClassWithMethods { untypedNoArgumentMethod() {} @@ -531,8 +820,45 @@ Node parseExpression(String text) => parseBodyCode(text, (parser, token) => parser.parseExpression(token)); +const String NUM_SOURCE = ''' +abstract class num { + num operator +(num other); + num operator -(num other); + num operator *(num other); + num operator %(num other); + double operator /(num other); + int operator ~/(num other); + num operator -(); + bool operator <(num other); + bool operator <=(num other); + bool operator >(num other); + bool operator >=(num other); +} +'''; + +const String INT_SOURCE = ''' +abstract class int extends num { + int operator &(int other); + int operator |(int other); + int operator ^(int other); + int operator ~(); + int operator <<(int shiftAmount); + int operator >>(int shiftAmount); + int operator -(); +} +'''; + void setup() { - compiler = new MockCompiler(); + RegExp classNum = new RegExp(r'abstract class num {}'); + Expect.isTrue(DEFAULT_CORELIB.contains(classNum)); + RegExp classInt = new RegExp(r'abstract class int extends num { }'); + Expect.isTrue(DEFAULT_CORELIB.contains(classInt)); + + String CORE_SOURCE = DEFAULT_CORELIB + .replaceAll(classNum, NUM_SOURCE) + .replaceAll(classInt, INT_SOURCE); + + compiler = new MockCompiler(coreSource: CORE_SOURCE); types = compiler.types; voidType = compiler.types.voidType; intType = compiler.intClass.computeType(compiler); @@ -570,23 +896,56 @@ } } +api.DiagnosticHandler createHandler(String text) { + return (uri, int begin, int end, String message, kind) { + SourceFile sourceFile; + if (uri == null) { + sourceFile = new SourceFile('analysis', text); + } else { + sourceFile = compiler.sourceFiles[uri.toString()]; + } + if (sourceFile != null) { + print(sourceFile.getLocationMessage(message, begin, end, true, (x) => x)); + } else { + print(message); + } + }; +} + analyze(String text, [expectedWarnings]) { if (expectedWarnings == null) expectedWarnings = []; if (expectedWarnings is !List) expectedWarnings = [expectedWarnings]; + compiler.diagnosticHandler = createHandler(text); + Token tokens = scan(text); NodeListener listener = new NodeListener(compiler, null); Parser parser = new Parser(listener); parser.parseStatement(tokens); Node node = listener.popNode(); + Element compilationUnit = + new CompilationUnitElementX(new Script(null, null), compiler.mainApp); Element function = new ElementX( - buildSourceString(''), ElementKind.FUNCTION, compiler.mainApp); + buildSourceString(''), ElementKind.FUNCTION, compilationUnit); TreeElements elements = compiler.resolveNodeStatement(node, function); TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements, types); compiler.clearWarnings(); checker.analyze(node); compareWarningKinds(text, expectedWarnings, compiler.warnings); + compiler.diagnosticHandler = null; +} + +void generateOutput(String text) { + for (WarningMessage message in compiler.warnings) { + var beginToken = message.node.getBeginToken(); + var endToken = message.node.getEndToken(); + int begin = beginToken.charOffset; + int end = endToken.charOffset + endToken.slowCharCount; + SourceFile sourceFile = new SourceFile('analysis', text); + print(sourceFile.getLocationMessage(message.message.toString(), + begin, end, true, (str) => str)); + } } analyzeIn(ClassElement classElement, String text, [expectedWarnings]) { @@ -603,7 +962,7 @@ TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements, types); compiler.clearWarnings(); - checker.currentClass = classElement; checker.analyze(node); + generateOutput(text); compareWarningKinds(text, expectedWarnings, compiler.warnings); }
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart index 8a23071..3fea40e 100644 --- a/tests/compiler/dart2js/type_combination_test.dart +++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -96,7 +96,8 @@ } void testUnion(MockCompiler compiler) { - RuleSet ruleSet = new RuleSet('union', (t1, t2) => t1.union(t2, compiler)); + RuleSet ruleSet = new RuleSet('union', + (t1, t2) => t1.union(t2, compiler).simplify(compiler)); rule(type1, type2, result) => ruleSet.rule(type1, type2, result); check(type1, type2, predicate) => ruleSet.check(type1, type2, predicate);
diff --git a/tests/compiler/dart2js_extra/factory_test.dart b/tests/compiler/dart2js_extra/factory_test.dart deleted file mode 100644 index 0d3e59b..0000000 --- a/tests/compiler/dart2js_extra/factory_test.dart +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import "package:expect/expect.dart"; - -class A { - factory A() { - return 1; - } -} - -main() { - Expect.equals(1, new A()); -}
diff --git a/tests/compiler/dart2js_extra/type_error_message_test.dart b/tests/compiler/dart2js_extra/type_error_message_test.dart new file mode 100644 index 0000000..220550b --- /dev/null +++ b/tests/compiler/dart2js_extra/type_error_message_test.dart
@@ -0,0 +1,31 @@ +// 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 'package:expect/expect.dart'; + +class C<T, S> {} + +bool inCheckedMode() { + try { + int i = 'hest'; + } catch (e) { + return true; + } + return false; +} + +main() { + if (inCheckedMode()) { + bool caught = false; + try { + C<String, String> x = new C<C<int, String>, String>(); + } catch (e) { + String expected = 'C<C<int, String>, String>'; + Expect.isTrue(e.toString().contains(expected), + 'Expected "$expected" in the message'); + caught = true; + } + Expect.isTrue(caught); + } +}
diff --git a/tests/compiler/dart2js_native/native_exception2_test.dart b/tests/compiler/dart2js_native/native_exception2_test.dart new file mode 100644 index 0000000..6f26332 --- /dev/null +++ b/tests/compiler/dart2js_native/native_exception2_test.dart
@@ -0,0 +1,25 @@ +// 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. + +// Similar to native_exception_test.dart but also defines a native +// class. This exercises a different code path in emitter.dart. + +library native_exception2_test; + +import 'native_exception_test.dart' as other; + +class NativeClass native "NativeClass" { +} + +makeNativeClass() native; + +setup() native """ +function NativeClass() {} +makeNativeClass = function() { return new NativeClass; } +"""; + +main() { + setup(); + other.main(); +}
diff --git a/tests/compiler/dart2js_native/native_exception_test.dart b/tests/compiler/dart2js_native/native_exception_test.dart new file mode 100644 index 0000000..9b1d346 --- /dev/null +++ b/tests/compiler/dart2js_native/native_exception_test.dart
@@ -0,0 +1,34 @@ +// 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 that dart2js can handle unexpected exception types. + +library native_exception_test; + +import 'dart:_foreign_helper' show JS; + +import "package:expect/expect.dart"; + +main() { + var previous; + check(e) { + print('$e'); + Expect.equals(e, e); + Expect.notEquals(e, new Object()); + Expect.notEquals(e, previous); + previous = e; + return '$e' != '[object Object]'; + } + Expect.throws(() { JS('void', 'noGlobalVariableWithThisName'); }, check); + Expect.throws(() { JS('void', 'throw 3'); }, check); + Expect.throws( + () { + JS('bool', 'Object.prototype.hasOwnProperty.call(undefined, "foo")'); + }, + check); + Expect.throws(() { JS('void', 'throw new ReferenceError()'); }, check); + Expect.throws(() { JS('void', 'throw void 0'); }, check); + Expect.throws(() { JS('void', 'throw "a string"'); }, check); + Expect.throws(() { JS('void', 'throw null'); }, check); +}
diff --git a/tests/corelib/string_trim2_test.dart b/tests/corelib/string_trim2_test.dart new file mode 100644 index 0000000..0f0ccab --- /dev/null +++ b/tests/corelib/string_trim2_test.dart
@@ -0,0 +1,48 @@ +// 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 "package:expect/expect.dart"; + +// TODO(floitsch): Test 0x85 when dart2js supports it. +const WHITESPACE = const [ + 9, + 10, + 11, + 12, + 13, + 0x20, + 0xA0, + 0x1680, + 0x180E, + 0x2000, + 0x2001, + 0x2002, + 0x2003, + 0x2004, + 0x2005, + 0x2006, + 0x2007, + 0x2008, + 0x2009, + 0x200A, + 0x202F, + 0x205F, + 0x3000, + 0x2028, + 0x2029, + 0xFEFF, +]; + +main() { + for (var ws in WHITESPACE) { + Expect.equals("", new String.fromCharCode(ws).trim()); + } + Expect.equals("", new String.fromCharCodes(WHITESPACE).trim()); + for (var ws in WHITESPACE) { + var c = new String.fromCharCode(ws); + Expect.equals("a", ("a" + c).trim()); + Expect.equals("a", (c + "a").trim()); + Expect.equals("a", (c + c + "a" + c + c).trim()); + } +}
diff --git a/tests/html/html.status b/tests/html/html.status index 409328c..255b99c 100644 --- a/tests/html/html.status +++ b/tests/html/html.status
@@ -4,7 +4,6 @@ window_open_test: Skip # http://dartbug.com/5151 async_window_test: Skip #TODO(gram): investigating -svg_test: Skip #TODO(vsm): investigating event_test: Skip # Issue 1996 custom_elements_test: Skip # Not yet implemented. @@ -13,6 +12,7 @@ [ $compiler == none && ($runtime == drt || $runtime == dartium) ] # postMessage in dartium always transfers the typed array buffer, never a view postmessage_structured_test/typed_arrays: Fail +custom_element_bindings_test: Fail # To investigate. [ $compiler == none && $runtime == drt && $system == windows ] worker_test/functional: Pass, Crash # Issue 9929. @@ -28,9 +28,6 @@ [ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ] worker_api_test: Fail # IE does not support URL.createObjectURL in web workers. -[ $compiler == dart2js && ( $runtime == ff ) ] -worker_api_test: Fail # Requires Firefox 21. - [ $compiler == dart2js && $runtime == safari ] url_test: Fail # Issue 10096 @@ -187,7 +184,6 @@ rtc_test/supported: Fail shadow_dom_test/supported: Fail speechrecognition_test/supported: Fail -svg_test/supported_externalResourcesRequired: Fail svgelement_test/supported_altGlyph: Fail svgelement_test/supported_animate: Fail svgelement_test/supported_animateMotion: Fail @@ -265,6 +261,9 @@ speechrecognition_test/supported: Fail touchevent_test/supported: Fail +[ $runtime == ie9 && $checked ] +element_types_test/constructors: Fail # Issue 10796 + [ $runtime == opera ] blob_constructor_test: Fail canvas_test: Fail @@ -306,8 +305,6 @@ notifications_test/supported: Fail performance_api_test/supported: Fail speechrecognition_test/supported: Fail -svg_test/supported_externalResourcesRequired: Fail -svg_test/supported_langSpace: Fail websql_test/supported: Fail [ $runtime == ff ] @@ -320,7 +317,6 @@ # All changes should be accompanied by platform support annotation changes. audiobuffersourcenode_test/supported: Fail audiocontext_test/supported: Fail -crypto_test/supported: Fail css_test/supportsPointConversions: Fail document_test/supports_cssCanvasContext: Fail element_types_test/supported_content: Fail @@ -346,8 +342,6 @@ rtc_test/supported: Fail # Release build does not enable by default. shadow_dom_test/supported: Fail speechrecognition_test/supported: Fail -svg_test/supported_externalResourcesRequired: Fail -svg_test/supported_langSpace: Fail touchevent_test/supported: Fail websql_test/supported: Fail xhr_test/supported_HttpRequestProgressEvent: Fail
diff --git a/tests/html/svg_test.dart b/tests/html/svg_test.dart index 156f379..db31807 100644 --- a/tests/html/svg_test.dart +++ b/tests/html/svg_test.dart
@@ -68,15 +68,6 @@ var isSvgSvgElement = predicate((x) => x is svg.SvgSvgElement, 'is a SvgSvgElement'); var isNode = predicate((x) => x is Node, 'is a Node'); - var isSvgTests = predicate((x) => x is svg.Tests, 'is a svg.Tests'); - var isSvgLangSpace = predicate((x) => x is svg.LangSpace, 'is a svg.LangSpace'); - var isSvgExternalResourcesRequired = - predicate((x) => x is svg.ExternalResourcesRequired, - 'is a svg.ExternalResourcesRequired'); - var isSvgTransformable = - predicate((x) => x is svg.Transformable, 'is a svg.Transformable'); - var isSvgLocatable = - predicate((x) => x is svg.Locatable, 'is a svg.Locatable'); var isSvgNumber = predicate((x) => x is svg.Number, 'is a svg.Number'); var isSvgRect = predicate((x) => x is svg.Rect, 'is a svg.Rect'); @@ -89,13 +80,6 @@ expect(r, isElement); expect(r, isNode); - // Other implemented interfaces. - expect(r, isSvgTests); - expect(r, isSvgLangSpace); - expect(r, isSvgExternalResourcesRequired); - expect(r, isSvgTransformable); - expect(r, isSvgLocatable); - // Interfaces not implemented. expect(r, isNot(isSvgNumber)); expect(r, isNot(isSvgRect)); @@ -116,24 +100,6 @@ return element; } - group('supported_externalResourcesRequired', () { - test('supported', () { - var div = insertTestDiv(); - var r = document.query('#rect1'); - expect(svg.ExternalResourcesRequired.supported(r), true); - div.remove(); - }); - }); - - group('supported_langSpace', () { - test('supported', () { - var div = insertTestDiv(); - var r = document.query('#rect1'); - expect(svg.LangSpace.supported(r), true); - div.remove(); - }); - }); - group('svgBehavioral', () { // Test that SVG elements have the operations advertised through all the IDL @@ -154,47 +120,6 @@ var isCssStyleDeclaration = predicate((x) => x is CssStyleDeclaration, 'is a CssStyleDeclaration'); - /// Verifies that [e] supports the operations on the svg.Tests interface. - checkSvgTests(e) { - // Just check that the operations seem to exist. - var rx = e.requiredExtensions; - expect(rx, isStringList); - var rf = e.requiredFeatures; - expect(rf, isStringList); - var sl = e.systemLanguage; - expect(sl, isStringList); - - bool hasDoDo = e.hasExtension("DoDo"); - expect(hasDoDo, isFalse); - } - - /// Verifies that [e] supports the operations on the svg.Locatable interface. - checkSvgLocatable(e) { - var v1 = e.farthestViewportElement; - var v2 = e.nearestViewportElement; - expect(v1, same(v2)); - - var bbox = e.getBBox(); - expect(bbox, isSvgRect); - - var ctm = e.getCtm(); - expect(ctm, isSvgMatrix); - - var sctm = e.getScreenCtm(); - expect(sctm, isSvgMatrix); - - var xf2e = e.getTransformToElement(e); - expect(xf2e, isSvgMatrix); - } - - /** - * Verifies that [e] supports the operations on the svg.Transformable - * interface. - */ - checkSvgTransformable(e) { - var trans = e.transform; - expect(trans, isSvgAnimatedTransformList); - } testRect(name, checker) { test(name, () { @@ -204,43 +129,6 @@ div.remove(); }); } - - /** - * Verifies that [e] supports the operations on the svg.LangSpace interface. - */ - checkSvgLangSpace(e) { - if (svg.LangSpace.supported(e)) { - // Just check that the attributes seem to exist. - var lang = e.xmllang; - e.xmllang = lang; - - String space = e.xmlspace; - e.xmlspace = space; - - expect(lang, isString); - expect(space, isString); - } - } - - /** - * Verifies that [e] supports the operations on the - * svg.ExternalResourcesRequired interface. - */ - checkSvgExternalResourcesRequired(e) { - if (svg.ExternalResourcesRequired.supported(e)) { - var b = e.externalResourcesRequired; - expect(b, isSvgAnimatedBoolean); - expect(b.baseVal, isFalse); - expect(b.animVal, isFalse); - } - } - - testRect('rect_SvgTests', checkSvgTests); - testRect('rect_SvgLangSpace', checkSvgLangSpace); - testRect('rect_SvgExternalResourcesRequired', - checkSvgExternalResourcesRequired); - testRect('rect_SvgLocatable', checkSvgLocatable); - testRect('rect_SvgTransformable', checkSvgTransformable); }); }
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status index 8b8934f..6368aad 100644 --- a/tests/isolate/isolate.status +++ b/tests/isolate/isolate.status
@@ -40,7 +40,6 @@ [ $compiler == dartanalyzer ] isolate2_negative_test: fail -isolate3_negative_test: fail isolate_import_negative_test: fail isolate_negative_test: fail spawn_function_negative_test: fail
diff --git a/tests/language/factory_return_type_checked_test.dart b/tests/language/factory_return_type_checked_test.dart new file mode 100644 index 0000000..dc46145 --- /dev/null +++ b/tests/language/factory_return_type_checked_test.dart
@@ -0,0 +1,23 @@ +// 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 "package:expect/expect.dart"; + +class A { + factory A() => 42; +} + +main() { + bool isCheckedMode = false; + try { + String a = 42; + } catch (e) { + isCheckedMode = true; + } + if (isCheckedMode) { + Expect.throws(() => new A(), (e) => e is TypeError); + } else { + Expect.equals(42, new A()); + } +}
diff --git a/tests/language/generic_list_checked_test.dart b/tests/language/generic_list_checked_test.dart new file mode 100644 index 0000000..fcff24b --- /dev/null +++ b/tests/language/generic_list_checked_test.dart
@@ -0,0 +1,20 @@ +// 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 'package:expect/expect.dart'; + +bool inCheckedMode() { + try { + int i = 'hest'; + } catch (e) { + return true; + } + return false; +} + +main() { + if (inCheckedMode()) { + Expect.throws(() { List<int> t = new List<String>(); }); + } +}
diff --git a/tests/language/inferrer_constructor_test.dart b/tests/language/inferrer_constructor_test.dart new file mode 100644 index 0000000..38b97da --- /dev/null +++ b/tests/language/inferrer_constructor_test.dart
@@ -0,0 +1,24 @@ +// 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 that dart2js type inferrer detects dead code. + +import "package:expect/expect.dart"; + +class A { + var field; + A(test) { + if (test) { + return; + field = 42; + } else { + field = 54; + } + } +} + +main() { + var a = new A(true); + Expect.throws(() => a.field + 42, (e) => e is NoSuchMethodError); +}
diff --git a/tests/language/issue10561_test.dart b/tests/language/issue10561_test.dart new file mode 100644 index 0000000..d02e157 --- /dev/null +++ b/tests/language/issue10561_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. + +// Regression test for dart2js that used to miscompile classes +// extending HashMap, because HashMap is patched. + +import "package:expect/expect.dart"; + +import 'dart:collection'; + +class Foo extends HashMap { +} + +main() { + Expect.equals(0, new Foo().length); +}
diff --git a/tests/language/issue10721_test.dart b/tests/language/issue10721_test.dart new file mode 100644 index 0000000..4bad7a0 --- /dev/null +++ b/tests/language/issue10721_test.dart
@@ -0,0 +1,26 @@ +// 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 "package:expect/expect.dart"; + +void main() { + Expect.equals('', useParameterInClosure(1)); + Expect.equals(43, updateParameterInClosure(1)()); +} + +String useParameterInClosure(arg1, {int arg2}) { + if (arg1 is Map) { + return arg1.keys.map((key) => arg1[key]).first; + } else { + return ''; + } +} + +Function updateParameterInClosure(arg1) { + if (arg1 is Map) { + return () => arg1 = 42; + } else { + return () => arg1 = arg1 + 42; + } +}
diff --git a/tests/language/issue10747_test.dart b/tests/language/issue10747_test.dart new file mode 100644 index 0000000..fda6c49 --- /dev/null +++ b/tests/language/issue10747_test.dart
@@ -0,0 +1,28 @@ +// 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 "package:expect/expect.dart"; + +class B<T> { +} + +class A<T> { + var field; + A(this.field); + asTypeVariable() => field as T; + asBOfT() => field as B<T>; +} + +main() { + Expect.equals(42, new A<int>(42).asTypeVariable()); + Expect.throws( + () => new A<String>(42).asTypeVariable(), + (e) => e is CastError); + + var b = new B<int>(); + Expect.equals(b, new A<int>(b).asBOfT()); + Expect.throws( + () => new A<String>(b).asBOfT(), + (e) => e is CastError); +}
diff --git a/tests/language/issue10783_test.dart b/tests/language/issue10783_test.dart new file mode 100644 index 0000000..c603f81 --- /dev/null +++ b/tests/language/issue10783_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 "package:expect/expect.dart"; + +class C { + foo(int y) { return y; } +} + +main() { + for (var b in [[false, 'pig']]) { + var c; + if (b[0]) c = new C(); + Expect.throws(() => print(c.foo(b[1])), (e) => e is NoSuchMethodError); + } +}
diff --git a/tests/language/language.status b/tests/language/language.status index e7a5d61..a1fbeef 100644 --- a/tests/language/language.status +++ b/tests/language/language.status
@@ -556,11 +556,6 @@ [ $compiler == dartanalyzer ] abstract_factory_constructor_test/00: fail assign_instance_method_negative_test: fail -assign_static_type_test/01: fail -assign_static_type_test/02: fail -assign_static_type_test/03: fail -assign_static_type_test/04: fail -assign_static_type_test/05: fail assign_static_type_test/06: fail bad_named_parameters2_test: fail bad_named_parameters_test: fail @@ -576,21 +571,13 @@ call_constructor_on_unresolvable_class_test/02: fail call_constructor_on_unresolvable_class_test/03: fail call_constructor_on_unresolvable_class_test/07: fail -call_non_method_field_test/01: fail -call_non_method_field_test/02: fail -call_nonexistent_static_test/01: fail -call_nonexistent_static_test/02: fail -call_nonexistent_static_test/03: fail call_nonexistent_static_test/04: fail -call_nonexistent_static_test/05: fail call_nonexistent_static_test/06: fail call_nonexistent_static_test/07: fail -call_nonexistent_static_test/08: fail call_nonexistent_static_test/09: fail call_nonexistent_static_test/10: fail call_through_getter_test: fail -callable_test/00: fail -callable_test/01: fail +callable_test/none: fail cast_test/04: fail cast_test/05: fail class_cycle_negative_test: fail @@ -613,6 +600,7 @@ class_literal_test/27: fail class_literal_test/28: fail class_literal_test/29: fail +class_literal_test/none: fail closure_call_wrong_argument_count_negative_test: fail compile_time_constant10_test/none: fail compile_time_constant8_test: fail @@ -623,6 +611,8 @@ compile_time_constant_arguments_test/05: fail compile_time_constant_arguments_test/06: fail compile_time_constant_b_test: fail +compile_time_constant_c_test/01: fail +compile_time_constant_c_test/02: fail compile_time_constant_checked2_test/01: fail compile_time_constant_checked2_test/02: fail compile_time_constant_checked2_test/03: fail @@ -635,11 +625,6 @@ compile_time_constant_checked3_test/04: fail compile_time_constant_checked3_test/05: fail compile_time_constant_checked3_test/06: fail -compile_time_constant_checked_test/01: fail -compile_time_constant_checked_test/02: fail -compile_time_constant_checked_test/03: fail -compile_time_constant_c_test/01: fail -compile_time_constant_c_test/02: fail compile_time_constant_d_test: fail compile_time_constant_e_test: fail compile_time_constant_test/02: fail @@ -649,9 +634,6 @@ constructor3_negative_test: fail constructor_call_wrong_argument_count_negative_test: fail constructor_negative_test: fail -constructor_redirect2_test/02: fail -constructor_redirect2_test/04: fail -constructor_redirect_test/01: fail constructor_return_with_arrow_negative_test: fail constructor_return_with_init_and_arrow_negative_test: fail cyclic_type_variable_test/01: fail @@ -660,33 +642,20 @@ cyclic_type_variable_test/04: fail default_factory2_test/01: fail default_implementation2_test: fail -duplicate_constructor_test/01: fail dynamic2_test/00: fail dynamic_field_test: fail export_cyclic_test: fail f_bounded_quantification_test/01: fail f_bounded_quantification_test/02: fail -factory1_test/00: skip -factory1_test/01: skip factory2_test: fail factory5_test/00: fail -factory_implementation_test/00: skip +factory_implementation_test/none: fail factory_redirection2_test/01: fail factory_redirection_test/07: fail -factory_redirection_test/08: skip -factory_redirection_test/09: skip -factory_redirection_test/10: skip -factory_redirection_test/11: skip -factory_redirection_test/12: skip -factory_redirection_test/13: skip -factory_redirection_test/14: skip fauxverride_test/03: fail fauxverride_test/05: fail field_method4_negative_test: fail field_override_test/01: fail -field_override_test/02: fail -field_type_check_test/01: fail -field_type_check2_test/01: skip final_for_in_variable_test/01: fail final_param_negative_test: fail final_var_negative_test: fail @@ -704,10 +673,7 @@ getter_no_setter_test/00: fail getter_no_setter_test/01: fail getters_setters2_test/01: fail -getters_setters2_test/02: fail -getters_setters2_test/03: skip getters_setters_type_test/01: fail -implicit_scope_test: fail implicit_this_test/01: fail implicit_this_test/04: fail implicit_this_test/none: fail @@ -725,14 +691,12 @@ interface_test/00: fail internal_library_test/01: fail is_not_class2_negative_test: fail -issue1363_test: fail library_juxtaposition_test: fail licm_test: fail list_literal1_negative_test: fail list_literal_syntax_test/01: fail list_literal_syntax_test/02: fail list_literal_syntax_test/03: fail -list_literal_syntax_test/05: fail map_literal1_negative_test: fail map_literal3_test: fail method_override2_test/03: fail @@ -754,11 +718,10 @@ named_parameters_aggregated_test/03: fail named_parameters_aggregated_test/04: fail named_parameters_aggregated_test/05: fail -named_parameters_type_test: fail -nested_switch_label_test: fail new_expression_type_args_test/00: fail new_expression_type_args_test/01: fail new_expression_type_args_test/02: fail +nested_switch_label_test: fail no_such_method_negative_test: fail non_const_super_negative_test: fail number_identifier_negative_test: fail @@ -771,8 +734,6 @@ override_field_test/03: fail override_method_with_field_test/01: fail override_method_with_field_test/02: fail -parameter_initializer5_negative_test: fail -positional_parameters_type_test: fail prefix10_negative_test: fail prefix11_negative_test: fail prefix12_negative_test: fail @@ -798,42 +759,12 @@ static_call_wrong_argument_count_negative_test: fail static_field3_test/01: fail static_field3_test/02: fail -static_field3_test/03: fail static_field3_test/04: fail static_field_test/01: fail static_field_test/02: fail static_field_test/03: fail -static_field_test/04: fail static_final_field2_negative_test: fail static_final_field_negative_test: fail -string_interpolate1_negative_test: fail -string_interpolate2_negative_test: fail -string_interpolation2_negative_test: fail -string_interpolation3_negative_test: fail -string_interpolation4_negative_test: fail -string_interpolation5_negative_test: fail -string_interpolation6_negative_test: fail -string_interpolation9_test/10: fail -string_interpolation9_test/11: fail -string_interpolation9_test/12: fail -string_interpolation9_test/13: fail -string_interpolation9_test/14: fail -string_interpolation9_test/15: fail -string_interpolation9_test/16: fail -string_interpolation9_test/17: fail -string_interpolation9_test/18: fail -string_interpolation9_test/19: fail -string_interpolation9_test/1: fail -string_interpolation9_test/20: fail -string_interpolation9_test/2: fail -string_interpolation9_test/3: fail -string_interpolation9_test/4: fail -string_interpolation9_test/5: fail -string_interpolation9_test/6: fail -string_interpolation9_test/7: fail -string_interpolation9_test/8: fail -string_interpolation9_test/9: fail -string_interpolation_test/01: fail super_operator_index_test/01: fail super_operator_index_test/02: fail super_operator_index_test/03: fail @@ -865,26 +796,16 @@ type_variable_bounds2_test/02: fail type_variable_bounds2_test/03: fail type_variable_bounds2_test/04: fail -type_variable_bounds2_test/05: skip type_variable_bounds2_test/06: fail -type_variable_bounds3_test/00: skip type_variable_bounds_test/00: fail type_variable_bounds_test/01: fail type_variable_bounds_test/02: fail type_variable_bounds_test/03: fail type_variable_bounds_test/04: fail -type_variable_bounds_test/05: fail type_variable_bounds_test/06: fail type_variable_bounds_test/07: fail type_variable_bounds_test/09: fail -type_variable_bounds_test/10: fail type_variable_identifier_expression_negative_test: fail -type_variable_scope_test/00: skip -type_variable_scope_test/01: skip -type_variable_scope_test/02: skip -type_variable_scope_test/03: skip -type_variable_scope_test/04: skip -type_variable_scope_test/05: skip type_variable_static_context_negative_test: fail typed_equality_test: fail unary2_test: fail @@ -892,15 +813,13 @@ unresolved_in_factory_negative_test: fail unresolved_top_level_method_negative_test: fail unresolved_top_level_var_negative_test: fail -unsigned_right_shift_test/01: fail -unsigned_right_shift_test/02: fail -wrong_number_type_arguments_test/00: fail -wrong_number_type_arguments_test/02: fail # test issue 10683, It is a compile-time error if e refers to the name v or the name v=. block_scope_test: fail lazy_static3_test: fail +# test issue 10752, there are 'implicit' scopes for 'if', 'while' and 'do-while' +implicit_scope_test: fail, OK [ $arch == arm ] *: Skip
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status index 1dfd21f..541b3c9 100644 --- a/tests/language/language_dart2js.status +++ b/tests/language/language_dart2js.status
@@ -44,7 +44,6 @@ prefix16_test: Fail # dartbug.com/7354 default_factory2_test/01: Pass # For the wrong reasons. type_variable_scope_test/none: Fail -factory_implementation_test/00: Fail redirecting_factory_infinite_steps_test/01: Fail type_variable_bounds_test/01: Fail type_variable_bounds_test/02: Fail @@ -58,8 +57,6 @@ f_bounded_quantification_test/01: Fail f_bounded_quantification_test/02: Fail closure_type_test: Fail # does not detect type error in checked mode. -factory1_test/00: Fail -factory1_test/01: Fail type_annotation_test/09: Fail # Named constructors interpreted as a type. prefix15_test: Fail # Issue 5022 local_function2_test: Fail # Issue 5022
diff --git a/tests/lib/lib.status b/tests/lib/lib.status index 26e406b..097a374 100644 --- a/tests/lib/lib.status +++ b/tests/lib/lib.status
@@ -25,6 +25,9 @@ [ $compiler == dart2js && $checked ] async/stream_event_transform_test: Fail # Issue 7733. +[ $compiler == dart2js && $unchecked && ($runtime == d8 || $runtime == chrome || $runtime == drt) ] +crypto/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692 + [ $compiler == dart2js && $jscl ] async/future_test: Fail # Timer interface not supported; dartbug.com/7728. async/slow_consumer2_test: Fail # Timer interface not supported; dartbug.com/7728.
diff --git a/tests/standalone/crypto/base64_test.dart b/tests/standalone/crypto/base64_test.dart deleted file mode 100644 index 55546f0..0000000 --- a/tests/standalone/crypto/base64_test.dart +++ /dev/null
@@ -1,71 +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. - -import "package:expect/expect.dart"; - -part "../../../sdk/lib/io/base64.dart"; - -void main() { - String line; - String expected; - - line = - "Man is distinguished, not only by his reason, but by this singular " - "passion from other animals, which is a lust of the mind, that by a " - "perseverance of delight in the continued and indefatigable generation " - "of knowledge, exceeds the short vehemence of any carnal pleasure."; - expected = - "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbm" - "x5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\r\n" - "IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci" - "BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\r\n" - "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcm" - "FuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\r\n" - "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYX" - "Rpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\r\n" - "ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm" - "5hbCBwbGVhc3VyZS4="; - Expect.equals(expected, _Base64._encode(line.codeUnits)); - Expect.listEquals(line.codeUnits, _Base64._decode(expected)); - - line = "Simple string"; - expected = "U2ltcGxlIHN0cmluZw=="; - Expect.equals(expected, _Base64._encode(line.codeUnits)); - Expect.listEquals(line.codeUnits, _Base64._decode(expected)); - - for (int i = 0; i < 256; i++) { - List<int> x = [i]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 255; i++) { - List<int> x = [i, i + 1]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 254; i++) { - List<int> x = [i, i + 1, i + 2]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 253; i++) { - List<int> x = [i, i + 1, i + 2, i + 3]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 252; i++) { - List<int> x = [i, i + 1, i + 2, i + 3, i + 4]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 251; i++) { - List<int> x = [i, i + 1, i + 2, i + 3, i + 4, i + 5]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } - - for (int i = 0; i < 250; i++) { - List<int> x = [i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6]; - Expect.listEquals(x, _Base64._decode(_Base64._encode(x))); - } -}
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart index 93c9deb..d57c014 100644 --- a/tests/standalone/io/file_input_stream_test.dart +++ b/tests/standalone/io/file_input_stream_test.dart
@@ -169,6 +169,61 @@ } +void testInputStreamOffset() { + void test(int start, int end, int expectedBytes) { + var keepAlive = new ReceivePort(); + var temp = new Directory('').createTempSync(); + var file = new File('${temp.path}/input_stream_offset.txt'); + var originalLength = writeLongFileSync(file); + var streamedBytes = 0; + if (expectedBytes < 0) expectedBytes = originalLength + expectedBytes; + file.openRead(start, end).listen( + (d) { + streamedBytes += d.length; + }, + onDone: () { + Expect.equals(expectedBytes, streamedBytes); + temp.delete(recursive: true).then((_) => keepAlive.close()); + }, + onError: (e) { + Expect.fail("Unexpected error"); + }); + } + test(10, 20, 10); + test(10, 11, 1); + test(10, 10, 0); + test(100000000, null, 0); + test(null, 0, 0); + test(null, 1, 1); + test(1, null, -1); + test(20, null, -20); +} + + +void testInputStreamBadOffset() { + void test(int start, int end) { + var keepAlive = new ReceivePort(); + var temp = new Directory('').createTempSync(); + var file = new File('${temp.path}/input_stream_bad_offset.txt'); + var originalLength = writeLongFileSync(file); + var streamedBytes = 0; + file.openRead(start, end).listen( + (d) { + streamedBytes += d.length; + }, + onDone: () { + temp.delete(recursive: true); + }, + onError: (e) { + keepAlive.close(); + }); + } + test(-1, null); + test(100, 99); + test(null, -1); +} + + void testStringLineTransformerEnding(String name, int length) { String fileName = getFilename("tests/standalone/io/$name"); // File contains 10 lines. @@ -198,6 +253,8 @@ testInputStreamTruncate(); testInputStreamDelete(); testInputStreamAppend(); + testInputStreamOffset(); + testInputStreamBadOffset(); // Check the length of these files as both are text files where one // is without a terminating line separator which can easily be added // back if accidentally opened in a text editor.
diff --git a/tests/standalone/io/http_client_timeout_test.dart b/tests/standalone/io/http_client_timeout_test.dart new file mode 100644 index 0000000..0703abb4 --- /dev/null +++ b/tests/standalone/io/http_client_timeout_test.dart
@@ -0,0 +1,85 @@ +// 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 'dart:io'; + + +void testOneRequest(int connections) { + HttpServer.bind('127.0.0.1', 0).then((server) { + server.listen((request) => request.response.close()); + var client = new HttpClient(); + var futures = []; + for (int i = 0; i < connections; i++) { + futures.add( + client.get('127.0.0.1', server.port, '/') + .then((request) => request.close()) + .then((response) => response.fold(null, (x, y) {}))); + } + Future.wait(futures).then((_) { + new Timer.periodic(const Duration(milliseconds: 100), (timer) { + if (server.connectionsInfo().total == 0) { + timer.cancel(); + server.close(); + } + }); + }); + }); +} + + +void testIdleTimeout(int timeout) { + HttpServer.bind('127.0.0.1', 0).then((server1) { + HttpServer.bind('127.0.0.1', 0).then((server2) { + server1.listen((request) => request.pipe(request.response)); + server2.listen((request) => request.pipe(request.response)); + + var client = new HttpClient(); + client.idleTimeout = new Duration(milliseconds: timeout); + + // Create a 'slow' connection.. + Future connect(int port) { + return client.post('127.0.0.1', port, '/') + .then((request) { + request.write("data"); + new Timer(const Duration(milliseconds: 250), () { + request.close(); + }); + return request.done; + }) + .then((response) { + return response.fold(null, (x, y) {}); + }); + } + + // Create a single, slow request, to server1. + connect(server1.port); + + // Create a repeating connection to server2. + run() { + connect(server2.port).then((_) { + if (server1.connectionsInfo().total == 0) { + server1.close(); + server2.close(); + return; + } + Timer.run(run); + }); + } + run(); + }); + }); +} + + +main() { + testOneRequest(1); + testOneRequest(5); + testOneRequest(20); + testIdleTimeout(0); + testIdleTimeout(100); + testIdleTimeout(500); + testIdleTimeout(1000); + testIdleTimeout(2000); +}
diff --git a/tests/standalone/io/http_close_test.dart b/tests/standalone/io/http_close_test.dart index a4f8175..17b4e47 100644 --- a/tests/standalone/io/http_close_test.dart +++ b/tests/standalone/io/http_close_test.dart
@@ -111,9 +111,36 @@ } +void testClientCloseWhileSendingRequest(int connections) { + HttpServer.bind("127.0.0.1", 0).then((server) { + int errors = 0; + server.listen((request) { + request.listen((_) {}, onError: (e) { errors++; }); + }); + var client = new HttpClient(); + for (int i = 0; i < connections; i++) { + client.post("127.0.0.1", server.port, "/") + .then((request) { + request.contentLength = 110; + request.write("0123456789"); + return request.close(); + }) + .catchError((_) {}); + } + new Timer.periodic(const Duration(milliseconds: 100), (t) { + if (errors == connections && server.connectionsInfo().total == 0) { + t.cancel(); + server.close(); + } + }); + }); +} + + void main() { testClientAndServerCloseNoListen(10); testClientCloseServerListen(10); testClientCloseSendingResponse(10); + testClientCloseWhileSendingRequest(10); }
diff --git a/tests/standalone/io/process_echo_util.dart b/tests/standalone/io/process_echo_util.dart new file mode 100644 index 0000000..1cc501d --- /dev/null +++ b/tests/standalone/io/process_echo_util.dart
@@ -0,0 +1,9 @@ +// 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:io"; + +void main() { + new Options().arguments.forEach(print); +}
diff --git a/tests/standalone/io/process_exit_negative_test.dart b/tests/standalone/io/process_exit_negative_test.dart index 9eede27..418977f 100644 --- a/tests/standalone/io/process_exit_negative_test.dart +++ b/tests/standalone/io/process_exit_negative_test.dart
@@ -9,14 +9,14 @@ import "process_test_util.dart"; void main() { - Future<Process> fp = Process.start(getProcessTestFileName(), - const ["0", "0", "0", "0"]); + var fp = Process.start(getProcessTestFileName(), + const ["0", "0", "0", "0"]); fp.then((p) { - p.onExit = (int s) { + p.exitCode.then((int s) { print(a.toString()); // Should cause a compilation error here. - }; + }); // Drain stdout and stderr. - p.stdout.onData = p.stdout.read; - p.stderr.onData = p.stderr.read; + p.stdout.listen((_) {}); + p.stderr.listen((_) {}); }); }
diff --git a/tests/standalone/io/process_shell_test.dart b/tests/standalone/io/process_shell_test.dart new file mode 100644 index 0000000..add0c9f --- /dev/null +++ b/tests/standalone/io/process_shell_test.dart
@@ -0,0 +1,72 @@ +// 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:io"; + +void testRunShell() { + test(args) { + var options = new Options(); + var path = new Path(options.script); + path = path.directoryPath.join(new Path("process_echo_util.dart")); + Process.runShell(options.executable, [path.toString()]..addAll(args)) + .then((result) { + if (Platform.operatingSystem == "windows") { + result = result.stdout.split("\r\n"); + } else { + result = result.stdout.split("\n"); + } + if (result.length - 1 != args.length) { + throw "wrong number of args: $args vs $result"; + } + for (int i = 0; i < args.length; i++) { + if (args[i] != result[i]) { + throw "bad result at $i: '${args[i]}' vs '${result[i]}'"; + } + } + }); + } + test(["\""]); + test(["a b"]); + test(["'"]); + test(["'\"\"'\"'\"'"]); + test(["'\"\"'", "\"'\"'"]); + test(["'\$HOME'"]); + test(["'\$tmp'"]); +} + +void testShell() { + test(args, expected) { + var options = new Options(); + var path = new Path(options.script); + path = path.directoryPath.join(new Path("process_echo_util.dart")); + var command = "${options.executable} $path $args"; + Process.runShell(command, []) + .then((result) { + if (Platform.operatingSystem == "windows") { + result = result.stdout.split("\r\n"); + } else { + result = result.stdout.split("\n"); + } + if (result.length - 1 != expected.length) { + throw "wrong number of args: $expected vs $result"; + } + for (int i = 0; i < expected.length; i++) { + if (expected[i] != result[i]) { + throw "bad result at $i: ${expected[i]} vs ${result[i]}"; + } + } + }); + } + test("arg", ["arg"]); + test("arg1 arg2", ["arg1", "arg2"]); + if (Platform.operatingSystem != 'windows') { + test("arg1 arg2 > /dev/null", []); + } +} + +void main() { + testRunShell(); + testShell(); +} +
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status index 58dfb16..10e39ba 100644 --- a/tests/standalone/standalone.status +++ b/tests/standalone/standalone.status
@@ -7,6 +7,9 @@ [ $runtime == vm && $system == macos ] debugger/basic_debugger_test: Pass, Crash # Issue 10488. +[ $runtime == vm && $system == windows ] +debugger/*: Skip # Issue: 10791 + [ $runtime == vm ] # Fails because checked-in dart executable is not up to date. io/test_runner_test: Fail @@ -79,7 +82,6 @@ io/process_exit_negative_test: Fail # This is a compilation-time negative test. [ $compiler == dartanalyzer ] -crypto/base64_test: fail io/file_constructor_test: fail io/http_date_test: fail io/http_headers_test: fail
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart index 3ed3e17..ae44c27 100644 --- a/tests/utils/dummy_compiler_test.dart +++ b/tests/utils/dummy_compiler_test.dart
@@ -52,8 +52,9 @@ var removeLast; var add; } - class JSFixedArray {} - class JSExtendableArray {} + class JSMutableArray {} + class JSFixedArray extends JSMutableArray {} + class JSExtendableArray extends JSMutableArray {} class JSString { var split; var concat;
diff --git a/tools/VERSION b/tools/VERSION index e85a212..004cbc5 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -1,4 +1,4 @@ MAJOR 0 MINOR 5 -BUILD 9 +BUILD 10 PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py index 3cfd6e5..72cf2e6 100644 --- a/tools/bots/compiler.py +++ b/tools/bots/compiler.py
@@ -219,9 +219,11 @@ # The dart2js compiler isn't self-hosted (yet) so we run its # unit tests on the VM. We avoid doing this on the builders # that run the browser tests to cut down on the cycle time. + unit_test_flags = [flag for flag in flags if flag.startswith('--shard')] + # Run the unit tests in checked mode (the VM's checked mode). + unit_test_flags.append('--checked') TestStep("dart2js_unit", mode, system, 'none', 'vm', ['dart2js'], - # Run the unit tests in checked mode (the VM's checked mode). - ['--checked']) + unit_test_flags) if system.startswith('win') and runtime.startswith('ie10'): TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags)
diff --git a/tools/build.py b/tools/build.py index 2426699..71b9247 100755 --- a/tools/build.py +++ b/tools/build.py
@@ -108,7 +108,7 @@ # We have not yet tweaked the v8 dart build to work with the Android # NDK/SDK, so don't try to build it. if args == []: - print "For android builds you must specify a target, such as 'dart'." + print "For android builds you must specify a target, such as 'samples'." return False if 'v8' in args: print "The v8 target is not supported for android builds." @@ -166,7 +166,7 @@ os.environ['ANDROID_TOOLCHAIN'] = android_toolchain - android_sdk_version = 9 + android_sdk_version = 15 android_sdk_tools = os.path.join(android_sdk_root, 'tools') CheckDirExists(android_sdk_tools, 'Android SDK tools')
diff --git a/tools/dom/dom.json b/tools/dom/dom.json index 22f3b28..cc9935d 100644 --- a/tools/dom/dom.json +++ b/tools/dom/dom.json
@@ -3529,7 +3529,10 @@ "HTMLFormElement": {}, "acceptCharset": {}, "action": {}, - "autocomplete": {}, + "autocomplete": { + "comment": "http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#autofilling-form-controls:-the-autocomplete-attribute", + "support_level": "experimental" + }, "checkValidity": {}, "elements": {}, "encoding": {}, @@ -5295,6 +5298,10 @@ }, "support_level": "untriaged" }, + "MIDIInput": { + "members": {}, + "support_level": "untriaged" + }, "MIDIMessageEvent": { "members": { "data": { @@ -5323,6 +5330,9 @@ "name": { "support_level": "untriaged" }, + "ondisconnect": { + "support_level": "untriaged" + }, "removeEventListener": { "support_level": "untriaged" }, @@ -10173,12 +10183,27 @@ "lang": { "support_level": "untriaged" }, + "onboundary": { + "support_level": "untriaged" + }, + "onend": { + "support_level": "untriaged" + }, "onerror": { "support_level": "untriaged" }, + "onmark": { + "support_level": "untriaged" + }, "onpause": { "support_level": "untriaged" }, + "onresume": { + "support_level": "untriaged" + }, + "onstart": { + "support_level": "untriaged" + }, "pitch": { "support_level": "untriaged" },
diff --git a/tools/dom/scripts/fremontcutbuilder.py b/tools/dom/scripts/fremontcutbuilder.py index 3b172b2..16bf69a 100755 --- a/tools/dom/scripts/fremontcutbuilder.py +++ b/tools/dom/scripts/fremontcutbuilder.py
@@ -12,40 +12,33 @@ _logger = logging.getLogger('fremontcutbuilder') +# See: +# http://src.chromium.org/viewvc/multivm/trunk/webkit/Source/core/features.gypi +# for ENABLE_* flags defined in Chromium / Blink. +# We list all ENABLE flags used in IDL in one of these two lists. FEATURE_DISABLED = [ 'ENABLE_BATTERY_STATUS', - 'ENABLE_CSS3_CONDITIONAL_RULES', 'ENABLE_CSS_DEVICE_ADAPTATION', 'ENABLE_CUSTOM_SCHEME_HANDLER', 'ENABLE_ENCRYPTED_MEDIA_V2', 'ENABLE_MEDIA_CAPTURE', # Only enabled on Android. 'ENABLE_ORIENTATION_EVENTS', # Only enabled on Android. - 'ENABLE_SPEECH_SYNTHESIS', 'ENABLE_WEBVTT_REGIONS', 'ENABLE_XHR_TIMEOUT', ] FEATURE_DEFINES = [ - 'ENABLE_CALENDAR_PICKER', - 'ENABLE_CANVAS_PROXY', - 'ENABLE_CSS_REGIONS', - 'ENABLE_CUSTOM_ELEMENTS', - 'ENABLE_DATALIST_ELEMENT', - 'ENABLE_DIALOG_ELEMENT', + 'ENABLE_CALENDAR_PICKER', # Not on Android + 'ENABLE_DATALIST_ELEMENT', # Not on Android 'ENABLE_ENCRYPTED_MEDIA', - 'ENABLE_FONT_LOAD_EVENTS', - 'ENABLE_GAMEPAD', - 'ENABLE_INPUT_SPEECH', - 'ENABLE_LEGACY_NOTIFICATIONS', - 'ENABLE_MEDIA_STREAM', - 'ENABLE_NAVIGATOR_CONTENT_UTILS', - 'ENABLE_NOTIFICATIONS', - 'ENABLE_PAGE_POPUP', - 'ENABLE_SHARED_WORKERS', + 'ENABLE_INPUT_SPEECH', # Not on Android + 'ENABLE_LEGACY_NOTIFICATIONS', # Not on Android + 'ENABLE_NAVIGATOR_CONTENT_UTILS', # Not on Android + 'ENABLE_NOTIFICATIONS', # Not on Android + 'ENABLE_PAGE_POPUP', # Not on Android 'ENABLE_SVG', 'ENABLE_SVG_FONTS', - 'ENABLE_VIDEO', - 'ENABLE_WEB_AUDIO', + 'ENABLE_WEB_AUDIO', # Not on Android 'ENABLE_WEBGL', ] @@ -111,11 +104,13 @@ if unused_conditionals: _logger.warning('There are some unused conditionals %s' % sorted(unused_conditionals)) + _logger.warning('Please update fremontcutbuilder.py') unknown_conditionals = conditionals_met - known_conditionals if unknown_conditionals: _logger.warning('There are some unknown conditionals %s' % sorted(unknown_conditionals)) + _logger.warning('Please update fremontcutbuilder.py') db.Save() return db
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py index cdbade3..3ed4393 100644 --- a/tools/dom/scripts/htmleventgenerator.py +++ b/tools/dom/scripts/htmleventgenerator.py
@@ -121,6 +121,7 @@ 'DOMApplicationCache.progress': ('progress', 'Event'), 'DOMApplicationCache.updateready': ('updateReady', 'Event'), 'Document.readystatechange': ('readyStateChange', 'Event'), + 'Document.securitypolicyviolation': ('securityPolicyViolation', 'SecurityPolicyViolationEvent'), 'Document.selectionchange': ('selectionChange', 'Event'), 'Document.webkitpointerlockchange': ('pointerLockChange', 'Event'), 'Document.webkitpointerlockerror': ('pointerLockError', 'Event'), @@ -135,8 +136,14 @@ 'FileWriter.write': ('write', 'ProgressEvent'), 'FileWriter.writeend': ('writeEnd', 'ProgressEvent'), 'FileWriter.writestart': ('writeStart', 'ProgressEvent'), + 'FontLoader.load': ('load', 'CssFontFaceLoadEvent'), + 'FontLoader.loading': ('loading', 'CssFontFaceLoadEvent'), + 'FontLoader.loadingdone': ('loadingDone', 'CssFontFaceLoadEvent'), + 'FontLoader.loadstart': ('loadStart', 'CssFontFaceLoadEvent'), 'HTMLBodyElement.storage': ('storage', 'StorageEvent'), 'HTMLInputElement.webkitSpeechChange': ('speechChange', 'Event'), + 'HTMLFormElement.autocomplete': ('autocomplete', 'Event'), + 'HTMLFormElement.autocompleteerror': ('autocompleteError', 'AutocompleteErrorEvent'), 'HTMLMediaElement.loadstart': ('loadStart', 'Event'), 'HTMLMediaElement.progress': ('progress', 'Event'), 'HTMLMediaElement.show': ('show', 'Event'), @@ -153,10 +160,12 @@ 'MediaStream.removetrack': ('removeTrack', 'Event'), 'MediaStreamTrack.mute': ('mute', 'Event'), 'MediaStreamTrack.unmute': ('unmute', 'Event'), + 'MIDIPort.disconnect': ('disconnect', 'MidiConnectionEvent'), 'Notification.click': ('click', 'Event'), 'Notification.close': ('close', 'Event'), 'Notification.display': ('display', 'Event'), 'Notification.show': ('show', 'Event'), + 'Performance.webkitresourcetimingbufferfull': ('resourceTimingBufferFull', 'Event'), 'RTCDTMFSender.tonechange': ('toneChange', 'RtcDtmfToneChangeEvent'), 'RTCDataChannel.close': ('close', 'Event'), 'RTCDataChannel.open': ('open', 'Event'), @@ -179,6 +188,11 @@ 'SpeechRecognition.speechend': ('speechEnd', 'Event'), 'SpeechRecognition.speechstart': ('speechStart', 'Event'), 'SpeechRecognition.start': ('start', 'Event'), + 'SpeechSynthesisUtterance.boundary': ('boundary', 'SpeechSynthesisEvent'), + 'SpeechSynthesisUtterance.end': ('end', 'SpeechSynthesisEvent'), + 'SpeechSynthesisUtterance.mark': ('mark', 'SpeechSynthesisEvent'), + 'SpeechSynthesisUtterance.resume': ('resume', 'SpeechSynthesisEvent'), + 'SpeechSynthesisUtterance.start': ('start', 'SpeechSynthesisEvent'), 'TextTrack.cuechange': ('cueChange', 'Event'), 'TextTrackCue.enter': ('enter', 'Event'), 'TextTrackCue.exit': ('exit', 'Event'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py index e28460c..7262ee1 100644 --- a/tools/dom/scripts/htmlrenamer.py +++ b/tools/dom/scripts/htmlrenamer.py
@@ -56,7 +56,6 @@ 'SVGSVGElement': 'SvgSvgElement', # Manual to avoid name conflicts. 'WebGLVertexArrayObjectOES': 'VertexArrayObject', 'XMLHttpRequest': 'HttpRequest', - 'XMLHttpRequestException': 'HttpRequestException', 'XMLHttpRequestProgressEvent': 'HttpRequestProgressEvent', 'XMLHttpRequestUpload': 'HttpRequestUpload', }, **typed_array_renames)) @@ -157,7 +156,6 @@ # browser. _private_html_members = monitored.Set('htmlrenamer._private_html_members', [ 'CanvasRenderingContext2D.arc', - 'CanvasRenderingContext2D.drawImage', 'CompositionEvent.initCompositionEvent', 'CustomEvent.initCustomEvent', 'DeviceOrientationEvent.initDeviceOrientationEvent', @@ -301,8 +299,6 @@ 'UIEvent.layerY', 'UIEvent.pageX', 'UIEvent.pageY', - 'WheelEvent.wheelDeltaX', - 'WheelEvent.wheelDeltaY', 'WheelEvent.initWebKitWheelEvent', 'DOMWindow.getComputedStyle', ]) @@ -310,6 +306,7 @@ # Members from the standard dom that exist in the dart:html library with # identical functionality but with cleaner names. renamed_html_members = monitored.Dict('htmlrenamer.renamed_html_members', { + 'CanvasRenderingContext2D.drawImage': '_drawImage', 'CSSStyleDeclaration.getPropertyValue': '_getPropertyValue', 'CSSStyleDeclaration.setProperty': '_setProperty', 'DirectoryEntry.getDirectory': '_getDirectory', @@ -346,6 +343,8 @@ 'StorageInfo.queryUsageAndQuota': '_queryUsageAndQuota', 'SVGElement.className': '$dom_svgClassName', 'SVGStopElement.offset': 'gradientOffset', + 'WheelEvent.wheelDeltaX': '_wheelDeltaX', + 'WheelEvent.wheelDeltaY': '_wheelDeltaY', #'WorkerContext.webkitRequestFileSystem': '_requestFileSystem', #'WorkerContext.webkitRequestFileSystemSync': '_requestFileSystemSync', })
diff --git a/tools/dom/scripts/idlparser.py b/tools/dom/scripts/idlparser.py index 6583444..3142118 100755 --- a/tools/dom/scripts/idlparser.py +++ b/tools/dom/scripts/idlparser.py
@@ -212,7 +212,7 @@ [MAYBE(ExtAttrs), MAYBE(Static), MAYBE(Stringifier), MAYBE(_Specials), ReturnType, MAYBE(Id), '(', _Arguments, ')', ';'], # WebKit: - [MAYBE(ExtAttrs), MAYBE(Static), MAYBE(_AttrGetterSetter), + [MAYBE(ExtAttrs), MAYBE(Static), MAYBE(_Specials), ReturnType, MAYBE(Id), '(', _Arguments, ')', ';'], # FremontCut: [MAYBE(_Annotations), MAYBE(ExtAttrs), MAYBE(Static), MAYBE(Stringifier),
diff --git a/tools/dom/scripts/logging.conf b/tools/dom/scripts/logging.conf index 8645a8e..6dbf12e 100644 --- a/tools/dom/scripts/logging.conf +++ b/tools/dom/scripts/logging.conf
@@ -1,5 +1,5 @@ [loggers] -keys=root,pegparser,database,databasebuilder,dartgenerator,dartmetadata,snippet_manager,htmlrenamer +keys=root,pegparser,database,databasebuilder,dartgenerator,dartmetadata,snippet_manager,htmlrenamer,fremontcutbuilder [handlers] keys=consoleHandler @@ -29,6 +29,12 @@ handlers=consoleHandler qualname=databasebuilder +[logger_fremontcutbuilder] +level=INFO +propagate=0 +handlers=consoleHandler +qualname=fremontcutbuilder + [logger_snippet_manager] level=INFO propagate=0
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py index 0302a6c..c6463e1 100644 --- a/tools/dom/scripts/systemhtml.py +++ b/tools/dom/scripts/systemhtml.py
@@ -708,8 +708,11 @@ # ext_attrs = self._interface.ext_attrs - has_indexed_getter = ('IndexedGetter' in ext_attrs or - 'CustomIndexedSetter' in ext_attrs) + has_indexed_getter = 'CustomIndexedGetter' in ext_attrs + for operation in self._interface.operations: + if operation.id == 'item' and 'getter' in operation.specials: + has_indexed_getter = True + break if has_indexed_getter: indexed_getter = ('JS("%s", "#[#]", this, index)' %
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py index a81e322..c5c8219 100644 --- a/tools/dom/scripts/systemnative.py +++ b/tools/dom/scripts/systemnative.py
@@ -336,8 +336,7 @@ ext_attrs = self._interface.ext_attrs - if ('CustomToJS' in ext_attrs or - ('CustomToJSObject' in ext_attrs and 'TypedArray' not in ext_attrs) or + if ('CustomToV8' in ext_attrs or 'PureInterface' in ext_attrs or 'CPPPureInterface' in ext_attrs or self._interface_type_info.custom_to_dart()):
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart index 788b179..303a4e8 100644 --- a/tools/dom/src/EventStreamProvider.dart +++ b/tools/dom/src/EventStreamProvider.dart
@@ -78,16 +78,16 @@ } } - bool get _paused => _pauseCount > 0; + bool get isPaused => _pauseCount > 0; void resume() { - if (_canceled || !_paused) return; + if (_canceled || !isPaused) return; --_pauseCount; _tryResume(); } void _tryResume() { - if (_onData != null && !_paused) { + if (_onData != null && !isPaused) { _target.$dom_addEventListener(_eventType, _onData, _useCapture); } }
diff --git a/tools/dom/src/ImmutableListMixin.dart b/tools/dom/src/ImmutableListMixin.dart index df14b40..2c05c11 100644 --- a/tools/dom/src/ImmutableListMixin.dart +++ b/tools/dom/src/ImmutableListMixin.dart
@@ -47,7 +47,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void remove(Object object) { + bool remove(Object object) { throw new UnsupportedError("Cannot remove from immutable List."); } @@ -59,7 +59,7 @@ throw new UnsupportedError("Cannot remove from immutable List."); } - void setRange(int start, int end, Iterable<E> iterable, [int skipCount]) { + void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { throw new UnsupportedError("Cannot setRange on immutable List."); }
diff --git a/tools/dom/src/TemplateBindings.dart b/tools/dom/src/TemplateBindings.dart index 9841aee..81cebd3 100644 --- a/tools/dom/src/TemplateBindings.dart +++ b/tools/dom/src/TemplateBindings.dart
@@ -378,7 +378,7 @@ } // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner - static Document _getTemplateContentsOwner(Document doc) { + static Document _getTemplateContentsOwner(HtmlDocument doc) { if (doc.window == null) { return doc; } @@ -456,7 +456,7 @@ // template. // TODO(jmesserly): node is DocumentFragment or Element var descendents = (node as dynamic).queryAll(_allTemplatesSelectors); - if (node is Element && node.isTemplate) bootstrap(node); + if (node is Element && (node as Element).isTemplate) bootstrap(node); descendents.forEach(bootstrap); } @@ -610,7 +610,7 @@ static void _removeChild(Node parent, Node child) { child._templateInstance = null; - if (child is Element && child.isTemplate) { + if (child is Element && (child as Element).isTemplate) { // Make sure we stop observing when we remove an element. var templateIterator = child._templateIterator; if (templateIterator != null) {
diff --git a/tools/dom/src/WrappedList.dart b/tools/dom/src/WrappedList.dart index 3baff3e..b725b96 100644 --- a/tools/dom/src/WrappedList.dart +++ b/tools/dom/src/WrappedList.dart
@@ -23,7 +23,7 @@ void add(E element) { _list.add(element); } - void remove(Object element) { _list.remove(element); } + bool remove(Object element) => _list.remove(element); void clear() { _list.clear(); }
diff --git a/tools/dom/src/dart2js_Conversions.dart b/tools/dom/src/dart2js_Conversions.dart index 1c51b29..86f32fb 100644 --- a/tools/dom/src/dart2js_Conversions.dart +++ b/tools/dom/src/dart2js_Conversions.dart
@@ -32,8 +32,14 @@ // Assume it's a Window if it contains the setInterval property. It may be // from a different frame - without a patched prototype - so we cannot // rely on Dart type checking. - if (JS('bool', r'"setInterval" in #', e)) - return _DOMWindowCrossFrame._createSafe(e); + if (JS('bool', r'"setInterval" in #', e)) { + var window = _DOMWindowCrossFrame._createSafe(e); + // If it's a native window. + if (window is EventTarget) { + return window; + } + return null; + } else return e; }
diff --git a/tools/dom/src/dartium_KeyEvent.dart b/tools/dom/src/dartium_KeyEvent.dart index b627b9c..5be433b 100644 --- a/tools/dom/src/dartium_KeyEvent.dart +++ b/tools/dom/src/dartium_KeyEvent.dart
@@ -66,6 +66,8 @@ /** True if the altGraphKey is pressed during this event. */ bool get altGraphKey => _parent.altGraphKey; + /** Accessor to the clipboardData available for this event. */ + DataTransfer get clipboardData => _parent.clipboardData; /** True if the ctrl key is pressed during this event. */ bool get ctrlKey => _parent.ctrlKey; int get detail => _parent.detail;
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate index 28e1d55..2a20d31 100644 --- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate +++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -94,4 +94,4 @@ return JS('var', r'ReceivePortSync.dispatchCall(#, #)', id, message); } -spawnDomFunction(f) => IsolateNatives.spawnDomFunction(f); +spawnDomFunction(Function f) => IsolateNatives.spawnDomFunction(f);
diff --git a/tools/dom/templates/html/dart2js/impl_Console.darttemplate b/tools/dom/templates/html/dart2js/impl_Console.darttemplate index 25d08e1..84527d2 100644 --- a/tools/dom/templates/html/dart2js/impl_Console.darttemplate +++ b/tools/dom/templates/html/dart2js/impl_Console.darttemplate
@@ -6,7 +6,7 @@ $(ANNOTATIONS)class Console { - static Console safeConsole = new Console(); + static Console _safeConsole = new Console(); bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"'); @@ -79,8 +79,8 @@ JS('void', 'console.time(#)', title) : null; @DomName('Console.timeEnd') - void timeEnd(String timerName) => _isConsoleDefined ? - JS('void', 'console.timeEnd(#)', timerName) : null; + void timeEnd(String title) => _isConsoleDefined ? + JS('void', 'console.timeEnd(#)', title) : null; @DomName('Console.timeStamp') void timeStamp(Object arg) => _isConsoleDefined ?
diff --git a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate index 9792bf1..d4e304d 100644 --- a/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate +++ b/tools/dom/templates/html/dart2js/impl_MouseEvent.darttemplate
@@ -64,13 +64,12 @@ return new Point(x, y); } else { // Firefox does not support offsetX. - var target = this.target; - if (!(target is Element)) { + if (!(this.target is Element)) { throw new UnsupportedError( 'offsetX is only supported on elements'); } - return (this.client - - this.target.getBoundingClientRect().topLeft).toInt(); + Element target = this.target; + return (this.client - target.getBoundingClientRect().topLeft).toInt(); } }
diff --git a/tools/dom/templates/html/dart2js/impl_URL.darttemplate b/tools/dom/templates/html/dart2js/impl_URL.darttemplate index 30c4161..3da9a69 100644 --- a/tools/dom/templates/html/dart2js/impl_URL.darttemplate +++ b/tools/dom/templates/html/dart2js/impl_URL.darttemplate
@@ -11,8 +11,8 @@ '(self.URL || self.webkitURL).createObjectURL(#)', blob_OR_source_OR_stream); - static void revokeObjectUrl(String objectUrl) => + static void revokeObjectUrl(String url) => JS('void', - '(self.URL || self.webkitURL).revokeObjectURL(#)', objectUrl); + '(self.URL || self.webkitURL).revokeObjectURL(#)', url); $!MEMBERS }
diff --git a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate index 1fca45d..22b56c2 100644 --- a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate +++ b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
@@ -112,13 +112,13 @@ } $else if (sourceRect == null) { - $dom_drawImage(source, + _drawImage(source, destRect.left, destRect.top, destRect.width, destRect.height); } else { - $dom_drawImage(source, + _drawImage(source, sourceRect.left, sourceRect.top, sourceRect.width, @@ -166,7 +166,7 @@ void drawImage(CanvasImageSource source, num destX, num destY) native; $else void drawImage(CanvasImageSource source, num destX, num destY) { - $dom_drawImage(source, destX, destY); + _drawImage(source, destX, destY); } $endif @@ -204,7 +204,7 @@ $else void drawImageScaled(CanvasImageSource source, num destX, num destY, num destWidth, num destHeight) { - $dom_drawImage(source, destX, destY, destWidth, destHeight); + _drawImage(source, destX, destY, destWidth, destHeight); } $endif @@ -247,7 +247,7 @@ void drawImageScaledFromSource(CanvasImageSource source, num sourceX, num sourceY, num sourceWidth, num sourceHeight, num destX, num destY, num destWidth, num destHeight) { - $dom_drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, + _drawImage(source, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight); } $endif @@ -258,7 +258,7 @@ '#.lineDashOffset || #.webkitLineDashOffset', this, this); @DomName('CanvasRenderingContext2D.lineDashOffset') - void set lineDashOffset(num value) => JS('void', + void set lineDashOffset(num value) => JS('void', 'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : ' '#.webkitLineDashOffset = #', this, this, value, this, value); $else
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate index 261a6cd..188759e 100644 --- a/tools/dom/templates/html/impl/impl_Element.darttemplate +++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -564,11 +564,11 @@ * * [insertAdjacentText] * * [insertAdjacentElement] */ - void insertAdjacentHtml(String where, String text) { + void insertAdjacentHtml(String where, String html) { if (JS('bool', '!!#.insertAdjacentHtml', this)) { - _insertAdjacentHtml(where, text); + _insertAdjacentHtml(where, html); } else { - _insertAdjacentNode(where, new DocumentFragment.html(text)); + _insertAdjacentNode(where, new DocumentFragment.html(html)); } } @@ -636,7 +636,9 @@ $else $endif - @Creates('Null') +$if DART2JS + @Creates('Null') // Set from Dart code; does not instantiate a native type. +$endif Map<String, StreamSubscription> _attributeBindings; // TODO(jmesserly): I'm concerned about adding these to every element.
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate index 04b03cd..287151f 100644 --- a/tools/dom/templates/html/impl/impl_Node.darttemplate +++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -57,11 +57,12 @@ void addAll(Iterable<Node> iterable) { if (iterable is _ChildNodeListLazy) { - if (!identical(iterable._this, _this)) { + _ChildNodeListLazy otherList = iterable; + if (!identical(otherList._this, _this)) { // Optimized route for copying between nodes. - for (var i = 0, len = iterable.length; i < len; ++i) { + for (var i = 0, len = otherList.length; i < len; ++i) { // Should use $dom_firstChild, Bug 8886. - _this.append(iterable[0]); + _this.append(otherList[0]); } } return;
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate index 8ac5997..d196fc1 100644 --- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate +++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -44,7 +44,7 @@ return _cssClassSet; } - List<Element> get children => new FilteredElementList(this); + List<Element> get children => new FilteredElementList<Element>(this); void set children(List<Element> value) { final children = this.children;
diff --git a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate index 1e4b239..dcad713 100644 --- a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate +++ b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
@@ -230,7 +230,7 @@ * * [WheelEvent.deltaX](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaX) from the W3C. */ @DomName('WheelEvent.deltaX') - num get deltaX => -$dom_wheelDeltaX; + num get deltaX => -_wheelDeltaX; /** * The amount that is expected to scroll vertically, in units determined by @@ -241,6 +241,6 @@ * * [WheelEvent.deltaY](http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-WheelEvent-deltaY) from the W3C. */ @DomName('WheelEvent.deltaY') - num get deltaY => -$dom_wheelDeltaY; + num get deltaY => -_wheelDeltaY; $endif }
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate index f60f7d495..9c8f8ce 100644 --- a/tools/dom/templates/html/impl/impl_Window.darttemplate +++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -152,7 +152,7 @@ return _requestAnimationFrame(callback); } - void cancelAnimationFrame(id) { + void cancelAnimationFrame(int id) { _ensureRequestAnimationFrame(); _cancelAnimationFrame(id); } @@ -205,7 +205,7 @@ this, this, this); @DomName('Window.console') - Console get console => Console.safeConsole; + Console get console => Console._safeConsole; /// Checks if _setImmediate is supported. static bool get _supportsSetImmediate =>
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi index abced4d..05a3bad 100644 --- a/tools/gyp/configurations_make.gypi +++ b/tools/gyp/configurations_make.gypi
@@ -55,6 +55,7 @@ '-Wno-psabi', # suppresses va_list warning '-fno-strict-overflow', ], + 'ldflags': ['-static'], }], ['_toolset=="host"', { 'cflags': ['-m32', '-msse2'],
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart index 4261cec..94c33bb 100644 --- a/tools/testing/dart/test_runner.dart +++ b/tools/testing/dart/test_runner.dart
@@ -846,7 +846,7 @@ } else if (fields[ERROR_LEVEL] == 'WARNING') { // We only care about testing Static type warnings // ignore all others - if (fields[ERROR_TYPE] == 'STATIC_TYPE') { + if (fields[ERROR_TYPE] == 'STATIC_TYPE' || fields[ERROR_TYPE] == 'STATIC_TYPE_WARNING') { staticWarnings.add(fields[FORMATTED_ERROR]); } } @@ -970,6 +970,20 @@ } } + +/** Modifies the --timeout=XX parameter passed to run_selenium.py */ +List<String> _modifySeleniumTimeout(List<String> arguments, int timeout) { + return arguments.map((argument) { + if (argument.startsWith('--timeout=')) { + return "--timeout=$timeout"; + } else { + return argument; + } + }).toList(); + return; +} + + /** * A RunningProcess actually runs a test, getting the command lines from * its [TestCase], starting the test process (and first, a compilation @@ -1011,8 +1025,10 @@ _commandComplete(0); } else { var processOptions = _createProcessOptions(); + var commandArguments = _modifySeleniumTimeout(command.arguments, + testCase.timeout); Future processFuture = io.Process.start(command.executable, - command.arguments, + commandArguments, processOptions); processFuture.then((io.Process process) { // Close stdin so that tests that try to block on input will fail. @@ -1177,7 +1193,8 @@ "environments for batch runner tests!"); } - var line = _createArgumentsLine(testCase.batchTestArguments); + var line = _createArgumentsLine(testCase.batchTestArguments, + testCase.timeout); _process.stdin.write(line); _stdoutSubscription.resume(); _stderrSubscription.resume(); @@ -1185,7 +1202,8 @@ _stderrCompleter.future]).then((_) => _reportResult()); } - String _createArgumentsLine(List<String> arguments) { + String _createArgumentsLine(List<String> arguments, int timeout) { + arguments = _modifySeleniumTimeout(arguments, timeout); return arguments.join(' ').concat('\n'); }
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart index bd0ddbd..329d087 100644 --- a/tools/testing/dart/test_suite.dart +++ b/tools/testing/dart/test_suite.dart
@@ -998,7 +998,8 @@ args = [ dartDir.append('tools/testing/run_selenium.py').toNativePath(), '--browser=$runtime', - '--timeout=${configuration["timeout"]~/2}', + // NOTE: This value will be overridden by the test runner + '--timeout=${configuration['timeout']}', '--out=$fullHtmlPath']; if (runtime == 'dartium') { args.add('--executable=$dartiumFilename');