Version 0.5.19.0
svn merge -r 24018:24061 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@24070 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index c7360e9..d65c4e0 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -104,13 +104,7 @@
cmds = [sys.executable, toolsBuildScript,
'--mode=' + mode, '--revision=' + version,
'--name=' + name, '--out=' + outdir]
- local_env = os.environ.copy()
- # The buildbot sets AWS_CREDENTIAL_FILE/BOTO_CONFIG to the chromium specific
- # file, we use the one in home.
- if 'BOTO_CONFIG' in local_env:
- del local_env['BOTO_CONFIG']
- if 'AWS_CREDENTIAL_FILE' in local_env:
- del local_env['AWS_CREDENTIAL_FILE']
+ local_env = EnvironmentWithoutBotoConfig()
#if 'linux' in name:
# javahome = os.path.join(os.path.expanduser('~'), 'jdk1.6.0_25')
# local_env['JAVA_HOME'] = javahome
@@ -119,20 +113,31 @@
return subprocess.call(cmds, env=local_env)
-def ProcessBot(name, target):
+def EnvironmentWithoutBotoConfig(environment=None):
+ # The buildbot sets AWS_CREDENTIAL_FILE/BOTO_CONFIG to the chromium specific
+ # file, we use the one in home.
+ custom_env = dict(environment or os.environ)
+ if 'BOTO_CONFIG' in custom_env:
+ del custom_env['BOTO_CONFIG']
+ if 'AWS_CREDENTIAL_FILE' in custom_env:
+ del custom_env['AWS_CREDENTIAL_FILE']
+ return custom_env
+
+def ProcessBot(name, target, custom_env=None):
'''
Build and test the named bot target (compiler, android, pub). We look for
the supporting script in tools/bots/ to run the tests and build.
'''
print 'Process%s' % target.capitalize()
- has_shell=False
+ has_shell = False
+ environment = custom_env or os.environ
if '-win' in name:
# In Windows we need to run in the shell, so that we have all the
# environment variables available.
- has_shell=True
+ has_shell = True
return subprocess.call([sys.executable,
os.path.join('tools', 'bots', target + '.py')],
- env=os.environ, shell=has_shell)
+ env=environment, shell=has_shell)
def FixJavaHome():
buildbot_javahome = os.getenv('BUILDBOT_JAVA_HOME')
@@ -222,7 +227,8 @@
elif name.startswith('vm-android'):
status = ProcessBot(name, 'android')
elif name.startswith('cross') or name.startswith('target'):
- status = ProcessBot(name, 'cross-vm')
+ status = ProcessBot(name, 'cross-vm',
+ custom_env=EnvironmentWithoutBotoConfig())
else:
status = ProcessBot(name, 'compiler')
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_junit.dart b/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
index 1fa994e..8d43a53 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
@@ -59,7 +59,7 @@
class _IsNotSameAs extends BaseMatcher {
final _expected;
const _IsNotSameAs(this._expected);
- bool matches(item, MatchState matchState) => !identical(item, _expected);
+ bool matches(item, Map matchState) => !identical(item, _expected);
Description describe(Description description) =>
description.add('not same instance as ').addDescriptionOf(_expected);
}
@@ -69,14 +69,14 @@
final String msg;
final expectedValue;
const _EqualsWithMessage(this.msg, this.expectedValue);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item == expectedValue;
}
Description describe(Description mismatchDescription) {
return mismatchDescription.replace(msg);
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
return mismatchDescription.replace(msg).add(" $item != $expectedValue");
}
}
@@ -85,14 +85,14 @@
class _IsTrueWithMessage extends BaseMatcher {
final String msg;
const _IsTrueWithMessage(this.msg);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item == true;
}
Description describe(Description mismatchDescription) {
return mismatchDescription.replace(msg);
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
return mismatchDescription.replace(msg).add(" $item is not true");
}
}
@@ -101,14 +101,14 @@
class _IsFalseWithMessage extends BaseMatcher {
final String msg;
const _IsFalseWithMessage(this.msg);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item == false;
}
Description describe(Description mismatchDescription) {
return mismatchDescription.replace(msg);
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
return mismatchDescription.replace(msg).add(" $item is not false");
}
}
@@ -117,14 +117,14 @@
class _IsNotNullWithMessage extends BaseMatcher {
final String msg;
const _IsNotNullWithMessage(this.msg);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item != null;
}
Description describe(Description mismatchDescription) {
return mismatchDescription.replace(msg);
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
return mismatchDescription.replace(msg).add(" $item is null");
}
}
diff --git a/pkg/http/test/multipart_test.dart b/pkg/http/test/multipart_test.dart
index 78121f6..6153541 100644
--- a/pkg/http/test/multipart_test.dart
+++ b/pkg/http/test/multipart_test.dart
@@ -26,7 +26,7 @@
_BodyMatches(this._pattern);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! http.MultipartRequest) return false;
var future = item.finalize().toBytes().then((bodyBytes) {
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index 6d86985..ed09137 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -149,7 +149,7 @@
_Parse(this._matcher);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! String) return false;
var parsed;
@@ -177,7 +177,7 @@
class _HttpException extends TypeMatcher {
const _HttpException() : super("HttpException");
- bool matches(item, MatchState matchState) => item is HttpException;
+ bool matches(item, Map matchState) => item is HttpException;
}
/// A matcher for RedirectLimitExceededExceptions.
@@ -192,7 +192,7 @@
const _RedirectLimitExceededException() :
super("RedirectLimitExceededException");
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is RedirectException && item.message == "Redirect limit exceeded";
}
@@ -205,5 +205,5 @@
class _SocketException extends TypeMatcher {
const _SocketException() : super("SocketException");
- bool matches(item, MatchState matchState) => item is SocketException;
+ bool matches(item, Map matchState) => item is SocketException;
}
diff --git a/pkg/oauth2/test/utils.dart b/pkg/oauth2/test/utils.dart
index 9198c80..fddcd37 100644
--- a/pkg/oauth2/test/utils.dart
+++ b/pkg/oauth2/test/utils.dart
@@ -54,7 +54,7 @@
class _AuthorizationException extends TypeMatcher {
const _AuthorizationException() : super("AuthorizationException");
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is oauth2.AuthorizationException;
}
@@ -67,6 +67,6 @@
class _ExpirationException extends TypeMatcher {
const _ExpirationException() : super("ExpirationException");
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is oauth2.ExpirationException;
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index ae61138..1a4e87f 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -64,21 +64,6 @@
analyzer_experimental/test/generated/ast_test: Fail, Slow # Issue 11230
unittest/test/instance_test: Fail # http://dartbug.com/11191
-[ $compiler == dart2js && $runtime == d8 && $checked ]
-pathos/test/pathos_io_test: Fail # Issue 11258
-oauth2/*: Fail # Issue 11258
-oauth2/test/utils_test: Pass
-http/*: Fail # Issue 11258
-stack_trace/*: Fail # Issue 11258
-intl/test/date_time_format_file_odd_test: Fail # Issue 11258
-intl/test/date_time_format_file_even_test: Fail # Issue 11258
-intl/test/message_extraction/message_extraction_test: Fail # Issue 11258
-scheduled_test/*: Fail # Issue 11258
-scheduled_test/test/substitute_future_test: Pass
-scheduled_test/test/value_future_test: Pass
-analyzer_experimental/test/error_test: Fail # Issue 11258
-analyzer_experimental/test/services/formatter_test: Fail # Issue 11258
-
[ $compiler == dartc ]
unittest/test/mock_regexp_negative_test: Fail
unittest/test/mock_stepwise_negative_test: Fail
@@ -116,10 +101,13 @@
crypto/test/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692
[ $compiler == dart2js && $browser ]
-pathos/test/pathos_dartium_test: Fail, OK # Issue 6490
+pathos/test/pathos_dartium_test: Fail # Issue 6490
crypto/test/sha256_test: Slow, Pass
crypto/test/sha1_test: Slow, Pass
+[ $compiler == dart2js && $checked ]
+pathos/test/pathos_dartium_test: Crash
+
[ $browser ]
analyzer_experimental/test/error_test: Fail, OK # Uses dart:io.
analyzer_experimental/test/generated/element_test: Fail, OK # Uses dart:io.
diff --git a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
index fcdaacb..07609ff 100644
--- a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
@@ -46,7 +46,7 @@
const _ScheduledCompletes(this._matcher, this._description);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Future) return false;
// TODO(nweiz): parse the stack, figure out on what line these were called,
diff --git a/pkg/scheduled_test/test/descriptor/file_test.dart b/pkg/scheduled_test/test/descriptor/file_test.dart
index 96d4418..5c64586 100644
--- a/pkg/scheduled_test/test/descriptor/file_test.dart
+++ b/pkg/scheduled_test/test/descriptor/file_test.dart
@@ -221,8 +221,8 @@
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"
- "Actual: 'barfoobaz'"
+ "Expected: contains 'baaz'\n"
+ " Actual: 'barfoobaz'"
]), verbose: true);
});
}, passing: ['test 2']);
@@ -263,8 +263,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"
- "Actual: [98, 97, 114, 102, 111, 111, 98, 97, 122]"
+ " Actual: [98, 97, 114, 102, 111, 111, 98, 97, 122]"
]), verbose: true);
});
}, passing: ['test 2']);
diff --git a/pkg/unittest/lib/mock.dart b/pkg/unittest/lib/mock.dart
index 385194f..8b60078 100644
--- a/pkg/unittest/lib/mock.dart
+++ b/pkg/unittest/lib/mock.dart
@@ -136,7 +136,7 @@
* that was used to select the logs that were verified.
*/
String _mockingErrorFormatter(actual, Matcher matcher, String signature,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
var description = new StringDescription();
description.add('Expected ${signature} ').addDescriptionOf(matcher).
add('\n but: ');
@@ -157,7 +157,7 @@
proxy.fail(reason);
}
void failMatch(actual, Matcher matcher, String reason,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
proxy.fail(_mockingErrorFormatter(actual, matcher, reason,
matchState, verbose));
}
@@ -288,7 +288,7 @@
* if it matches this [CallMatcher.
*/
bool matches(String method, List arguments) {
- var matchState = new MatchState();
+ var matchState = {};
if (!nameFilter.matches(method, matchState)) {
return false;
}
@@ -541,7 +541,7 @@
Function entryFilter = _makePredicate(logFilter);
String filterName = _qualifiedName(mockNameFilter, logFilter.toString());
LogEntryList rtn = new LogEntryList(filterName);
- MatchState matchState = new MatchState();
+ var matchState = {};
for (var i = 0; i < logs.length; i++) {
LogEntry entry = logs[i];
if (mockNameFilter.matches(entry.mockName, matchState) &&
@@ -895,7 +895,7 @@
var keyIterator = keys.logs.iterator;
keyIterator.moveNext();
LogEntry keyEntry = keyIterator.current;
- MatchState matchState = new MatchState();
+ Map matchState = {};
for (LogEntry logEntry in logs) {
// If we have a log entry match, copy the saved matches from the
@@ -1000,7 +1000,7 @@
const _TimesMatcher(this.min, [this.max = -1]);
- bool matches(logList, MatchState matchState) => logList.length >= min &&
+ bool matches(logList, Map matchState) => logList.length >= min &&
(max < 0 || logList.length <= max);
Description describe(Description description) {
@@ -1018,7 +1018,7 @@
}
Description describeMismatch(logList, Description mismatchDescription,
- MatchState matchState, bool verbose) =>
+ Map matchState, bool verbose) =>
mismatchDescription.add('was called ${logList.length} times');
}
@@ -1059,7 +1059,7 @@
const _ResultMatcher(this.action, this.value);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! LogEntry) {
return false;
}
@@ -1081,7 +1081,7 @@
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item.action == Action.RETURN || item.action == Action.PROXY) {
mismatchDescription.add('returned ');
} else {
@@ -1139,7 +1139,7 @@
const _ResultSetMatcher(this.action, this.value, this.frequency);
- bool matches(logList, MatchState matchState) {
+ bool matches(logList, Map matchState) {
for (LogEntry entry in logList) {
// normalize the action; PROXY is like RETURN.
Action eaction = entry.action;
@@ -1148,10 +1148,7 @@
}
if (eaction == action && value.matches(entry.value, matchState)) {
if (frequency == _Frequency.NONE) {
- matchState.state = {
- 'state' : matchState.state,
- 'entry' : entry
- };
+ addStateInfo(matchState, {'entry': entry});
return false;
} else if (frequency == _Frequency.SOME) {
return true;
@@ -1159,10 +1156,7 @@
} else {
// Mismatch.
if (frequency == _Frequency.ALL) { // We need just one mismatch to fail.
- matchState.state = {
- 'state' : matchState.state,
- 'entry' : entry
- };
+ addStateInfo(matchState, {'entry': entry});
return false;
}
}
@@ -1185,9 +1179,9 @@
}
Description describeMismatch(logList, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (frequency != _Frequency.SOME) {
- LogEntry entry = matchState.state['entry'];
+ LogEntry entry = matchState['entry'];
if (entry.action == Action.RETURN || entry.action == Action.PROXY) {
mismatchDescription.add('returned');
} else {
@@ -1195,7 +1189,7 @@
}
mismatchDescription.add(' value that ');
value.describeMismatch(entry.value, mismatchDescription,
- matchState.state['state'], verbose);
+ matchState['state'], verbose);
mismatchDescription.add(' at least once');
} else {
mismatchDescription.add('never did');
@@ -1369,7 +1363,7 @@
}
}
bool matchedMethodName = false;
- MatchState matchState = new MatchState();
+ Map matchState = {};
for (String k in _behaviors.keys) {
Behavior b = _behaviors[k];
if (b.matcher.nameFilter.matches(method, matchState)) {
diff --git a/pkg/unittest/lib/src/basematcher.dart b/pkg/unittest/lib/src/basematcher.dart
index a74928c..099494d 100644
--- a/pkg/unittest/lib/src/basematcher.dart
+++ b/pkg/unittest/lib/src/basematcher.dart
@@ -5,23 +5,6 @@
part of matcher;
/**
- * MatchState is a simple wrapper around an arbitrary object.
- * [Matcher] [matches] methods can use this to store useful
- * information upon match failures, and this information will
- * be passed to [describeMismatch]. Each [Matcher] is responsible
- * for its own use of this state, so the state created by [matches]
- * should be consistent with that expected by [describeMismatch] in
- * the same [Matcher] class, but can vary between classes. The inner
- * state, if set, will typically be a [Map] with a number of key-value
- * pairs containing relevant state information.
- */
-class MatchState {
- var state = null;
-
- MatchState([this.state]);
-}
-
-/**
* BaseMatcher is the base class for all matchers. To implement a new
* matcher, either add a class that implements Matcher or a class that
* extends BaseMatcher. Extending BaseMatcher has the benefit that a
@@ -36,7 +19,7 @@
* [matchState] may be used to return additional info for
* the use of [describeMismatch].
*/
- bool matches(item, MatchState matchState);
+ bool matches(item, Map matchState);
/**
* Creates a textual description of a matcher,
@@ -50,8 +33,11 @@
* It does not check whether the [item] fails the match, as it is
* only called after a failed match. There may be additional info
* about the mismatch in [matchState].
+ * The base matcher does not add anything as the actual value is
+ * typically sufficient, but matchers that can add valuable info
+ * should override this.
*/
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) =>
- mismatchDescription.add('was ').addDescriptionOf(item);
+ Map matchState, bool verbose) =>
+ mismatchDescription;
}
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 25767e3..4b5bdbb 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -12,7 +12,7 @@
class _Empty extends BaseMatcher {
const _Empty();
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is Map || item is Iterable) {
return item.isEmpty;
} else if (item is String) {
@@ -33,14 +33,14 @@
class _IsNull extends BaseMatcher {
const _IsNull();
- bool matches(item, MatchState matchState) => item == null;
+ bool matches(item, Map matchState) => item == null;
Description describe(Description description) =>
description.add('null');
}
class _IsNotNull extends BaseMatcher {
const _IsNotNull();
- bool matches(item, MatchState matchState) => item != null;
+ bool matches(item, Map matchState) => item != null;
Description describe(Description description) =>
description.add('not null');
}
@@ -53,14 +53,14 @@
class _IsTrue extends BaseMatcher {
const _IsTrue();
- bool matches(item, MatchState matchState) => item == true;
+ bool matches(item, Map matchState) => item == true;
Description describe(Description description) =>
description.add('true');
}
class _IsFalse extends BaseMatcher {
const _IsFalse();
- bool matches(item, MatchState matchState) => item == false;
+ bool matches(item, Map matchState) => item == false;
Description describe(Description description) =>
description.add('false');
}
@@ -74,7 +74,7 @@
class _IsSameAs extends BaseMatcher {
final _expected;
const _IsSameAs(this._expected);
- bool matches(item, MatchState matchState) => identical(item, _expected);
+ bool matches(item, Map matchState) => identical(item, _expected);
// If all types were hashable we could show a hash here.
Description describe(Description description) =>
description.add('same instance as ').addDescriptionOf(_expected);
@@ -97,76 +97,77 @@
_DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit;
- String _compareIterables(expected, actual, matcher, depth) {
+ // Returns a pair (reason, location)
+ List _compareIterables(expected, actual, matcher, depth, location) {
if (actual is !Iterable) {
- return 'is not Iterable';
+ return ['is not Iterable', location];
}
var expectedIterator = expected.iterator;
var actualIterator = actual.iterator;
- var position = 0;
- String reason = null;
- while (reason == null) {
+ var index = 0;
+ while (true) {
if (expectedIterator.moveNext()) {
+ var newLocation = '${location}[${index}]';
if (actualIterator.moveNext()) {
- Description r = matcher(expectedIterator.current,
- actualIterator.current,
- 'mismatch at position ${position}',
+ var rp = matcher(expectedIterator.current,
+ actualIterator.current, newLocation,
depth);
- if (r != null) reason = r.toString();
- ++position;
+ if (rp != null) return rp;
+ ++index;
} else {
- reason = 'shorter than expected';
+ return ['shorter than expected', newLocation];
}
} else if (actualIterator.moveNext()) {
- reason = 'longer than expected';
+ return ['longer than expected', newLocation];
} else {
return null;
}
}
- return reason;
+ return null;
}
- Description _recursiveMatch(expected, actual, String location, int depth) {
- Description reason = null;
+ List _recursiveMatch(expected, actual, String location, int depth) {
+ String reason = null;
// If _limit is 1 we can only recurse one level into object.
bool canRecurse = depth == 0 || _limit > 1;
if (expected == actual) {
// Do nothing.
} else if (depth > _limit) {
- reason = new StringDescription('recursion depth limit exceeded');
+ reason = 'recursion depth limit exceeded';
} else {
if (expected is Iterable && canRecurse) {
- String r = _compareIterables(expected, actual,
- _recursiveMatch, depth+1);
- if (r != null) reason = new StringDescription(r);
+ List result = _compareIterables(expected, actual,
+ _recursiveMatch, depth + 1, location);
+ if (result != null) {
+ reason = result[0];
+ location = result[1];
+ }
} else if (expected is Map && canRecurse) {
if (actual is !Map) {
- reason = new StringDescription('expected a map');
+ reason = 'expected a map';
} else {
var err = (expected.length == actual.length) ? '' :
- 'different map lengths; ';
+ 'has different length and ';
for (var key in expected.keys) {
if (!actual.containsKey(key)) {
- reason = new StringDescription(err);
- reason.add('missing map key ');
- reason.addDescriptionOf(key);
+ reason = '${err}is missing map key \'$key\'';
break;
}
}
if (reason == null) {
for (var key in actual.keys) {
if (!expected.containsKey(key)) {
- reason = new StringDescription(err);
- reason.add('extra map key ');
- reason.addDescriptionOf(key);
+ reason = '${err}has extra map key \'$key\'';
break;
}
}
if (reason == null) {
for (var key in expected.keys) {
- reason = _recursiveMatch(expected[key], actual[key],
- 'with key <${key}> ${location}', depth+1);
- if (reason != null) {
+ var rp = _recursiveMatch(expected[key], actual[key],
+ "${location}['${key}']", depth+1);
+ if (rp != null) {
+ reason = rp[0];
+ location = rp[1];
break;
}
}
@@ -174,38 +175,62 @@
}
}
} else {
- reason = new StringDescription();
+ var description = new StringDescription();
// If we have recursed, show the expected value too; if not,
// expect() will show it for us.
if (depth > 0) {
- reason.add('expected ');
- reason.addDescriptionOf(expected).add(' but ');
+ description.add('was ').
+ addDescriptionOf(actual).
+ add(' instead of ').
+ addDescriptionOf(expected);
+ reason = description.toString();
+ } else {
+ reason = ''; // We're not adding any value to the actual value.
}
- reason.add('was ');
- reason.addDescriptionOf(actual);
}
}
- if (reason != null && location.length > 0) {
- reason.add(' ').add(location);
+ if (reason == null) return null;
+ return [reason, location];
+ }
+
+ String _match(expected, actual, Map matchState) {
+ var rp = _recursiveMatch(expected, actual, '', 0);
+ if (rp == null) return null;
+ var reason;
+ if (rp[0].length > 0) {
+ if (rp[1].length > 0) {
+ reason = "${rp[0]} at location ${rp[1]}";
+ } else {
+ reason = rp[0];
+ }
+ } else {
+ reason = '';
}
+ // Cache the failure reason in the matchState.
+ addStateInfo(matchState, {'reason': reason});
return reason;
}
- String _match(expected, actual) {
- Description reason = _recursiveMatch(expected, actual, '', 0);
- return reason == null ? null : reason.toString();
- }
-
- // TODO(gram) - see if we can make use of matchState here to avoid
- // recursing again in describeMismatch.
- bool matches(item, MatchState matchState) => _match(_expected, item) == null;
+ bool matches(item, Map matchState) =>
+ _match(_expected, item, matchState) == null;
Description describe(Description description) =>
description.addDescriptionOf(_expected);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) =>
- mismatchDescription.add(_match(_expected, item));
+ Map matchState, bool verbose) {
+ var reason = matchState['reason'];
+ // If we didn't get a good reason, that would normally be a
+ // simple 'is <value>' message. We only add that if the mismatch
+ // description is non empty (so we are supplementing the mismatch
+ // description).
+ if (reason.length == 0 && mismatchDescription.length > 0) {
+ mismatchDescription.add('is ').addDescriptionOf(item);
+ } else {
+ mismatchDescription.add(reason);
+ }
+ return mismatchDescription;
+ }
}
/** A special equality matcher for strings. */
@@ -216,18 +241,18 @@
bool get showActualValue => true;
- bool matches(item, MatchState mismatchState) => _value == item;
+ bool matches(item, Map matchState) => _value == item;
Description describe(Description description) =>
description.addDescriptionOf(_value);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is! String) {
- return mismatchDescription.addDescriptionOf(item).add(' not a string');
+ return mismatchDescription.addDescriptionOf(item).add('is not a string');
} else {
var buff = new StringBuffer();
- buff.write('Strings are not equal.');
+ buff.write('is different.');
var escapedItem = _escape(item);
var escapedValue = _escape(_value);
int minLength = escapedItem.length < escapedValue.length ?
@@ -257,7 +282,7 @@
_writeTrailing(buff, escapedItem, start);
buff.write('\n ');
for (int i = (start > 10 ? 14 : start); i > 0; i--) buff.write(' ');
- buff.write('^\n Differ at position $start');
+ buff.write('^\n Differ at offset $start');
}
return mismatchDescription.replace(buff.toString());
@@ -291,7 +316,7 @@
class _IsAnything extends BaseMatcher {
const _IsAnything();
- bool matches(item, MatchState matchState) => true;
+ bool matches(item, Map matchState) => true;
Description describe(Description description) =>
description.add('anything');
}
@@ -321,7 +346,7 @@
class isInstanceOf<T> extends BaseMatcher {
final String _name;
const isInstanceOf([name = 'specified type']) : this._name = name;
- bool matches(obj, MatchState matchState) => obj is T;
+ bool matches(obj, Map matchState) => obj is T;
// The description here is lame :-(
Description describe(Description description) =>
description.add('an instance of ${_name}');
@@ -376,7 +401,7 @@
const Throws([Matcher matcher]) :
this._matcher = matcher;
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Function && item is! Future) return false;
if (item is Future) {
var done = wrapAsync((fn) => fn());
@@ -409,10 +434,7 @@
if (_matcher == null ||_matcher.matches(e, matchState)) {
return true;
} else {
- matchState.state = {
- 'exception' :e,
- 'stack': s
- };
+ addStateInfo(matchState, {'exception': e, 'stack': s});
return false;
}
}
@@ -420,29 +442,26 @@
Description describe(Description description) {
if (_matcher == null) {
- return description.add("throws an exception");
+ return description.add("throws");
} else {
- return description.add('throws an exception which matches ').
- addDescriptionOf(_matcher);
+ return description.add('throws ').addDescriptionOf(_matcher);
}
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState,
+ Map matchState,
bool verbose) {
if (item is! Function && item is! Future) {
- return mismatchDescription.add(' not a Function or Future');
- } else if (_matcher == null || matchState.state == null) {
- return mismatchDescription.add(' no exception');
+ return mismatchDescription.add('is not a Function or Future');
+ } else if (_matcher == null || matchState['exception'] == null) {
+ return mismatchDescription.add('did not throw');
} else {
- mismatchDescription.
- add(' exception ').addDescriptionOf(matchState.state['exception']);
+ mismatchDescription. add('threw ').
+ addDescriptionOf(matchState['exception']);
if (verbose) {
- mismatchDescription.add(' at ').
- add(matchState.state['stack'].toString());
+ mismatchDescription.add(' at ').add(matchState['stack'].toString());
}
- mismatchDescription.add(' does not match ').addDescriptionOf(_matcher);
- return mismatchDescription;
+ return mismatchDescription;
}
}
}
@@ -450,15 +469,12 @@
class _ReturnsNormally extends BaseMatcher {
const _ReturnsNormally();
- bool matches(f, MatchState matchState) {
+ bool matches(f, Map matchState) {
try {
f();
return true;
} catch (e, s) {
- matchState.state = {
- 'exception' : e,
- 'stack': s
- };
+ addStateInfo(matchState, {'exception': e, 'stack': s});
return false;
}
}
@@ -467,15 +483,13 @@
description.add("return normally");
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState,
+ Map matchState,
bool verbose) {
- mismatchDescription.add(' threw ').
- addDescriptionOf(matchState.state['exception']);
- if (verbose) {
- mismatchDescription.add(' at ').
- add(matchState.state['stack'].toString());
- }
- return mismatchDescription;
+ mismatchDescription.add('threw ').addDescriptionOf(matchState['exception']);
+ if (verbose) {
+ mismatchDescription.add(' at ').add(matchState['stack'].toString());
+ }
+ return mismatchDescription;
}
}
@@ -516,7 +530,7 @@
class _FormatException extends TypeMatcher {
const _FormatException() : super("FormatException");
- bool matches(item, MatchState matchState) => item is FormatException;
+ bool matches(item, Map matchState) => item is FormatException;
}
/** A matcher for Exceptions. */
@@ -527,7 +541,7 @@
class _Exception extends TypeMatcher {
const _Exception() : super("Exception");
- bool matches(item, MatchState matchState) => item is Exception;
+ bool matches(item, Map matchState) => item is Exception;
}
/** A matcher for ArgumentErrors. */
@@ -539,7 +553,7 @@
class _ArgumentError extends TypeMatcher {
const _ArgumentError() : super("ArgumentError");
- bool matches(item, MatchState matchState) => item is ArgumentError;
+ bool matches(item, Map matchState) => item is ArgumentError;
}
/** A matcher for RangeErrors. */
@@ -551,7 +565,7 @@
class _RangeError extends TypeMatcher {
const _RangeError() : super("RangeError");
- bool matches(item, MatchState matchState) => item is RangeError;
+ bool matches(item, Map matchState) => item is RangeError;
}
/** A matcher for NoSuchMethodErrors. */
@@ -563,7 +577,7 @@
class _NoSuchMethodError extends TypeMatcher {
const _NoSuchMethodError() : super("NoSuchMethodError");
- bool matches(item, MatchState matchState) => item is NoSuchMethodError;
+ bool matches(item, Map matchState) => item is NoSuchMethodError;
}
/** A matcher for UnimplementedErrors. */
@@ -575,7 +589,7 @@
class _UnimplementedError extends TypeMatcher {
const _UnimplementedError() : super("UnimplementedError");
- bool matches(item, MatchState matchState) => item is UnimplementedError;
+ bool matches(item, Map matchState) => item is UnimplementedError;
}
/** A matcher for UnsupportedError. */
@@ -587,7 +601,7 @@
class _UnsupportedError extends TypeMatcher {
const _UnsupportedError() :
super("UnsupportedError");
- bool matches(item, MatchState matchState) => item is UnsupportedError;
+ bool matches(item, Map matchState) => item is UnsupportedError;
}
/** A matcher for StateErrors. */
@@ -599,7 +613,7 @@
class _StateError extends TypeMatcher {
const _StateError() : super("StateError");
- bool matches(item, MatchState matchState) => item is StateError;
+ bool matches(item, Map matchState) => item is StateError;
}
@@ -608,7 +622,7 @@
class _IsMap extends TypeMatcher {
const _IsMap() : super("Map");
- bool matches(item, MatchState matchState) => item is Map;
+ bool matches(item, Map matchState) => item is Map;
}
/** A matcher for List types. */
@@ -616,7 +630,7 @@
class _IsList extends TypeMatcher {
const _IsList() : super("List");
- bool matches(item, MatchState matchState) => item is List;
+ bool matches(item, Map matchState) => item is List;
}
/**
@@ -630,8 +644,16 @@
final Matcher _matcher;
const _HasLength([Matcher matcher = null]) : this._matcher = matcher;
- bool matches(item, MatchState matchState) {
- return _matcher.matches(item.length, matchState);
+ bool matches(item, Map matchState) {
+ try {
+ // 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 _matcher.matches(item.length, matchState);
+ }
+ } catch (e) {
+ return false;
+ }
}
Description describe(Description description) =>
@@ -639,17 +661,16 @@
addDescriptionOf(_matcher);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool 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.
+ // property; we use the same trick as in matches().
if (item.length * item.length >= 0) {
- return mismatchDescription.add('had length of ').
+ return mismatchDescription.add('has length of ').
addDescriptionOf(item.length);
}
} catch (e) {
- return mismatchDescription.add('had no length property');
+ return mismatchDescription.add('has no length property');
}
}
}
@@ -670,7 +691,7 @@
const _Contains(this._expected);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is String) {
return item.indexOf(_expected) >= 0;
} else if (item is Iterable) {
@@ -687,6 +708,16 @@
Description describe(Description description) =>
description.add('contains ').addDescriptionOf(_expected);
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ if (item is String || item is Iterable || item is Map) {
+ return super.describeMismatch(item, mismatchDescription, matchState,
+ verbose);
+ } else {
+ return mismatchDescription.add('is not a string, map or iterable');
+ }
+ }
}
/**
@@ -701,7 +732,7 @@
const _In(this._expected);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (_expected is String) {
return _expected.indexOf(item) >= 0;
} else if (_expected is Iterable) {
@@ -732,7 +763,7 @@
const _Predicate(this._matcher, this._description);
- bool matches(item, MatchState matchState) => _matcher(item);
+ bool matches(item, Map matchState) => _matcher(item);
Description describe(Description description) =>
description.add(_description);
@@ -770,10 +801,10 @@
/** Override this to extract the interesting feature.*/
featureValueOf(actual) => actual;
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
var f = featureValueOf(item);
if (_matcher.matches(f, matchState)) return true;
- matchState.state = { 'innerState': matchState.state, 'feature': f };
+ addStateInfo(matchState, {'feature': f});
return false;
}
@@ -781,10 +812,16 @@
description.add(_featureDescription).add(' ').addDescriptionOf(_matcher);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
- mismatchDescription.add(_featureName).add(' ');
- _matcher.describeMismatch(matchState.state['feature'], mismatchDescription,
- matchState.state['innerState'], verbose);
+ Map matchState, bool verbose) {
+ mismatchDescription.add('has ').add(_featureName).add(' with value ').
+ addDescriptionOf(matchState['feature']);
+ var innerDescription = new StringDescription();
+ _matcher.describeMismatch(matchState['feature'], innerDescription,
+ matchState['state'], verbose);
+ if (innerDescription.length > 0) {
+ mismatchDescription.add(' which ').add(innerDescription.toString());
+ }
return mismatchDescription;
}
}
+
diff --git a/pkg/unittest/lib/src/description.dart b/pkg/unittest/lib/src/description.dart
index cde5243..6c43077 100644
--- a/pkg/unittest/lib/src/description.dart
+++ b/pkg/unittest/lib/src/description.dart
@@ -17,11 +17,13 @@
_out = init;
}
+ int get length => _out.length;
+
/** Get the description as a string. */
String toString() => _out;
- /** Append some plain [text] to the description. */
- Description add(String text) {
+ /** Append [text] to the description. */
+ Description add(text) {
_out = '${_out}${text}';
return this;
}
diff --git a/pkg/unittest/lib/src/expect.dart b/pkg/unittest/lib/src/expect.dart
index 562eb24..92eb9c4 100644
--- a/pkg/unittest/lib/src/expect.dart
+++ b/pkg/unittest/lib/src/expect.dart
@@ -17,6 +17,17 @@
}
/**
+ * Useful utility for nesting match states.
+ */
+
+void addStateInfo(Map matchState, Map values) {
+ var innerState = new Map.from(matchState);
+ matchState.clear();
+ matchState['state'] = innerState;
+ matchState.addAll(values);
+}
+
+/**
* Some matchers, like those for Futures and exception testing,
* can fail in asynchronous sections, and throw exceptions.
* A user of this library will typically want to catch and handle
@@ -51,7 +62,7 @@
bool verbose : false}) {
matcher = wrapMatcher(matcher);
bool doesMatch;
- var matchState = new MatchState();
+ var matchState = {};
try {
doesMatch = matcher.matches(actual, matchState);
} catch (e, trace) {
@@ -105,7 +116,7 @@
throw new TestFailure(reason);
}
void failMatch(actual, Matcher matcher, String reason,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
fail(_assertErrorFormatter(actual, matcher, reason, matchState, verbose));
}
}
@@ -135,16 +146,17 @@
// The default error formatter implementation.
String _defaultErrorFormatter(actual, Matcher matcher, String reason,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
var description = new StringDescription();
description.add('Expected: ').addDescriptionOf(matcher).add('\n');
+ description.add(' Actual: ').addDescriptionOf(actual);
var mismatchDescription = new StringDescription();
matcher.describeMismatch(actual, mismatchDescription, matchState, verbose);
- description.add(' But: ')
- .add(mismatchDescription.toString()).add('.\n');
- description.add('Actual: ').addDescriptionOf(actual);
+ if (mismatchDescription.length > 0) {
+ description.add(' Which: ${mismatchDescription}\n');
+ }
if (reason != null) {
description.add(reason).add('\n');
}
diff --git a/pkg/unittest/lib/src/future_matchers.dart b/pkg/unittest/lib/src/future_matchers.dart
index f92625a..38f98ed 100644
--- a/pkg/unittest/lib/src/future_matchers.dart
+++ b/pkg/unittest/lib/src/future_matchers.dart
@@ -36,7 +36,7 @@
const _Completes(this._matcher, this._id);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Future) return false;
var done = wrapAsync((fn) => fn(), _id);
diff --git a/pkg/unittest/lib/src/interfaces.dart b/pkg/unittest/lib/src/interfaces.dart
index 909c93e..660c49f 100644
--- a/pkg/unittest/lib/src/interfaces.dart
+++ b/pkg/unittest/lib/src/interfaces.dart
@@ -16,7 +16,7 @@
* error formatter with another.
*/
typedef String ErrorFormatter(actual, Matcher matcher, String reason,
- MatchState matchState, bool verbose);
+ Map matchState, bool verbose);
/**
* Matchers build up their error messages by appending to
@@ -58,7 +58,7 @@
* and may be used to add details about the mismatch that are too
* costly to determine in [describeMismatch].
*/
- bool matches(item, MatchState matchState);
+ bool matches(item, Map matchState);
/** This builds a textual description of the matcher. */
Description describe(Description description);
@@ -66,7 +66,7 @@
/**
* This builds a textual description of a specific mismatch. [item]
* is the value that was tested by [matches]; [matchState] is
- * the [MatchState] that was passed to and supplemented by [matches]
+ * the [Map] that was passed to and supplemented by [matches]
* with additional information about the mismact, and [mismatchDescription]
* is the [Description] that is being built to decribe the mismatch.
* A few matchers make use of the [verbose] flag to provide detailed
@@ -74,7 +74,7 @@
* diagnosing failures, such as stack traces.
*/
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose);
+ Map matchState, bool verbose);
}
/**
@@ -96,6 +96,6 @@
* an [ErrorFormatter]) and then call [fail] with this message.
*/
void failMatch(actual, Matcher matcher, String reason,
- MatchState matchState, bool verbose);
+ Map matchState, bool verbose);
}
diff --git a/pkg/unittest/lib/src/iterable_matchers.dart b/pkg/unittest/lib/src/iterable_matchers.dart
index 65bc610..f7bddf0 100644
--- a/pkg/unittest/lib/src/iterable_matchers.dart
+++ b/pkg/unittest/lib/src/iterable_matchers.dart
@@ -15,18 +15,14 @@
_EveryElement(Matcher this._matcher);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Iterable) {
return false;
}
var i = 0;
for (var element in item) {
if (!_matcher.matches(element, matchState)) {
- matchState.state = {
- 'index': i,
- 'element': element,
- 'state': matchState.state
- };
+ addStateInfo(matchState, {'index': i, 'element': element});
return false;
}
++i;
@@ -35,16 +31,26 @@
}
Description describe(Description description) =>
- description.add('every element ').addDescriptionOf(_matcher);
+ description.add('every element(').addDescriptionOf(_matcher).add(')');
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
- 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);
+ Map matchState, bool verbose) {
+ if (matchState['index'] != null) {
+ var index = matchState['index'];
+ var element = matchState['element'];
+ mismatchDescription.add('has value ').addDescriptionOf(element).
+ add(' which ');
+ var subDescription = new StringDescription();
+ _matcher.describeMismatch(element, subDescription,
+ matchState['state'], verbose);
+ if (subDescription.length > 0) {
+ mismatchDescription.add(subDescription);
+ } else {
+ mismatchDescription.add("doesn't match ");
+ _matcher.describe(mismatchDescription);
+ }
+ mismatchDescription.add(' at index $index');
+ return mismatchDescription;
}
return super.describeMismatch(item, mismatchDescription,
matchState, verbose);
@@ -62,7 +68,7 @@
_SomeElement(this._matcher);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item.any((e) => _matcher.matches(e, matchState));
}
@@ -86,16 +92,16 @@
_matcher = equals(_expected, 1);
}
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
(item is Iterable) && _matcher.matches(item, matchState);
Description describe(Description description) =>
description.add('equals ').addDescriptionOf(_expected).add(' ordered');
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is !Iterable) {
- return mismatchDescription.add('not an Iterable');
+ return mismatchDescription.add('is not an Iterable');
} else {
return _matcher.describeMismatch(item, mismatchDescription,
matchState, verbose);
@@ -149,7 +155,7 @@
Description reason = new StringDescription();
reason.add('has no match for element ').
addDescriptionOf(expectedElement).
- add(' at position ${expectedPosition}');
+ add(' at index ${expectedPosition}');
return reason.toString();
}
++expectedPosition;
@@ -157,13 +163,13 @@
return null;
}
- bool matches(item, MatchState mismatchState) => (_test(item) == null);
+ bool matches(item, Map mismatchState) => (_test(item) == null);
Description describe(Description description) =>
description.add('equals ').addDescriptionOf(_expected).add(' unordered');
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) =>
+ Map matchState, bool verbose) =>
mismatchDescription.add(_test(item));
}
@@ -174,7 +180,7 @@
abstract class _IterableMatcher extends BaseMatcher {
const _IterableMatcher();
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is! Iterable) {
return mismatchDescription.
addDescriptionOf(item).
@@ -203,7 +209,7 @@
_PairwiseCompare(this._expected, this._comparator, this._description);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Iterable) return false;
if (item.length != _expected.length) return false;
var iterator = item.iterator;
@@ -211,12 +217,8 @@
for (var e in _expected) {
iterator.moveNext();
if (!_comparator(e, iterator.current)) {
- matchState.state = {
- 'index': i,
- 'expected': e,
- 'actual' : iterator.current,
- 'state': matchState.state
- };
+ addStateInfo(matchState, {'index': i, 'expected': e,
+ 'actual': iterator.current});
return false;
}
i++;
@@ -228,18 +230,19 @@
description.add('pairwise $_description ').addDescriptionOf(_expected);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is !Iterable) {
- return mismatchDescription.add('not an Iterable');
+ return mismatchDescription.add('is not an Iterable');
} else if (item.length != _expected.length) {
return mismatchDescription.
- add('length was ${item.length} instead of ${_expected.length}');
+ add('has length ${item.length} instead of ${_expected.length}');
} else {
return mismatchDescription.
- addDescriptionOf(matchState.state["actual"]).
- add(' not $_description ').
- addDescriptionOf(matchState.state["expected"]).
- add(' at position ${matchState.state["index"]}');
+ add('has ').
+ addDescriptionOf(matchState["actual"]).
+ add(' which is not $_description ').
+ addDescriptionOf(matchState["expected"]).
+ add(' at index ${matchState["index"]}');
}
}
}
diff --git a/pkg/unittest/lib/src/map_matchers.dart b/pkg/unittest/lib/src/map_matchers.dart
index 72984f9..91d2f06 100644
--- a/pkg/unittest/lib/src/map_matchers.dart
+++ b/pkg/unittest/lib/src/map_matchers.dart
@@ -14,7 +14,7 @@
const _ContainsValue(this._value);
- bool matches(item, MatchState matchState) => item.containsValue(_value);
+ bool matches(item, Map matchState) => item.containsValue(_value);
Description describe(Description description) =>
description.add('contains value ').addDescriptionOf(_value);
}
@@ -32,7 +32,7 @@
const _ContainsMapping(this._key, Matcher this._valueMatcher);
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item.containsKey(_key) &&
_valueMatcher.matches(item[_key], matchState);
@@ -42,7 +42,7 @@
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (!item.containsKey(_key)) {
return mismatchDescription.add(" doesn't contain key ")
.addDescriptionOf(_key);
diff --git a/pkg/unittest/lib/src/numeric_matchers.dart b/pkg/unittest/lib/src/numeric_matchers.dart
index 84afb49..1ebd33f 100644
--- a/pkg/unittest/lib/src/numeric_matchers.dart
+++ b/pkg/unittest/lib/src/numeric_matchers.dart
@@ -100,7 +100,7 @@
[valueInDescription = true]) :
this._valueInDescription = valueInDescription;
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item == _value) {
return _equalValue;
} else if (item < _value) {
@@ -118,6 +118,12 @@
return description.add(_comparisonDescription);
}
}
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ mismatchDescription.add('is not ');
+ return describe(mismatchDescription);
+ }
}
/**
@@ -132,7 +138,7 @@
const _IsCloseTo(this._value, this._delta);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (!_isNumeric(item)) {
return false;
}
@@ -148,14 +154,14 @@
addDescriptionOf(_value);
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is !num) {
return mismatchDescription.add(' not numeric');
} else {
var diff = item - _value;
if (diff < 0) diff = -diff;
return mismatchDescription.
- add(' differed by ').
+ add(' differs by ').
addDescriptionOf(diff);
}
}
@@ -192,7 +198,7 @@
const _InRange(this._low, this._high,
this._lowMatchValue, this._highMatchValue);
- bool matches(value, MatchState matchState) {
+ bool matches(value, Map matchState) {
if (value is !num) {
return false;
}
@@ -214,7 +220,7 @@
"$_high (${_highMatchValue ? 'inclusive' : 'exclusive'})");
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is !num) {
return mismatchDescription.
addDescriptionOf(item).
diff --git a/pkg/unittest/lib/src/operator_matchers.dart b/pkg/unittest/lib/src/operator_matchers.dart
index c7421b7..dde08f3 100644
--- a/pkg/unittest/lib/src/operator_matchers.dart
+++ b/pkg/unittest/lib/src/operator_matchers.dart
@@ -14,7 +14,7 @@
const _IsNot(Matcher this._matcher);
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
!_matcher.matches(item, matchState);
Description describe(Description description) =>
@@ -78,13 +78,10 @@
const _AllOf(this._matchers);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
for (var matcher in _matchers) {
if (!matcher.matches(item, matchState)) {
- matchState.state = {
- 'matcher': matcher,
- 'state': matchState.state
- };
+ addStateInfo(matchState, {'matcher': matcher});
return false;
}
}
@@ -92,11 +89,10 @@
}
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
- var matcher = matchState.state['matcher'];
+ Map matchState, bool verbose) {
+ var matcher = matchState['matcher'];
matcher.describeMismatch(item, mismatchDescription,
- matchState.state['state'], verbose);
- mismatchDescription.add(" (wasn't ").addDescriptionOf(matcher).add(')');
+ matchState['state'], verbose);
return mismatchDescription;
}
@@ -166,7 +162,7 @@
const _AnyOf(this._matchers);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
for (var matcher in _matchers) {
if (matcher.matches(item, matchState)) {
return true;
diff --git a/pkg/unittest/lib/src/string_matchers.dart b/pkg/unittest/lib/src/string_matchers.dart
index ae79cce..2180e82 100644
--- a/pkg/unittest/lib/src/string_matchers.dart
+++ b/pkg/unittest/lib/src/string_matchers.dart
@@ -18,7 +18,7 @@
_matchValue = _value.toLowerCase();
}
- bool matches(item, MatchState mismatchState) =>
+ bool matches(item, Map matchState) =>
item is String && _matchValue == item.toLowerCase();
Description describe(Description description) =>
@@ -44,17 +44,18 @@
_matchValue = collapseWhitespace(_value);
}
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is String && _matchValue == collapseWhitespace(item);
Description describe(Description description) =>
description.addDescriptionOf(_matchValue).add(' ignoring whitespace');
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is String) {
- return mismatchDescription.add('was ').
- addDescriptionOf(collapseWhitespace(item));
+ return mismatchDescription.add('is ').
+ addDescriptionOf(collapseWhitespace(item)).
+ add(' with whitespace compressed');
} else {
return super.describeMismatch(item, mismatchDescription,
matchState, verbose);
@@ -96,7 +97,7 @@
const _StringStartsWith(this._prefix);
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is String && item.startsWith(_prefix);
Description describe(Description description) =>
@@ -115,7 +116,7 @@
const _StringEndsWith(this._suffix);
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is String && item.endsWith(_suffix);
Description describe(Description description) =>
@@ -139,7 +140,7 @@
const _StringContainsInOrder(this._substrings);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (!(item is String)) {
return false;
}
@@ -178,7 +179,7 @@
}
}
- bool matches(item, MatchState matchState) =>
+ bool matches(item, Map matchState) =>
item is String ? _regexp.hasMatch(item) : false;
Description describe(Description description) =>
@@ -190,7 +191,7 @@
abstract class _StringMatcher extends BaseMatcher {
const _StringMatcher();
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (!(item is String)) {
return mismatchDescription.
addDescriptionOf(item).
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index 7dd1e1a..ec78877 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -863,6 +863,12 @@
/** Signature for a test function. */
typedef dynamic TestFunction();
+/**
+ * A flag that controls whether we hide unittest details in exception stacks.
+ * Useful to disable when debugging unittest or matcher customizations.
+ */
+bool formatStacks = true;
+
// Stack formatting utility. Strips extraneous content from a stack trace.
// Stack frame lines are parsed with a regexp, which has been tested
// in Chrome, Firefox and the VM. If a line fails to be parsed it is
@@ -886,6 +892,7 @@
r'):([:\d]+)[\)]?$'); // Get the line number and optional column number.
String _formatStack(stack) {
+ if (!formatStacks) return "$stack";
var lines;
if (stack is StackTrace) {
lines = stack.toString().split('\n');
diff --git a/pkg/unittest/test/instance_test.dart b/pkg/unittest/test/instance_test.dart
index 1d165d8..cac6ca0 100644
--- a/pkg/unittest/test/instance_test.dart
+++ b/pkg/unittest/test/instance_test.dart
@@ -13,17 +13,17 @@
group('Type Matchers', () {
test('isInstanceOf', () {
shouldFail(0, new isInstanceOf<String>('String'),
- "Expected: an instance of String But: was <0>. Actual: <0>");
+ "Expected: an instance of String Actual: <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 'Y' "
"Actual: <Closure: (dynamic) => dynamic "
- "from Function 'doesThrow': static.>");
+ "from Function 'doesThrow': static.> "
+ "Which: threw 'X'");
});
});
}
diff --git a/pkg/unittest/test/matchers_minified_test.dart b/pkg/unittest/test/matchers_minified_test.dart
index 3fb875d..d9ee642 100644
--- a/pkg/unittest/test/matchers_minified_test.dart
+++ b/pkg/unittest/test/matchers_minified_test.dart
@@ -24,10 +24,9 @@
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>"));
+ r"Expected: throws FormatException +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsArgumentError', () {
@@ -36,10 +35,9 @@
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>"));
+ r"Expected: throws ArgumentError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsRangeError', () {
@@ -48,10 +46,9 @@
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)?>"));
+ r"Expected: throws RangeError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsNoSuchMethodError', () {
@@ -60,10 +57,9 @@
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)?>"));
+ r"Expected: throws NoSuchMethodError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsUnimplementedError', () {
@@ -72,11 +68,9 @@
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)?>"));
+ r"Expected: throws UnimplementedError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsUnsupportedError', () {
@@ -85,10 +79,9 @@
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)?>"));
+ r"Expected: throws UnsupportedError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
test('throwsStateError', () {
@@ -97,10 +90,9 @@
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)?>"));
+ r"Expected: throws StateError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw " + _minifiedName + r":<Exception>"));
});
});
@@ -110,7 +102,7 @@
var e = new SimpleIterable(1);
shouldPass(d, isEmpty);
shouldFail(e, isEmpty,
- matches(r"Expected: empty +But: was " + _minifiedName + r":\[1\]\."));
+ matches(r"Expected: empty +Actual: " + _minifiedName + r":\[1\]"));
});
test('contains', () {
@@ -119,7 +111,7 @@
shouldFail(d, contains(5),
matches(
r"Expected: contains <5> +"
- r"But: was " + _minifiedName + r":\[3, 2, 1\]\."));
+ r"Actual: " + _minifiedName + r":\[3, 2, 1\]"));
});
});
@@ -133,8 +125,9 @@
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"'>"));
+ r"Actual: <Instance of '" + _minifiedName + r"'> +"
+ r"Which: has price with value <10> which is not "
+ r"a value greater than <10>"));
});
});
}
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index e623c5a..ebe87e9 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -20,36 +20,30 @@
test('isTrue', () {
shouldPass(true, isTrue);
- shouldFail(false, isTrue, "Expected: true But: was <false>. "
- "Actual: <false>");
+ shouldFail(false, isTrue, "Expected: true Actual: <false>");
});
test('isFalse', () {
shouldPass(false, isFalse);
- shouldFail(10, isFalse, "Expected: false But: was <10>. "
- "Actual: <10>");
- shouldFail(true, isFalse, "Expected: false But: was <true>. "
- "Actual: <true>");
+ shouldFail(10, isFalse, "Expected: false Actual: <10>");
+ shouldFail(true, isFalse, "Expected: false Actual: <true>");
});
test('isNull', () {
shouldPass(null, isNull);
- shouldFail(false, isNull, "Expected: null But: was <false>. "
- "Actual: <false>");
+ shouldFail(false, isNull, "Expected: null Actual: <false>");
});
test('isNotNull', () {
shouldPass(false, isNotNull);
- shouldFail(null, isNotNull, "Expected: not null But: was <null>. "
- "Actual: <null>");
+ shouldFail(null, isNotNull, "Expected: not null Actual: <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 {}. "
- "Actual: {}");
+ shouldFail(b, same(a), "Expected: same instance as {} Actual: {}");
});
test('equals', () {
@@ -64,41 +58,44 @@
shouldPass(0, anything);
shouldPass(null, anything);
shouldPass(a, anything);
- shouldFail(a, isNot(anything), "Expected: not anything "
- "But: was {}. Actual: {}");
+ shouldFail(a, isNot(anything), "Expected: not anything Actual: {}");
});
test('throws', () {
shouldFail(doesNotThrow, throws,
matches(
- r"Expected: throws an exception +But: no exception\."
- r"Actual: <Closure(: \(dynamic\) => dynamic "
- r"from Function 'doesNotThrow': static\.)?>"));
+ r"Expected: throws"
+ r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesNotThrow': static\.)?>"
+ r" Which: did not throw"));
shouldPass(doesThrow, throws);
shouldFail(true, throws,
- "Expected: throws an exception But: not a Function or Future. "
- "Actual: <true>");
+ "Expected: throws"
+ " Actual: <true>"
+ " Which: is not a Function or Future");
});
test('throwsA', () {
shouldPass(doesThrow, throwsA(equals('X')));
shouldFail(doesThrow, throwsA(equals('Y')),
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\.)?>"));
+ r"Expected: throws 'Y'"
+ r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesThrow': static\.)?>"
+ r" Which: threw 'X'"));
});
test('returnsNormally', () {
shouldPass(doesNotThrow, returnsNormally);
shouldFail(doesThrow, returnsNormally,
matches(
- r"Expected: return normally +But: threw 'X'\."
- r"Actual: <Closure(: \(dynamic\) => dynamic "
- r"from Function 'doesThrow': static\.)?>"));
+ r"Expected: return normally"
+ r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r"from Function 'doesThrow': static\.)?>"
+ r" Which: threw 'X'"));
});
+
test('hasLength', () {
var a = new Map();
var b = new List();
@@ -107,43 +104,66 @@
shouldPass('a', hasLength(1));
shouldFail(0, hasLength(0), new PrefixMatcher(
"Expected: an object with length of <0> "
- "But: had no length property."
- "Actual: <0>"));
+ "Actual: <0> "
+ "Which: has no length property"));
b.add(0);
shouldPass(b, hasLength(1));
shouldFail(b, hasLength(2),
"Expected: an object with length of <2> "
- "But: had length of <1>. "
- "Actual: [0]");
+ "Actual: [0] "
+ "Which: has length of <1>");
b.add(0);
shouldFail(b, hasLength(1),
"Expected: an object with length of <1> "
- "But: had length of <2>. "
- "Actual: [0, 0]");
+ "Actual: [0, 0] "
+ "Which: has length of <2>");
shouldPass(b, hasLength(2));
});
test('scalar type mismatch', () {
shouldFail('error', equals(5.1),
"Expected: <5.1> "
- "But: was 'error'. Actual: 'error'");
+ "Actual: 'error'");
});
test('nested type mismatch', () {
shouldFail(['error'], equals([5.1]),
"Expected: [5.1] "
- "But: expected <5.1> but was 'error' mismatch at position 0. "
- "Actual: ['error']");
+ "Actual: ['error'] "
+ "Which: was 'error' instead of <5.1> at location [0]");
});
test('doubly-nested type mismatch', () {
shouldFail([['error']], equals([[5.1]]),
"Expected: [[5.1]] "
- "But: expected <5.1> but was 'error' "
- "mismatch at position 0 mismatch at position 0. "
- "Actual: [['error']]");
+ "Actual: [['error']] "
+ "Which: was 'error' instead of <5.1> at location [0][0]");
+ });
+
+ test('doubly nested inequality', () {
+ var actual1 = [['foo', 'bar'], ['foo'], 3, []];
+ var expected1 = [['foo', 'bar'], ['foo'], 4, []];
+ var reason1 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+ "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+ "Which: was <3> instead of <4> at location [2]";
+
+ var actual2 = [['foo', 'barry'], ['foo'], 4, []];
+ var expected2 = [['foo', 'bar'], ['foo'], 4, []];
+ var reason2 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+ "Actual: [['foo', 'barry'], ['foo'], 4, []] "
+ "Which: was 'barry' instead of 'bar' at location [0][1]";
+
+ var actual3 = [['foo', 'bar'], ['foo'], 4, {'foo':'bar'}];
+ var expected3 = [['foo', 'bar'], ['foo'], 4, {'foo':'barry'}];
+ var reason3 = "Expected: [['foo', 'bar'], ['foo'], 4, {'foo': 'barry'}] "
+ "Actual: [['foo', 'bar'], ['foo'], 4, {'foo': 'bar'}] "
+ "Which: was 'bar' instead of 'barry' at location [3]['foo']";
+
+ shouldFail(actual1, equals(expected1), reason1);
+ shouldFail(actual2, equals(expected2), reason2);
+ shouldFail(actual3, equals(expected3), reason3);
});
});
@@ -152,67 +172,87 @@
test('greaterThan', () {
shouldPass(10, greaterThan(9));
shouldFail(9, greaterThan(10),
- "Expected: a value greater than <10> But: was <9>. Actual: <9>");
+ "Expected: a value greater than <10> "
+ "Actual: <9> "
+ "Which: is not a value greater than <10>");
});
test('greaterThanOrEqualTo', () {
shouldPass(10, greaterThanOrEqualTo(10));
shouldFail(9, greaterThanOrEqualTo(10),
- "Expected: a value greater than or equal to <10> But: was <9>. "
- "Actual: <9>");
+ "Expected: a value greater than or equal to <10> "
+ "Actual: <9> "
+ "Which: is not a value greater than or equal to <10>");
});
test('lessThan', () {
- shouldFail(10, lessThan(9), "Expected: a value less than <9> "
- "But: was <10>. Actual: <10>");
+ shouldFail(10, lessThan(9),
+ "Expected: a value less than <9> "
+ "Actual: <10> "
+ "Which: is not a value less than <9>");
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>. "
- "Actual: <11>");
+ "Expected: a value less than or equal to <10> "
+ "Actual: <11> "
+ "Which: is not a value less than or equal to <10>");
});
test('isZero', () {
shouldPass(0, isZero);
- shouldFail(1, isZero, "Expected: a value equal to <0> But: was <1>."
- " Actual: <1>");
+ shouldFail(1, isZero,
+ "Expected: a value equal to <0> "
+ "Actual: <1> "
+ "Which: is not a value equal to <0>");
});
test('isNonZero', () {
- shouldFail(0, isNonZero, "Expected: a value not equal to <0> "
- "But: was <0>. Actual: <0>");
+ shouldFail(0, isNonZero,
+ "Expected: a value not equal to <0> "
+ "Actual: <0> "
+ "Which: is not a value not equal to <0>");
shouldPass(1, isNonZero);
});
test('isPositive', () {
- shouldFail(-1, isPositive, "Expected: a positive value "
- "But: was <-1>. Actual: <-1>");
- shouldFail(0, isPositive, "Expected: a positive value "
- "But: was <0>. Actual: <0>");
+ shouldFail(-1, isPositive,
+ "Expected: a positive value "
+ "Actual: <-1> "
+ "Which: is not a positive value");
+ shouldFail(0, isPositive,
+ "Expected: a positive value "
+ "Actual: <0> "
+ "Which: is not a positive value");
shouldPass(1, isPositive);
});
test('isNegative', () {
shouldPass(-1, isNegative);
shouldFail(0, isNegative,
- "Expected: a negative value But: was <0>. Actual: <0>");
+ "Expected: a negative value "
+ "Actual: <0> "
+ "Which: is not a negative value");
});
test('isNonPositive', () {
shouldPass(-1, isNonPositive);
shouldPass(0, isNonPositive);
shouldFail(1, isNonPositive,
- "Expected: a non-positive value But: was <1>. Actual: <1>");
+ "Expected: a non-positive value "
+ "Actual: <1> "
+ "Which: is not a non-positive value");
});
test('isNonNegative', () {
shouldPass(1, isNonNegative);
shouldPass(0, isNonNegative);
shouldFail(-1, isNonNegative,
- "Expected: a non-negative value But: was <-1>. Actual: <-1>");
+ "Expected: a non-negative value "
+ "Actual: <-1> "
+ "Which: is not a non-negative value");
});
test('closeTo', () {
@@ -221,40 +261,40 @@
shouldPass(1, closeTo(0, 1));
shouldFail(1.001, closeTo(0, 1),
"Expected: a numeric value within <1> of <0> "
- "But: differed by <1.001>. "
- "Actual: <1.001>");
+ "Actual: <1.001> "
+ "Which: differs by <1.001>");
shouldFail(-1.001, closeTo(0, 1),
"Expected: a numeric value within <1> of <0> "
- "But: differed by <1.001>. "
- "Actual: <-1.001>");
+ "Actual: <-1.001> "
+ "Which: differs by <1.001>");
});
test('inInclusiveRange', () {
shouldFail(-1, inInclusiveRange(0,2),
"Expected: be in range from 0 (inclusive) to 2 (inclusive) "
- "But: was <-1>. Actual: <-1>");
+ "Actual: <-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>. Actual: <3>");
+ "Actual: <3>");
});
test('inExclusiveRange', () {
shouldFail(0, inExclusiveRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (exclusive) "
- "But: was <0>. Actual: <0>");
+ "Actual: <0>");
shouldPass(1, inExclusiveRange(0,2));
shouldFail(2, inExclusiveRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (exclusive) "
- "But: was <2>. Actual: <2>");
+ "Actual: <2>");
});
test('inOpenClosedRange', () {
shouldFail(0, inOpenClosedRange(0,2),
"Expected: be in range from 0 (exclusive) to 2 (inclusive) "
- "But: was <0>. Actual: <0>");
+ "Actual: <0>");
shouldPass(1, inOpenClosedRange(0,2));
shouldPass(2, inOpenClosedRange(0,2));
});
@@ -264,7 +304,7 @@
shouldPass(1, inClosedOpenRange(0,2));
shouldFail(2, inClosedOpenRange(0,2),
"Expected: be in range from 0 (inclusive) to 2 (exclusive) "
- "But: was <2>. Actual: <2>");
+ "Actual: <2>");
});
});
@@ -273,23 +313,24 @@
test('isEmpty', () {
shouldPass('', isEmpty);
shouldFail(null, isEmpty,
- "Expected: empty But: was <null>. Actual: <null>");
+ "Expected: empty Actual: <null>");
shouldFail(0, isEmpty,
- "Expected: empty But: was <0>. Actual: <0>");
- shouldFail('a', isEmpty, "Expected: empty But: was 'a'. Actual: 'a'");
+ "Expected: empty Actual: <0>");
+ shouldFail('a', isEmpty, "Expected: empty Actual: 'a'");
});
test('equalsIgnoringCase', () {
shouldPass('hello', equalsIgnoringCase('HELLO'));
shouldFail('hi', equalsIgnoringCase('HELLO'),
- "Expected: 'HELLO' ignoring case But: was 'hi'. Actual: 'hi'");
+ "Expected: 'HELLO' ignoring case Actual: 'hi'");
});
test('equalsIgnoringWhitespace', () {
shouldPass(' hello world ', equalsIgnoringWhitespace('hello world'));
shouldFail(' helloworld ', equalsIgnoringWhitespace('hello world'),
"Expected: 'hello world' ignoring whitespace "
- "But: was 'helloworld'. Actual: ' helloworld '");
+ "Actual: ' helloworld ' "
+ "Which: is 'helloworld' with whitespace compressed");
});
test('startsWith', () {
@@ -298,7 +339,7 @@
shouldPass('hello', startsWith('hello'));
shouldFail('hello', startsWith('hello '),
"Expected: a string starting with 'hello ' "
- "But: was 'hello'. Actual: 'hello'");
+ "Actual: 'hello'");
});
test('endsWith', () {
@@ -307,7 +348,7 @@
shouldPass('hello', endsWith('hello'));
shouldFail('hello', endsWith(' hello'),
"Expected: a string ending with ' hello' "
- "But: was 'hello'. Actual: 'hello'");
+ "Actual: 'hello'");
});
test('contains', () {
@@ -317,7 +358,7 @@
shouldPass('hello', contains('hell'));
shouldPass('hello', contains('hello'));
shouldFail('hello', contains(' '),
- "Expected: contains ' ' But: was 'hello'. Actual: 'hello'");
+ "Expected: contains ' ' Actual: 'hello'");
});
test('stringContainsInOrder', () {
@@ -336,14 +377,14 @@
shouldFail('goodbye cruel world',
stringContainsInOrder(['goo', 'cruel', 'bye']),
"Expected: a string containing 'goo', 'cruel', 'bye' in order "
- "But: was 'goodbye cruel world'. Actual: 'goodbye cruel world'");
+ "Actual: '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'. Actual: 'cOd'");
+ "Expected: match '[a-z][0-9][a-z]' Actual: 'cOd'");
});
});
@@ -351,37 +392,70 @@
test('isEmpty', () {
shouldPass([], isEmpty);
- shouldFail([1], isEmpty, "Expected: empty But: was [1]. Actual: [1]");
+ shouldFail([1], isEmpty, "Expected: empty Actual: [1]");
});
test('contains', () {
var d = [1, 2];
shouldPass(d, contains(1));
shouldFail(d, contains(0), "Expected: contains <0> "
- "But: was [1, 2]. Actual: [1, 2]");
+ "Actual: [1, 2]");
});
test('isIn', () {
var d = [1, 2];
shouldPass(1, isIn(d));
- shouldFail(0, isIn(d), "Expected: is in [1, 2] But: was <0>. Actual: <0>");
+ shouldFail(0, isIn(d), "Expected: is in [1, 2] Actual: <0>");
});
test('everyElement', () {
var d = [1, 2];
var e = [1, 1, 1];
shouldFail(d, everyElement(1),
- "Expected: every element <1> But: position 1 was <2>. "
- "Actual: [1, 2]");
+ "Expected: every element(<1>) "
+ "Actual: [1, 2] "
+ "Which: has value <2> which doesn't match <1> at index 1");
shouldPass(e, everyElement(1));
});
+ test('nested everyElement', () {
+ var d = [['foo', 'bar'], ['foo'], []];
+ var e = [['foo', 'bar'], ['foo'], 3, []];
+ shouldPass(d, everyElement(anyOf(isEmpty, contains('foo'))));
+ shouldFail(d, everyElement(everyElement(equals('foo'))),
+ "Expected: every element(every element('foo')) "
+ "Actual: [['foo', 'bar'], ['foo'], []] "
+ "Which: has value ['foo', 'bar'] which has value 'bar' "
+ "which is different. Expected: foo Actual: bar ^ "
+ "Differ at offset 0 at index 1 at index 0");
+ shouldFail(d, everyElement(allOf(hasLength(greaterThan(0)),
+ contains('foo'))),
+ "Expected: every element((an object with length of a value "
+ "greater than <0> and contains 'foo')) "
+ "Actual: [['foo', 'bar'], ['foo'], []] "
+ "Which: has value [] which has length of <0> at index 2");
+ shouldFail(d, everyElement(allOf(contains('foo'),
+ hasLength(greaterThan(0)))),
+ "Expected: every element((contains 'foo' and "
+ "an object with length of a value greater than <0>)) "
+ "Actual: [['foo', 'bar'], ['foo'], []] "
+ "Which: has value [] which doesn't match (contains 'foo' and "
+ "an object with length of a value greater than <0>) at index 2");
+ shouldFail(e, everyElement(allOf(contains('foo'),
+ hasLength(greaterThan(0)))),
+ "Expected: every element((contains 'foo' and an object with "
+ "length of a value greater than <0>)) "
+ "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+ "Which: has value <3> which is not a string, map or iterable "
+ "at index 2");
+ });
+
test('someElement', () {
var d = [1, 2];
var e = [1, 1, 1];
shouldPass(d, someElement(2));
shouldFail(e, someElement(2),
- "Expected: some element <2> But: was [1, 1, 1]. Actual: [1, 1, 1]");
+ "Expected: some element <2> Actual: [1, 1, 1]");
});
test('orderedEquals', () {
@@ -390,8 +464,8 @@
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. "
- "Actual: [1, 2]");
+ "Actual: [1, 2] "
+ "Which: was <1> instead of <2> at location [0]");
});
test('unorderedEquals', () {
@@ -399,16 +473,16 @@
shouldPass(d, unorderedEquals([2, 1]));
shouldFail(d, unorderedEquals([1]),
"Expected: equals [1] unordered "
- "But: has too many elements (2 > 1). "
- "Actual: [1, 2]");
+ "Actual: [1, 2] "
+ "Which: has too many elements (2 > 1)");
shouldFail(d, unorderedEquals([3, 2, 1]),
"Expected: equals [3, 2, 1] unordered "
- "But: has too few elements (2 < 3). "
- "Actual: [1, 2]");
+ "Actual: [1, 2] "
+ "Which: has too few elements (2 < 3)");
shouldFail(d, unorderedEquals([3, 1]),
"Expected: equals [3, 1] unordered "
- "But: has no match for element <3> at position 0. "
- "Actual: [1, 2]");
+ "Actual: [1, 2] "
+ "Which: has no match for element <3> at index 0");
});
test('pairwise compare', () {
@@ -418,22 +492,22 @@
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. "
- "Actual: 'x'");
+ "Actual: 'x' "
+ "Which: is not an Iterable");
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. "
- "Actual: [1, 2]");
+ "Actual: [1, 2] "
+ "Which: has length 2 instead of 3");
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. "
- "Actual: [1, 2, 3]");
+ "Actual: [1, 2, 3] "
+ "Which: has <1> which is not less than <1> at index 0");
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. "
- "Actual: [1, 2, 3]");
+ "Actual: [1, 2, 3] "
+ "Which: has <1> which is not double <1> at index 0");
});
});
@@ -444,7 +518,7 @@
shouldPass({}, isEmpty);
shouldPass(a, isEmpty);
a['foo'] = 'bar';
- shouldFail(a, isEmpty, "Expected: empty But: was {'foo': 'bar'}. "
+ shouldFail(a, isEmpty, "Expected: empty "
"Actual: {'foo': 'bar'}");
});
@@ -457,8 +531,9 @@
c['bar'] = 'foo';
shouldPass(a, equals(b));
shouldFail(b, equals(c),
- "Expected: {'bar': 'foo'} But: missing map key 'bar'. "
- "Actual: {'foo': 'bar'}");
+ "Expected: {'bar': 'foo'} "
+ "Actual: {'foo': 'bar'} "
+ "Which: is missing map key 'bar'");
});
test('equals with different lengths', () {
@@ -472,28 +547,28 @@
c['barrista'] = 'caffeine';
shouldFail(a, equals(b),
"Expected: {'foo': 'bar', 'bar': 'foo'} "
- "But: different map lengths; missing map key 'bar'. "
- "Actual: {'foo': 'bar'}");
+ "Actual: {'foo': 'bar'} "
+ "Which: has different length and is missing map key 'bar'");
shouldFail(b, equals(a),
"Expected: {'foo': 'bar'} "
- "But: different map lengths; extra map key 'bar'. "
- "Actual: {'foo': 'bar', 'bar': 'foo'}");
+ "Actual: {'foo': 'bar', 'bar': 'foo'} "
+ "Which: has different length and has extra map key 'bar'");
shouldFail(b, equals(c),
"Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
- "But: missing map key 'barrista'. "
- "Actual: {'foo': 'bar', 'bar': 'foo'}");
+ "Actual: {'foo': 'bar', 'bar': 'foo'} "
+ "Which: is missing map key 'barrista'");
shouldFail(c, equals(b),
"Expected: {'foo': 'bar', 'bar': 'foo'} "
- "But: missing map key 'foo'. "
- "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
+ "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+ "Which: is missing map key 'foo'");
shouldFail(a, equals(c),
"Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
- "But: different map lengths; missing map key 'bar'. "
- "Actual: {'foo': 'bar'}");
+ "Actual: {'foo': 'bar'} "
+ "Which: has different length and is missing map key 'bar'");
shouldFail(c, equals(a),
"Expected: {'foo': 'bar'} "
- "But: different map lengths; missing map key 'foo'. "
- "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
+ "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+ "Which: has different length and is missing map key 'foo'");
});
test('contains', () {
@@ -502,9 +577,10 @@
var b = new Map();
shouldPass(a, contains('foo'));
shouldFail(b, contains('foo'),
- "Expected: contains 'foo' But: was {}. Actual: {}");
+ "Expected: contains 'foo' Actual: {}");
shouldFail(10, contains('foo'),
- "Expected: contains 'foo' But: was <10>. Actual: <10>");
+ "Expected: contains 'foo' Actual: <10> "
+ "Which: is not a string, map or iterable");
});
test('containsValue', () {
@@ -512,7 +588,7 @@
a['foo'] = 'bar';
shouldPass(a, containsValue('bar'));
shouldFail(a, containsValue('ba'),
- "Expected: contains value 'ba' But: was {'foo': 'bar'}. "
+ "Expected: contains value 'ba' "
"Actual: {'foo': 'bar'}");
});
@@ -522,13 +598,13 @@
shouldPass(a, containsPair('foo', 'bar'));
shouldFail(a, containsPair('foo', 'ba'),
"Expected: contains pair 'foo' => 'ba' "
- "But: Strings are not equal. Both strings start the same, "
- "but the given value also has the following trailing characters: r. "
- "Actual: {'foo': 'bar'}");
+ "Actual: {'foo': 'bar'} "
+ "Which: is different. Both strings start the same, but "
+ "the given value also has the following trailing characters: r");
shouldFail(a, containsPair('fo', 'bar'),
"Expected: contains pair 'fo' => 'bar' "
- "But: doesn't contain key 'fo'. "
- "Actual: {'foo': 'bar'}");
+ "Actual: {'foo': 'bar'} "
+ "Which: doesn't contain key 'fo'");
});
test('hasLength', () {
@@ -538,8 +614,8 @@
shouldPass(a, hasLength(1));
shouldFail(b, hasLength(1),
"Expected: an object with length of <1> "
- "But: had length of <0>. "
- "Actual: {}");
+ "Actual: {} "
+ "Which: has length of <0>");
});
});
@@ -547,7 +623,7 @@
test('anyOf', () {
shouldFail(0, anyOf([equals(1), equals(2)]),
- "Expected: (<1> or <2>) But: was <0>. Actual: <0>");
+ "Expected: (<1> or <2>) Actual: <0>");
shouldPass(1, anyOf([equals(1), equals(2)]));
});
@@ -555,7 +631,8 @@
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: was <-1> (wasn't a value greater than <0>). Actual: <-1>");
+ "Actual: <-1> "
+ "Which: is not a value greater than <0>");
});
});
@@ -615,8 +692,9 @@
var completer = new Completer();
completer.completeError('X');
shouldFail(completer.future, throwsA(equals('Y')),
- "Expected: 'Y' But: Strings are not equal. "
- "Expected: Y Actual: X ^ Differ at position 0. Actual: 'X'",
+ "Expected: 'Y' Actual: 'X' "
+ "Which: is different. "
+ "Expected: Y Actual: X ^ Differ at offset 0",
isAsync: true);
});
});
@@ -624,7 +702,7 @@
group('Predicate Matchers', () {
test('isInstanceOf', () {
shouldFail(0, predicate((x) => x is String, "an instance of String"),
- "Expected: an instance of String But: was <0>. Actual: <0>");
+ "Expected: an instance of String Actual: <0>");
shouldPass('cow', predicate((x) => x is String, "an instance of String"));
});
});
diff --git a/pkg/unittest/test/matchers_unminified_test.dart b/pkg/unittest/test/matchers_unminified_test.dart
index 51629ca..11fb2e9 100644
--- a/pkg/unittest/test/matchers_unminified_test.dart
+++ b/pkg/unittest/test/matchers_unminified_test.dart
@@ -22,9 +22,10 @@
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)?>"));
+ r"Expected: throws FormatException +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
+
});
test('throwsArgumentError', () {
@@ -33,10 +34,9 @@
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)?>"));
+ r"Expected: throws ArgumentError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
test('throwsRangeError', () {
@@ -45,9 +45,9 @@
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)?>"));
+ r"Expected: throws RangeError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
test('throwsNoSuchMethodError', () {
@@ -56,10 +56,9 @@
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)?>"));
+ r"Expected: throws NoSuchMethodError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
test('throwsUnimplementedError', () {
@@ -68,11 +67,9 @@
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)?>"));
+ r"Expected: throws UnimplementedError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
test('throwsUnsupportedError', () {
@@ -81,10 +78,9 @@
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)?>"));
+ r"Expected: throws UnsupportedError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
test('throwsStateError', () {
@@ -93,10 +89,9 @@
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)?>"));
+ r"Expected: throws StateError +"
+ r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Which: threw \?:<Exception>"));
});
});
@@ -106,7 +101,6 @@
var e = new SimpleIterable(1);
shouldPass(d, isEmpty);
shouldFail(e, isEmpty, "Expected: empty "
- "But: was SimpleIterable:[1]. "
"Actual: SimpleIterable:[1]");
});
@@ -115,7 +109,6 @@
shouldPass(d, contains(2));
shouldFail(d, contains(5),
"Expected: contains <5> "
- "But: was SimpleIterable:[3, 2, 1]. "
"Actual: SimpleIterable:[3, 2, 1]");
});
});
@@ -128,8 +121,9 @@
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'>");
+ "Actual: <Instance of 'Widget'> "
+ "Which: has price with value <10> which is not "
+ "a value greater than <10>");
});
});
}
diff --git a/pkg/unittest/test/test_utils.dart b/pkg/unittest/test/test_utils.dart
index f0b276d..5364da6 100644
--- a/pkg/unittest/test/test_utils.dart
+++ b/pkg/unittest/test/test_utils.dart
@@ -69,7 +69,7 @@
class PrefixMatcher extends BaseMatcher {
final String _prefix;
const PrefixMatcher(this._prefix);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
return item is String &&
(collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix));
}
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
index d6486c4..55d2245 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>. Actual: <4>'),
+ message: 'Expected: <5> Actual: <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>. Actual: <true>:testThree'),
+ 'testOne::testTwo:Expected: false Actual: <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>. Actual: <true>:'
+ 'fail1:Expected: <false> Actual: <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>. Actual: <true>:'
+ 'fail1:Expected: <false> Actual: <true>:'
'error1:Callback called more times than expected (1).:'
'fail2:failure:'
'error2:Callback called more times than expected (1).:'
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index fa7a79c..3537e32 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -52,6 +52,7 @@
V(File_LinkTarget, 1) \
V(File_Delete, 1) \
V(File_DeleteLink, 1) \
+ V(File_Rename, 2) \
V(File_FullPath, 1) \
V(File_OpenStdio, 1) \
V(File_GetStdioHandleType, 1) \
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index a971f961..87fc2c1 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -506,6 +506,24 @@
}
+void FUNCTION_NAME(File_Rename)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ const char* old_path =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+ const char* new_path =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+ bool result = File::Rename(old_path, new_path);
+ if (result) {
+ Dart_SetReturnValue(args, Dart_NewBoolean(result));
+ } else {
+ Dart_Handle err = DartUtils::NewDartOSError();
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ }
+ Dart_ExitScope();
+}
+
+
void FUNCTION_NAME(File_FullPath)(Dart_NativeArguments args) {
Dart_EnterScope();
const char* str =
@@ -707,6 +725,20 @@
}
+static CObject* FileRenameRequest(const CObjectArray& request) {
+ if (request.Length() == 3 &&
+ request[1]->IsString() &&
+ request[2]->IsString()) {
+ CObjectString old_path(request[1]);
+ CObjectString new_path(request[2]);
+ bool completed = File::Rename(old_path.CString(), new_path.CString());
+ if (completed) return CObject::True();
+ return CObject::NewOSError();
+ }
+ return CObject::IllegalArgumentError();
+}
+
+
static CObject* FileFullPathRequest(const CObjectArray& request) {
if (request.Length() == 2 && request[1]->IsString()) {
CObjectString filename(request[1]);
@@ -1168,6 +1200,9 @@
case File::kDeleteRequest:
response = FileDeleteRequest(request);
break;
+ case File::kRenameRequest:
+ response = FileRenameRequest(request);
+ break;
case File::kFullPathRequest:
response = FileFullPathRequest(request);
break;
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 839c557..a2bf20d 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -65,27 +65,28 @@
kExistsRequest = 0,
kCreateRequest = 1,
kDeleteRequest = 2,
- kOpenRequest = 3,
- kFullPathRequest = 4,
- kCloseRequest = 5,
- kPositionRequest = 6,
- kSetPositionRequest = 7,
- kTruncateRequest = 8,
- kLengthRequest = 9,
- kLengthFromPathRequest = 10,
- kLastModifiedRequest = 11,
- kFlushRequest = 12,
- kReadByteRequest = 13,
- kWriteByteRequest = 14,
- kReadRequest = 15,
- kReadIntoRequest = 16,
- kWriteFromRequest = 17,
- kCreateLinkRequest = 18,
- kDeleteLinkRequest = 19,
- kLinkTargetRequest = 20,
- kTypeRequest = 21,
- kIdenticalRequest = 22,
- kStatRequest = 23
+ kRenameRequest = 3,
+ kOpenRequest = 4,
+ kFullPathRequest = 5,
+ kCloseRequest = 6,
+ kPositionRequest = 7,
+ kSetPositionRequest = 8,
+ kTruncateRequest = 9,
+ kLengthRequest = 10,
+ kLengthFromPathRequest = 11,
+ kLastModifiedRequest = 12,
+ kFlushRequest = 13,
+ kReadByteRequest = 14,
+ kWriteByteRequest = 15,
+ kReadRequest = 16,
+ kReadIntoRequest = 17,
+ kWriteFromRequest = 18,
+ kCreateLinkRequest = 19,
+ kDeleteLinkRequest = 20,
+ kLinkTargetRequest = 21,
+ kTypeRequest = 22,
+ kIdenticalRequest = 23,
+ kStatRequest = 24
};
enum FileStat {
@@ -152,6 +153,7 @@
static bool CreateLink(const char* path, const char* target);
static bool Delete(const char* path);
static bool DeleteLink(const char* path);
+ static bool Rename(const char* old_path, const char* new_path);
static off_t LengthFromPath(const char* path);
static void Stat(const char* path, int64_t* data);
static time_t LastModified(const char* path);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 939929a..513f96e 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -192,6 +192,19 @@
}
+bool File::Rename(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off_t File::LengthFromPath(const char* name) {
struct stat st;
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 8f1a114..840e6b9 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -193,6 +193,19 @@
}
+bool File::Rename(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off_t File::LengthFromPath(const char* name) {
struct stat st;
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index e29c6ab..c2308b6 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -195,6 +195,19 @@
}
+bool File::Rename(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off_t File::LengthFromPath(const char* name) {
struct stat st;
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 218c729..e788a42 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -14,6 +14,8 @@
/* patch */ static _linkTarget(String path) native "File_LinkTarget";
/* patch */ static _delete(String path) native "File_Delete";
/* patch */ static _deleteLink(String path) native "File_DeleteLink";
+ /* patch */ static _rename(String oldPath, String newPath)
+ native "File_Rename";
/* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
/* patch */ static _lastModified(String path) native "File_LastModified";
/* patch */ static _open(String path, int mode) native "File_Open";
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index d149c08..723bd6c 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -286,6 +286,26 @@
}
+bool File::Rename(const char* old_path, const char* new_path) {
+ File::Type type = GetType(old_path, false);
+ if (type == kIsFile) {
+ const wchar_t* system_old_path = StringUtils::Utf8ToWide(old_path);
+ const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path);
+ DWORD flags = MOVEFILE_WRITE_THROUGH;
+ int move_status =
+ MoveFileExW(system_old_path, system_new_path, flags);
+ free(const_cast<wchar_t*>(system_old_path));
+ free(const_cast<wchar_t*>(system_new_path));
+ return (move_status != 0);
+ } else if (type == kIsDirectory) {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ } else {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ return false;
+}
+
+
off_t File::LengthFromPath(const char* name) {
struct _stat st;
const wchar_t* system_name = StringUtils::Utf8ToWide(name);
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index ec54765..3a3fd9d 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -266,7 +266,7 @@
BOOL optval = true;
int status = setsockopt(s,
SOL_SOCKET,
- SO_REUSEADDR,
+ SO_EXCLUSIVEADDRUSE,
reinterpret_cast<const char*>(&optval),
sizeof(optval));
if (status == SOCKET_ERROR) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 790f6f6..a6ea151 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -79,6 +79,32 @@
return Dart_True(); // Indicates success. Result is in is_mirror.
}
+static Dart_Handle IsMethodMirror(Dart_Handle object, bool* is_mirror) {
+ Dart_Handle cls_name = NewString("MethodMirror");
+ Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ if (Dart_IsError(cls)) {
+ return cls;
+ }
+ Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ return Dart_True(); // Indicates success. Result is in is_mirror.
+}
+
+static Dart_Handle IsVariableMirror(Dart_Handle object, bool* is_mirror) {
+ Dart_Handle cls_name = NewString("VariableMirror");
+ Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ if (Dart_IsError(cls)) {
+ return cls;
+ }
+ Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ return Dart_True(); // Indicates success. Result is in is_mirror.
+}
+
static bool IsSimpleValue(Dart_Handle object) {
return (Dart_IsNull(object) ||
@@ -133,6 +159,11 @@
return vm_ref;
}
+static Dart_Handle StringFromSymbol(Dart_Handle symbol) {
+ Dart_Handle result = Dart_Invoke(MirrorLib(), NewString("_n"), 1, &symbol);
+ return result;
+}
+
static Dart_Handle UnwrapVMReference(Dart_Handle vm_ref) {
// Retrieve the persistent handle from the VMReference
@@ -151,8 +182,9 @@
return handle;
}
+static Dart_Handle UnwrapMirror(Dart_Handle mirror);
-static Dart_Handle UnwrapMirror(Dart_Handle mirror) {
+static Dart_Handle UnwrapObjectMirror(Dart_Handle mirror) {
Dart_Handle field_name = NewString("_reference");
Dart_Handle vm_ref = Dart_GetField(mirror, field_name);
if (Dart_IsError(vm_ref)) {
@@ -162,6 +194,78 @@
}
+static Dart_Handle UnwrapMethodMirror(Dart_Handle methodMirror) {
+ Dart_Handle namefield_name = NewString("simpleName");
+ Dart_Handle name_ref = Dart_GetField(methodMirror, namefield_name);
+ if (Dart_IsError(name_ref)) {
+ return name_ref;
+ }
+ Dart_Handle ownerfield_name = NewString("_owner");
+ Dart_Handle owner_mirror = Dart_GetField(methodMirror, ownerfield_name);
+ if (Dart_IsError(owner_mirror)) {
+ return owner_mirror;
+ }
+ Dart_Handle owner = UnwrapMirror(owner_mirror);
+ if (Dart_IsError(owner)) {
+ return owner;
+ }
+ Dart_Handle func = Dart_LookupFunction(owner, StringFromSymbol(name_ref));
+ if (Dart_IsError(func)) {
+ return func;
+ }
+ ASSERT(!Dart_IsNull(func));
+ return func;
+}
+
+static Dart_Handle UnwrapVariableMirror(Dart_Handle variableMirror) {
+ Dart_Handle namefield_name = NewString("simpleName");
+ Dart_Handle name_ref = Dart_GetField(variableMirror, namefield_name);
+ if (Dart_IsError(name_ref)) {
+ return name_ref;
+ }
+ Dart_Handle ownerfield_name = NewString("_owner");
+ Dart_Handle owner_mirror = Dart_GetField(variableMirror, ownerfield_name);
+ ASSERT(!Dart_IsNull(owner_mirror));
+ if (Dart_IsError(owner_mirror)) {
+ return owner_mirror;
+ }
+ Dart_Handle owner = UnwrapMirror(owner_mirror);
+ if (Dart_IsError(owner)) {
+ return owner;
+ }
+ Dart_Handle variable =
+ Dart_LookupVariable(owner, StringFromSymbol(name_ref));
+ if (Dart_IsError(variable)) {
+ return variable;
+ }
+ ASSERT(!Dart_IsNull(variable));
+ return variable;
+}
+
+static Dart_Handle UnwrapMirror(Dart_Handle mirror) {
+ // Caveat Emptor:
+ // only works for ObjectMirrors, VariableMirrors and MethodMirrors
+ // and their subtypes
+ bool is_method_mirror = false;
+ Dart_Handle result = IsMethodMirror(mirror, &is_method_mirror);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ if (is_method_mirror) {
+ return UnwrapMethodMirror(mirror);
+ }
+ bool is_variable_mirror = false;
+ result = IsVariableMirror(mirror, &is_variable_mirror);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ if (is_variable_mirror) {
+ return UnwrapVariableMirror(mirror);
+ }
+ return UnwrapObjectMirror(mirror);
+ // will return nonsense if mirror is not an ObjectMirror
+}
+
static Dart_Handle UnwrapArg(Dart_Handle arg) {
if (Dart_IsError(arg)) {
return arg;
@@ -466,6 +570,7 @@
}
// TODO(turnidge): Why am I getting Null when I expect Object?
+ // TODO(gbracha): this is probably the root of bug 7868
Dart_Handle super_class = Dart_GetSuperclass(intf);
if (Dart_IsNull(super_class)) {
super_class = Dart_GetClass(CoreLib(), NewString("Object"));
@@ -1108,6 +1213,20 @@
Dart_ExitScope();
}
+void NATIVE_ENTRY_FUNCTION(Mirrors_metadata)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
+
+ Dart_Handle reflectee = UnwrapMirror(mirror);
+ Dart_Handle result = Dart_GetMetadata(reflectee);
+ if (Dart_IsError(result)) {
+ Dart_PropagateError(result);
+ }
+ ASSERT(Dart_IsList(result));
+ Dart_SetReturnValue(args, result);
+ Dart_ExitScope();
+}
+
void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_invoke)(
Dart_NativeArguments args) {
Dart_EnterScope();
@@ -1278,7 +1397,6 @@
Dart_ExitScope();
}
-
void HandleMirrorsMessage(Isolate* isolate,
Dart_Port reply_port,
const Instance& message) {
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index ef95c2b..cb18187 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -70,6 +70,10 @@
return result;
}
+List<InstanceMirror> _metadata(mirror)
+ native 'Mirrors_metadata';
+
+
class _LocalMirrorSystemImpl extends MirrorSystem {
// Change parameter back to "this.libraries" when native code is changed.
_LocalMirrorSystemImpl(Map<String, LibraryMirror> libraries, this.isolate)
@@ -602,6 +606,10 @@
}
}
+ // get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list
+ List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
static _invokeConstructor(ref, constructorName, positionalArguments, async)
native 'LocalClassMirrorImpl_invokeConstructor';
}
@@ -704,6 +712,10 @@
return _upperBound;
}
+ // get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list
+ List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
String toString() => "TypeVariableMirror on '$simpleName'";
}
@@ -843,6 +855,10 @@
return _variables;
}
+ // get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list
+ List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
String toString() => "LibraryMirror on '$simpleName'";
}
@@ -943,6 +959,13 @@
final bool isRedirectingConstructor;
final bool isFactoryConstructor;
+ List<InstanceMirror> get metadata {
+ owner; // ensure owner is computed
+ // get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list
+ return _metadata(this).map(reflect).toList();
+ }
+
String toString() => "MethodMirror on '$simpleName'";
}
@@ -997,6 +1020,13 @@
final bool isStatic;
final bool isFinal;
+ List<InstanceMirror> get metadata {
+ owner; // ensure owner is computed
+ // get the metadata objects, convert them into InstanceMirrors using
+ // reflect() and then make them into a Dart list
+ return _metadata(this).map(reflect).toList();
+ }
+
String toString() => "VariableMirror on '$simpleName'";
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index a7adc56..29b9253 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -235,8 +235,9 @@
V(isolate_spawnUri, 1) \
V(Mirrors_isLocalPort, 1) \
V(Mirrors_makeLocalInstanceMirror, 1) \
- V(Mirrors_makeLocalClassMirror, 1) \
+ V(Mirrors_makeLocalClassMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
+ V(Mirrors_metadata, 1) \
V(LocalObjectMirrorImpl_invoke, 4) \
V(LocalObjectMirrorImpl_getField, 2) \
V(LocalObjectMirrorImpl_setField, 4) \
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index a524b8e..b869940 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2853,7 +2853,8 @@
void EffectGraphVisitor::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
- LoadStaticFieldInstr* load = new LoadStaticFieldInstr(node->field());
+ Value* field_value = Bind(new ConstantInstr(node->field()));
+ LoadStaticFieldInstr* load = new LoadStaticFieldInstr(field_value);
ReturnDefinition(load);
}
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index e3d2acf..3a1c685 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -22,19 +22,19 @@
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
V(ObjectArrayFactory, kArrayCid, 97987288) \
V(GrowableObjectArrayWithData, kGrowableObjectArrayCid, 816132033) \
- V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 552407276) \
- V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1168404493) \
- V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 2094565809) \
- V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1449285088) \
- V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1430476167) \
- V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 996241892) \
- V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 360797715) \
- V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 995053409) \
- V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 570248142) \
- V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1114332856) \
- V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1896334311) \
- V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1719636031) \
- V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1768466392) \
+ V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 1821003625) \
+ V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1139775342) \
+ V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 2065936658) \
+ V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1420655937) \
+ V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1401847016) \
+ V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 967612741) \
+ V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 332168564) \
+ V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 966424258) \
+ V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 541618991) \
+ V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1085703705) \
+ V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1867705160) \
+ V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1691006880) \
+ V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1739837241) \
// An class to collect the exits from an inlined function during graph
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 5094329..36646d3 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -3670,7 +3670,8 @@
LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
if (load_static_field != NULL) {
- return Alias::Field(GetFieldId(kAnyInstance, load_static_field->field()));
+ return Alias::Field(GetFieldId(kAnyInstance,
+ load_static_field->StaticField()));
}
UNREACHABLE();
@@ -3846,7 +3847,7 @@
LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
if (load_static_field != NULL) {
- return load_static_field->field().is_final();
+ return load_static_field->StaticField().is_final();
}
return false;
@@ -3974,7 +3975,7 @@
location = store_field->offset_in_bytes();
} else if (key->IsLoadStaticField()) {
LoadStaticFieldInstr* load_static_field = key->AsLoadStaticField();
- object = String::Handle(load_static_field->field().name()).Hash();
+ object = String::Handle(load_static_field->StaticField().name()).Hash();
} else if (key->IsStoreStaticField()) {
StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
object = String::Handle(store_static_field->field().name()).Hash();
@@ -4004,7 +4005,7 @@
if (key->IsStoreStaticField()) {
LoadStaticFieldInstr* load_static_field = kv->AsLoadStaticField();
StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
- return load_static_field->field().raw() ==
+ return load_static_field->StaticField().raw() ==
store_static_field->field().raw();
}
return false;
@@ -5236,7 +5237,7 @@
void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
- const Field& field = instr->field();
+ const Field& field = instr->StaticField();
ASSERT(field.is_static());
if (field.is_final()) {
Instance& obj = Instance::Handle(field.value());
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 5b6d6b2..0ffb7f0 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -888,7 +888,7 @@
CompileType LoadStaticFieldInstr::ComputeType() const {
if (FLAG_enable_type_checks) {
return CompileType::FromAbstractType(
- AbstractType::ZoneHandle(field().type()));
+ AbstractType::ZoneHandle(StaticField().type()));
}
return CompileType::Dynamic();
}
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index f7aa016..1a4f025 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -440,7 +440,7 @@
void LoadStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s", String::Handle(field().name()).ToCString());
+ field_value()->PrintTo(f);
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 186e148..8cc2bcd 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -173,7 +173,7 @@
EffectSet LoadStaticFieldInstr::Dependencies() const {
- return field().is_final() ? EffectSet::None() : EffectSet::All();
+ return StaticField().is_final() ? EffectSet::None() : EffectSet::All();
}
@@ -181,9 +181,16 @@
LoadStaticFieldInstr* other_load = other->AsLoadStaticField();
ASSERT(other_load != NULL);
// Assert that the field is initialized.
- ASSERT(field().value() != Object::sentinel().raw());
- ASSERT(field().value() != Object::transition_sentinel().raw());
- return field().raw() == other_load->field().raw();
+ ASSERT(StaticField().value() != Object::sentinel().raw());
+ ASSERT(StaticField().value() != Object::transition_sentinel().raw());
+ return StaticField().raw() == other_load->StaticField().raw();
+}
+
+
+const Field& LoadStaticFieldInstr::StaticField() const {
+ Field& field = Field::Handle();
+ field ^= field_value()->BoundConstant().raw();
+ return field;
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index e3bd33d..0ad33b9 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -60,22 +60,22 @@
V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050) \
V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050) \
V(_StringBase, get:length, StringBaseLength, 320803993) \
- V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1026765313) \
+ V(_StringBase, get:isEmpty, StringBaseIsEmpty, 110631520) \
V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 984449525) \
V(_StringBase, [], StringBaseCharAt, 1062366987) \
V(_OneByteString, _setAt, OneByteStringSetAt, 342452817) \
- V(_IntegerImplementation, toDouble, IntegerToDouble, 1267108971) \
+ V(_IntegerImplementation, toDouble, IntegerToDouble, 1331752138) \
V(_Double, toInt, DoubleToInteger, 362666636) \
V(_Double, truncateToDouble, DoubleTruncate, 620870996) \
V(_Double, roundToDouble, DoubleRound, 620870996) \
V(_Double, floorToDouble, DoubleFloor, 620870996) \
V(_Double, ceilToDouble, DoubleCeil, 620870996) \
- V(_Double, pow, DoublePow, 631903778) \
+ V(_Double, pow, DoublePow, 102305574) \
V(_Double, _modulo, DoubleMod, 437099337) \
V(::, sqrt, MathSqrt, 1662640002) \
- V(Float32x4, Float32x4., Float32x4Constructor, 1327837070) \
- V(Float32x4, Float32x4.zero, Float32x4Zero, 927169529) \
- V(Float32x4, Float32x4.splat, Float32x4Splat, 1778587275) \
+ V(Float32x4, Float32x4., Float32x4Constructor, 1492157358) \
+ V(Float32x4, Float32x4.zero, Float32x4Zero, 444339161) \
+ V(Float32x4, Float32x4.splat, Float32x4Splat, 1843231403) \
V(_Float32x4, get:xxxx, Float32x4ShuffleXXXX, 42621627) \
V(_Float32x4, get:yyyy, Float32x4ShuffleYYYY, 42621627) \
V(_Float32x4, get:zzzz, Float32x4ShuffleZZZZ, 42621627) \
@@ -104,12 +104,12 @@
V(_Float32x4, withZ, Float32x4WithZ, 219466242) \
V(_Float32x4, withW, Float32x4WithW, 219466242) \
V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 1044409108) \
- V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 1489869343) \
+ V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 487876159) \
V(_Uint32x4, get:flagX, Uint32x4GetFlagX, 782547529) \
V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 782547529) \
V(_Uint32x4, get:flagZ, Uint32x4GetFlagZ, 782547529) \
V(_Uint32x4, get:flagW, Uint32x4GetFlagW, 782547529) \
- V(_Uint32x4, select, Uint32x4Select, 405662786) \
+ V(_Uint32x4, select, Uint32x4Select, 810336099) \
V(_Uint32x4, withFlagX, Uint32x4WithFlagX, 980864994) \
V(_Uint32x4, withFlagY, Uint32x4WithFlagY, 980864994) \
V(_Uint32x4, withFlagZ, Uint32x4WithFlagZ, 980864994) \
@@ -3380,28 +3380,32 @@
};
-class LoadStaticFieldInstr : public TemplateDefinition<0> {
+class LoadStaticFieldInstr : public TemplateDefinition<1> {
public:
- explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
+ explicit LoadStaticFieldInstr(Value* field_value) {
+ ASSERT(field_value->BindsToConstant());
+ SetInputAt(0, field_value);
+ }
DECLARE_INSTRUCTION(LoadStaticField)
virtual CompileType ComputeType() const;
- const Field& field() const { return field_; }
+ const Field& StaticField() const;
+
+ Value* field_value() const { return inputs_[0]; }
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const { return false; }
- virtual bool AllowsCSE() const { return field_.is_final(); }
+ virtual bool AllowsCSE() const { return StaticField().is_final(); }
virtual EffectSet Effects() const { return EffectSet::None(); }
virtual EffectSet Dependencies() const;
virtual bool AttributesEqual(Instruction* other) const;
virtual bool MayThrow() const { return false; }
- private:
- const Field& field_;
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldInstr);
};
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 01edb86..eacd243 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1054,13 +1054,17 @@
LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register object = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ __ LoadFromOffset(kLoadWord, result, object, offset() - kHeapObjectTag);
}
@@ -1363,10 +1367,6 @@
locs->set_in(2, Location::WritableRegister());
break;
case kTypedDataFloat32ArrayCid:
- // TODO(regis): Verify.
- // Need temp register for float-to-double conversion.
- locs->AddTemp(Location::RequiresFpuRegister());
- // Fall through.
case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants.
case kTypedDataFloat32x4ArrayCid:
locs->set_in(2, Location::RequiresFpuRegister());
@@ -1496,7 +1496,16 @@
break;
}
case kTypedDataFloat32ArrayCid:
+ // Convert to single precision.
+ __ vcvtsd(STMP, locs()->in(2).fpu_reg());
+ // Store.
+ __ add(index.reg(), index.reg(), ShifterOperand(array));
+ __ StoreSToOffset(STMP, index.reg(), 0);
+ break;
case kTypedDataFloat64ArrayCid:
+ __ add(index.reg(), index.reg(), ShifterOperand(array));
+ __ StoreDToOffset(locs()->in(2).fpu_reg(), index.reg(), 0);
+ break;
case kTypedDataFloat32x4ArrayCid:
UNIMPLEMENTED();
break;
@@ -1695,17 +1704,21 @@
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(0,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register field = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadObject(result, field());
__ LoadFromOffset(kLoadWord, result,
- result, Field::value_offset() - kHeapObjectTag);
+ field, Field::value_offset() - kHeapObjectTag);
}
@@ -2126,6 +2139,7 @@
if (left_int == 0) {
__ cmp(right, ShifterOperand(0));
__ b(deopt, MI);
+ __ mov(result, ShifterOperand(0));
return;
}
const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
@@ -2339,6 +2353,7 @@
if (value == 0) {
// TODO(vegorov): should be handled outside.
+ __ MoveRegister(result, left);
break;
} else if (value < 0) {
// TODO(vegorov): should be handled outside.
@@ -2426,7 +2441,22 @@
break;
}
case Token::kSHR: {
- UNIMPLEMENTED();
+ if (CanDeoptimize()) {
+ __ CompareImmediate(right, 0);
+ __ b(deopt, LT);
+ }
+ __ SmiUntag(right);
+ // sarl operation masks the count to 5 bits.
+ const intptr_t kCountLimit = 0x1F;
+ Range* right_range = this->right()->definition()->range();
+ if ((right_range == NULL) ||
+ !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
+ __ CompareImmediate(right, kCountLimit);
+ __ LoadImmediate(right, kCountLimit, GT);
+ }
+ __ SmiUntag(left);
+ __ Asr(result, left, right);
+ __ SmiTag(result);
break;
}
case Token::kDIV: {
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 3f043e3..e6eb45b 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1759,16 +1759,22 @@
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(0,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ // By specifying same register as input, our simple register allocator can
+ // generate better code.
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
}
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register field = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadObject(result, field());
- __ movl(result, FieldAddress(result, Field::value_offset()));
+ __ movl(result, FieldAddress(field, Field::value_offset()));
}
@@ -2535,7 +2541,7 @@
Range* right_range = this->right()->definition()->range();
if ((right_range == NULL) ||
!right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
- __ cmpl(right, Immediate(kCountLimit));
+ __ cmpl(right, Immediate(kCountLimit));
Label count_ok;
__ j(LESS, &count_ok, Assembler::kNearJump);
__ movl(right, Immediate(kCountLimit));
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 0245899..8bf386e 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1659,17 +1659,21 @@
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(0,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("LoadStaticFieldInstr");
+ Register field = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadObject(result, field());
- __ lw(result, Address(result, Field::value_offset() - kHeapObjectTag));
+ __ lw(result, FieldAddress(field, Field::value_offset()));
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index c93b79a3..357c907 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1743,16 +1743,20 @@
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(0,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register field = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadObject(result, field());
- __ movq(result, FieldAddress(result, Field::value_offset()));
+ __ movq(result, FieldAddress(field, Field::value_offset()));
}
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 0e0f942..f61d667 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -17,18 +17,18 @@
// build and run to get the correct fingerprint from the mismatch error.
#define CORE_LIB_INTRINSIC_LIST(V) \
V(_Smi, ~, Smi_bitNegate, 882629793) \
- V(_Double, >, Double_greaterThan, 301935359) \
- V(_Double, >=, Double_greaterEqualThan, 1184528952) \
- V(_Double, <, Double_lessThan, 1596251333) \
- V(_Double, <=, Double_lessEqualThan, 1184499161) \
- V(_Double, ==, Double_equal, 1706047712) \
- V(_Double, +, Double_add, 210576655) \
- V(_Double, -, Double_sub, 1605354741) \
- V(_Double, *, Double_mul, 788270837) \
- V(_Double, /, Double_div, 1202831412) \
+ V(_Double, >, Double_greaterThan, 498448864) \
+ V(_Double, >=, Double_greaterEqualThan, 1322959863) \
+ V(_Double, <, Double_lessThan, 1595326820) \
+ V(_Double, <=, Double_lessEqualThan, 1322930072) \
+ V(_Double, ==, Double_equal, 1012968674) \
+ V(_Double, +, Double_add, 407090160) \
+ V(_Double, -, Double_sub, 1801868246) \
+ V(_Double, *, Double_mul, 984784342) \
+ V(_Double, /, Double_div, 1399344917) \
V(_Double, get:isNaN, Double_getIsNaN, 54462366) \
V(_Double, get:isNegative, Double_getIsNegative, 54462366) \
- V(_Double, _mulFromInteger, Double_mulFromInteger, 704314034) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 550294258) \
V(_Double, .fromInteger, Double_fromInteger, 842078193) \
V(_ObjectArray, ., ObjectArray_Allocate, 97987288) \
V(_ObjectArray, get:length, Array_getLength, 405297088) \
@@ -41,12 +41,12 @@
V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 1048007636) \
V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 796709584) \
V(_GrowableObjectArray, _setData, GrowableArray_setData, 629110947) \
- V(_GrowableObjectArray, add, GrowableArray_add, 1904852879) \
+ V(_GrowableObjectArray, add, GrowableArray_add, 112207566) \
V(_ImmutableArray, [], ImmutableArray_getIndexed, 486821199) \
V(_ImmutableArray, get:length, ImmutableArray_getLength, 433698233) \
- V(Object, ==, Object_equal, 2126897013) \
+ V(Object, ==, Object_equal, 2126867222) \
V(_StringBase, get:hashCode, String_getHashCode, 320803993) \
- V(_StringBase, get:isEmpty, String_getIsEmpty, 1026765313) \
+ V(_StringBase, get:isEmpty, String_getIsEmpty, 110631520) \
V(_StringBase, get:length, String_getLength, 320803993) \
V(_StringBase, codeUnitAt, String_codeUnitAt, 984449525) \
V(_OneByteString, get:hashCode, OneByteString_getHashCode, 682660413) \
@@ -57,35 +57,35 @@
#define CORE_INTEGER_LIB_INTRINSIC_LIST(V) \
V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, 726019207)\
- V(_IntegerImplementation, +, Integer_add, 1768648592) \
+ V(_IntegerImplementation, +, Integer_add, 25837296) \
V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, 726019207)\
- V(_IntegerImplementation, -, Integer_sub, 1292467582) \
+ V(_IntegerImplementation, -, Integer_sub, 1697139934) \
V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, 726019207)\
- V(_IntegerImplementation, *, Integer_mul, 1853182047) \
- V(_IntegerImplementation, %, Integer_modulo, 1211518976) \
- V(_IntegerImplementation, remainder, Integer_remainder, 1131753683) \
- V(_IntegerImplementation, ~/, Integer_truncDivide, 142750059) \
- V(_IntegerImplementation, unary-, Integer_negate, 676633254) \
+ V(_IntegerImplementation, *, Integer_mul, 110370751) \
+ V(_IntegerImplementation, %, Integer_modulo, 980686435) \
+ V(_IntegerImplementation, remainder, Integer_remainder, 1536426035) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 2059401166) \
+ V(_IntegerImplementation, unary-, Integer_negate, 675709702) \
V(_IntegerImplementation, _bitAndFromInteger, \
Integer_bitAndFromInteger, 726019207) \
- V(_IntegerImplementation, &, Integer_bitAnd, 354347153) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 759019505) \
V(_IntegerImplementation, _bitOrFromInteger, \
Integer_bitOrFromInteger, 726019207) \
- V(_IntegerImplementation, |, Integer_bitOr, 875694946) \
+ V(_IntegerImplementation, |, Integer_bitOr, 1280367298) \
V(_IntegerImplementation, _bitXorFromInteger, \
Integer_bitXorFromInteger, 726019207) \
- V(_IntegerImplementation, ^, Integer_bitXor, 282155459) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 686827811) \
V(_IntegerImplementation, \
_greaterThanFromInteger, \
Integer_greaterThanFromInt, 79222670) \
- V(_IntegerImplementation, >, Integer_greaterThan, 462314913) \
- V(_IntegerImplementation, ==, Integer_equal, 1424765465) \
+ V(_IntegerImplementation, >, Integer_greaterThan, 866987265) \
+ V(_IntegerImplementation, ==, Integer_equal, 1763184121) \
V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, 79222670) \
- V(_IntegerImplementation, <, Integer_lessThan, 1424838471) \
- V(_IntegerImplementation, <=, Integer_lessEqualThan, 949016155) \
- V(_IntegerImplementation, >=, Integer_greaterEqualThan, 949045946) \
- V(_IntegerImplementation, <<, Integer_shl, 1195917829) \
- V(_IntegerImplementation, >>, Integer_sar, 1980227743) \
+ V(_IntegerImplementation, <, Integer_lessThan, 1423913958) \
+ V(_IntegerImplementation, <=, Integer_lessEqualThan, 1087447066) \
+ V(_IntegerImplementation, >=, Integer_greaterEqualThan, 1087476857) \
+ V(_IntegerImplementation, <<, Integer_shl, 1600590181) \
+ V(_IntegerImplementation, >>, Integer_sar, 237416447) \
V(_Double, toInt, Double_toInt, 362666636)
@@ -93,7 +93,7 @@
V(::, sqrt, Math_sqrt, 1662640002) \
V(::, sin, Math_sin, 1273932041) \
V(::, cos, Math_cos, 1749547468) \
- V(_Random, _nextState, Random_nextState, 77315414) \
+ V(_Random, _nextState, Random_nextState, 287494804) \
#define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
@@ -110,18 +110,18 @@
V(_Float32Array, _new, TypedData_Float32Array_new, 723829075) \
V(_Float64Array, _new, TypedData_Float64Array_new, 111654177) \
V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 984763738) \
- V(_Int8Array, ., TypedData_Int8Array_factory, 1168404493) \
- V(_Uint8Array, ., TypedData_Uint8Array_factory, 2094565809) \
- V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1449285088) \
- V(_Int16Array, ., TypedData_Int16Array_factory, 1430476167) \
- V(_Uint16Array, ., TypedData_Uint16Array_factory, 996241892) \
- V(_Int32Array, ., TypedData_Int32Array_factory, 360797715) \
- V(_Uint32Array, ., TypedData_Uint32Array_factory, 995053409) \
- V(_Int64Array, ., TypedData_Int64Array_factory, 570248142) \
- V(_Uint64Array, ., TypedData_Uint64Array_factory, 1114332856) \
- V(_Float32Array, ., TypedData_Float32Array_factory, 1719636031) \
- V(_Float64Array, ., TypedData_Float64Array_factory, 1896334311) \
- V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1768466392) \
+ V(_Int8Array, ., TypedData_Int8Array_factory, 1139775342) \
+ V(_Uint8Array, ., TypedData_Uint8Array_factory, 2065936658) \
+ V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1420655937) \
+ V(_Int16Array, ., TypedData_Int16Array_factory, 1401847016) \
+ V(_Uint16Array, ., TypedData_Uint16Array_factory, 967612741) \
+ V(_Int32Array, ., TypedData_Int32Array_factory, 332168564) \
+ V(_Uint32Array, ., TypedData_Uint32Array_factory, 966424258) \
+ V(_Int64Array, ., TypedData_Int64Array_factory, 541618991) \
+ V(_Uint64Array, ., TypedData_Uint64Array_factory, 1085703705) \
+ V(_Float32Array, ., TypedData_Float32Array_factory, 1691006880) \
+ V(_Float64Array, ., TypedData_Float64Array_factory, 1867705160) \
+ V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1739837241) \
// TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
// _FixedSizeArrayIterator, moveNext.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e1185d5..12cfe2d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -4654,6 +4654,8 @@
// This output can be copied into a file, then used with sed
// to replace the old values.
// sed -i .bak -f /tmp/newkeys runtime/vm/intrinsifier.h
+ // sed -i .bak -f /tmp/newkeys runtime/vm/intermediate_language.h
+ // sed -i .bak -f /tmp/newkeys runtime/vm/flow_graph_builder.h
OS::Print("s/%d/%d/\n", fp, SourceFingerprint());
} else {
OS::Print("FP mismatch while recognizing method %s:"
@@ -5238,7 +5240,6 @@
case Token::kPERIOD:
case Token::kLPAREN:
case Token::kLBRACK:
- case Token::kTIGHTADD:
case Token::kINTERPOL_VAR:
case Token::kINTERPOL_START:
case Token::kINTERPOL_END:
@@ -9202,21 +9203,35 @@
}
-RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
- ASSERT(!IsNull());
- if (this->IsCanonical()) {
- return this->raw();
+#if defined(DEBUG)
+class CheckForPointers : public ObjectPointerVisitor {
+ public:
+ explicit CheckForPointers(Isolate* isolate)
+ : ObjectPointerVisitor(isolate), has_pointers_(false) {}
+
+ bool has_pointers() const { return has_pointers_; }
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ if (first != last) {
+ has_pointers_ = true;
+ }
}
- Instance& result = Instance::Handle();
+
+ private:
+ bool has_pointers_;
+
+ DISALLOW_COPY_AND_ASSIGN(CheckForPointers);
+};
+#endif // DEBUG
+
+
+bool Instance::CheckAndCanonicalizeFields(const char** error_str) const {
const Class& cls = Class::Handle(this->clazz());
- // TODO(srdjan): Check that predefined classes do not have fields that need
- // to be checked/canonicalized as well.
- if ((cls.id() >= kNumPredefinedCids) || cls.IsArray()) {
+ if ((cls.id() >= kNumPredefinedCids)) {
// Iterate over all fields, canonicalize numbers and strings, expect all
- // other instances to be canonical otherwise report error (return
- // Instance::null()).
+ // other instances to be canonical otherwise report error (return false).
Object& obj = Object::Handle();
- const intptr_t end_field_offset = cls.instance_size() - kWordSize;
+ intptr_t end_field_offset = cls.instance_size() - kWordSize;
for (intptr_t field_offset = 0;
field_offset <= end_field_offset;
field_offset += kWordSize) {
@@ -9234,11 +9249,32 @@
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
OS::SNPrint(chars, len, kFormat, obj.ToCString());
*error_str = chars;
- return Instance::null();
+ return false;
}
}
}
+ } else {
+#if defined(DEBUG)
+ // Make sure that we are not missing any fields.
+ CheckForPointers has_pointers(Isolate::Current());
+ this->raw()->VisitPointers(&has_pointers);
+ ASSERT(!has_pointers.has_pointers());
+#endif // DEBUG
}
+ return true;
+}
+
+
+RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
+ ASSERT(!IsNull());
+ if (this->IsCanonical()) {
+ return this->raw();
+ }
+ if (!CheckAndCanonicalizeFields(error_str)) {
+ return Instance::null();
+ }
+ Instance& result = Instance::Handle();
+ const Class& cls = Class::Handle(this->clazz());
Array& constants = Array::Handle(cls.constants());
const intptr_t constants_len = constants.Length();
// Linear search to see whether this value is already present in the
@@ -12758,6 +12794,33 @@
}
+bool Array::CheckAndCanonicalizeFields(const char** error_str) const {
+ Object& obj = Object::Handle();
+ // Iterate over all elements, canonicalize numbers and strings, expect all
+ // other instances to be canonical otherwise report error (return false).
+ for (intptr_t i = 0; i < Length(); i++) {
+ obj = At(i);
+ if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
+ if (obj.IsNumber() || obj.IsString()) {
+ obj = Instance::Cast(obj).CheckAndCanonicalize(NULL);
+ ASSERT(!obj.IsNull());
+ this->SetAt(i, obj);
+ } else {
+ ASSERT(error_str != NULL);
+ const char* kFormat = "element at index %"Pd": %s\n";
+ const intptr_t len =
+ OS::SNPrint(NULL, 0, kFormat, i, obj.ToCString()) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, kFormat, i, obj.ToCString());
+ *error_str = chars;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
RawImmutableArray* ImmutableArray::New(intptr_t len,
Heap::Space space) {
ASSERT(Isolate::Current()->object_store()->immutable_array_class() !=
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 492b595..90e55f8 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3531,6 +3531,9 @@
// Returns error in error_str, pass NULL if an error cannot occur.
virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
+ // Returns true if all fields are OK for canonicalization.
+ virtual bool CheckAndCanonicalizeFields(const char** error_str) const;
+
RawObject* GetField(const Field& field) const {
return *FieldAddr(field);
}
@@ -4984,6 +4987,9 @@
return RoundedAllocationSize(sizeof(RawArray) + (len * kBytesPerElement));
}
+ // Returns true if all elements are OK for canonicalization.
+ virtual bool CheckAndCanonicalizeFields(const char** error_str) const;
+
// Make the array immutable to Dart code by switching the class pointer
// to ImmutableArray.
void MakeImmutable() const;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 0115294..f235827 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -1670,6 +1670,10 @@
EXPECT(!array.Equals(other_array));
EXPECT_EQ(0, Object::empty_array().Length());
+
+ array.MakeImmutable();
+ Object& obj = Object::Handle(array.raw());
+ ASSERT(obj.IsArray());
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index e2ade07..0aec272 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -6806,8 +6806,7 @@
static bool IsPrefixOperator(Token::Kind token) {
- return (token == Token::kTIGHTADD) || // Valid for literals only!
- (token == Token::kSUB) ||
+ return (token == Token::kSUB) ||
(token == Token::kNOT) ||
(token == Token::kBIT_NOT);
}
@@ -6920,9 +6919,6 @@
while (current_preced >= min_preced) {
while (Token::Precedence(CurrentToken()) == current_preced) {
Token::Kind op_kind = CurrentToken();
- if (op_kind == Token::kTIGHTADD) {
- op_kind = Token::kADD;
- }
const intptr_t op_pos = TokenPos();
ConsumeToken();
AstNode* right_operand = NULL;
@@ -7331,13 +7327,7 @@
}
ConsumeToken();
expr = ParseUnaryExpr();
- if (unary_op == Token::kTIGHTADD) {
- // kTIGHADD is added only in front of a number literal.
- if (!expr->IsLiteralNode()) {
- ErrorMsg(op_pos, "unexpected operator '+'");
- }
- // Expression is the literal itself.
- } else if (expr->IsPrimaryNode() && (expr->AsPrimaryNode()->IsSuper())) {
+ if (expr->IsPrimaryNode() && (expr->AsPrimaryNode()->IsSuper())) {
expr = BuildUnarySuperOperator(unary_op, expr->AsPrimaryNode());
} else {
expr = UnaryOpNode::UnaryOpOrLiteral(op_pos, unary_op, expr);
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 6162d1a..896142c 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -189,7 +189,7 @@
return true;
}
if ((tokens.length() == 3) &&
- ((tokens[0].kind == Token::kTIGHTADD) ||
+ ((tokens[0].kind == Token::kADD) ||
(tokens[0].kind == Token::kSUB)) &&
(tokens[1].kind == literal_kind) &&
(tokens[2].kind == Token::kEOS)) {
@@ -197,7 +197,7 @@
if ((tokens[0].offset + 1) != tokens[1].offset) {
return false;
}
- *is_positive = tokens[0].kind == Token::kTIGHTADD;
+ *is_positive = tokens[0].kind == Token::kADD;
*value = tokens[1].literal;
return true;
}
@@ -639,15 +639,8 @@
break;
case '+': // + ++ +=
- ReadChar();
- current_token_.kind =
- IsNumberStart(c0_) ? Token::kTIGHTADD : Token::kADD;
- // Unary + is not allowed for hexadecimal integers, so treat the
- // + as a binary operator.
- if ((c0_ == '0') &&
- ((LookaheadChar(1) == 'x') || (LookaheadChar(1) == 'X'))) {
- current_token_.kind = Token::kADD;
- } else if (c0_ == '+') {
+ Recognize(Token::kADD);
+ if (c0_ == '+') {
Recognize(Token::kINCR);
} else if (c0_ == '=') {
Recognize(Token::kASSIGN_ADD);
diff --git a/runtime/vm/scanner_test.cc b/runtime/vm/scanner_test.cc
index 1e04b8d..d4a653a 100644
--- a/runtime/vm/scanner_test.cc
+++ b/runtime/vm/scanner_test.cc
@@ -327,7 +327,7 @@
CheckKind(tokens, 3, Token::kDOUBLE);
CheckKind(tokens, 4, Token::kDOUBLE);
CheckKind(tokens, 5, Token::kDOUBLE);
- CheckKind(tokens, 6, Token::kTIGHTADD);
+ CheckKind(tokens, 6, Token::kADD);
CheckKind(tokens, 7, Token::kINTEGER);
CheckKind(tokens, 8, Token::kEOS);
}
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index c568ddd..1b58858 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -79,8 +79,6 @@
/* Additive operators. */ \
TOK(kADD, "+", 12, kNoAttribute) \
TOK(kSUB, "-", 12, kNoAttribute) \
- /* A 'plus' without a trailing whitespace (handle literals). */ \
- TOK(kTIGHTADD, "+", 12, kNoAttribute) \
\
/* Multiplicative operators */ \
TOK(kMUL, "*", 13, kNoAttribute) \
diff --git a/sdk/bin/pub.bat b/sdk/bin/pub.bat
index 99846ec..6f0d4e0 100644
--- a/sdk/bin/pub.bat
+++ b/sdk/bin/pub.bat
@@ -1,16 +1,49 @@
@echo off
-:: 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.
+REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
-:: Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
-:: structure.
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-set SCRIPTPATH=%~dp0
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
-:: Does the string have a trailing slash? If so, remove it.
-if %SCRIPTPATH:~-1%==\ set SCRIPTPATH=%SCRIPTPATH:~0,-1%
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
-:: The trailing forward slash in --package-root is required because of issue
-:: 9499.
-"%SCRIPTPATH%\dart.exe" "%SCRIPTPATH%\..\bin\snapshots\pub.dart.snapshot" %*
+set PUB=%SDK_DIR%\lib\_internal\pub\bin\pub.dart
+set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
+set PACKAGES_DIR=%BUILD_DIR%\packages\
+set DART=%BIN_DIR%\dart
+set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\pub.dart.snapshot
+
+if exist "%SNAPSHOT%" (
+ "%DART%" --checked "%SNAPSHOT%" %*
+) else (
+ "%DART_IN_BUILT_SDK%" --checked --package-root=%PACKAGES_DIR% "%PUB%" %*
+)
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "tokens=2 delims=[]" %%i in ('dir /a:l ^"%~dp1^" 2^>nul ^
+ ^| find "> %~n1 ["') do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index b51e9f5..c850caa 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -182,6 +182,10 @@
ClassElement classElement = element.getEnclosingClass();
return classElement == compiler.objectClass;
}
+
+ void enableMirrors() {}
+
+ void registerStaticUse(Element element, Enqueuer enqueuer) {}
}
/**
@@ -524,7 +528,7 @@
bool get analyzeAll => analyzeAllFlag || compileAll;
- bool get compileAll => mirrorsEnabled;
+ bool get compileAll => false;
bool get disableTypeInference => disableTypeInferenceFlag || mirrorsEnabled;
@@ -663,6 +667,7 @@
}
if (uri == Uri.parse('dart:mirrors')) {
mirrorSystemClass = library.find(const SourceString('MirrorSystem'));
+ backend.enableMirrors();
metadataHandler = constantHandler;
} else if (uri == Uri.parse('dart:_collection-dev')) {
symbolImplementationClass = library.find(const SourceString('Symbol'));
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index a1a2ed2..f3dae36 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -62,7 +62,6 @@
compiler.libraries.values.forEach(addMemberByName);
}
-
String get name => 'Enqueue';
EnqueueTask(Compiler compiler)
@@ -95,6 +94,8 @@
EnqueueTask task;
native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask
+ bool hasEnqueuedEverything = false;
+
Enqueuer(this.name, this.compiler,
ItemCompilationContext itemCompilationContextCreator())
: this.itemCompilationContextCreator = itemCompilationContextCreator;
@@ -342,40 +343,45 @@
for (var link = task.allElementsByName[name];
link != null && !link.isEmpty;
link = link.tail) {
- Element element = link.head;
- if (Elements.isUnresolved(element)) {
- // Ignore.
- } else if (element.isConstructor()) {
- ClassElement cls = element.declaration.getEnclosingClass();
- registerInstantiatedType(cls.rawType, elements);
- registerStaticUse(element.declaration);
- } else if (element.impliesType()) {
- // Don't enqueue classes, typedefs, and type variables.
- } else if (Elements.isStaticOrTopLevel(element)) {
- registerStaticUse(element.declaration);
- } else if (element.isInstanceMember()) {
- if (element.isFunction()) {
- int arity =
- element.asFunctionElement().requiredParameterCount(compiler);
- Selector selector =
- new Selector.call(element.name, element.getLibrary(), arity);
- registerInvocation(element.name, selector);
- } else if (element.isSetter()) {
- Selector selector =
- new Selector.setter(element.name, element.getLibrary());
- registerInvokedSetter(element.name, selector);
- } else if (element.isGetter()) {
- Selector selector =
- new Selector.getter(element.name, element.getLibrary());
- registerInvokedGetter(element.name, selector);
- } else if (element.isField()) {
- Selector selector =
- new Selector.setter(element.name, element.getLibrary());
- registerInvokedSetter(element.name, selector);
- selector =
- new Selector.getter(element.name, element.getLibrary());
- registerInvokedGetter(element.name, selector);
- }
+ pretendElementWasUsed(link.head, elements);
+ }
+ }
+
+ void pretendElementWasUsed(Element element, TreeElements elements) {
+ if (Elements.isUnresolved(element)) {
+ // Ignore.
+ } else if (element.isSynthesized
+ && element.getLibrary().isPlatformLibrary) {
+ // TODO(ahe): Work-around for http://dartbug.com/11205.
+ } else if (element.isConstructor()) {
+ ClassElement cls = element.declaration.getEnclosingClass();
+ registerInstantiatedType(cls.rawType, elements);
+ registerStaticUse(element.declaration);
+ } else if (element.impliesType()) {
+ // Don't enqueue classes, typedefs, and type variables.
+ } else if (Elements.isStaticOrTopLevel(element)) {
+ registerStaticUse(element.declaration);
+ } else if (element.isInstanceMember()) {
+ if (element.isFunction()) {
+ int arity =
+ element.asFunctionElement().requiredParameterCount(compiler);
+ Selector selector =
+ new Selector.call(element.name, element.getLibrary(), arity);
+ registerInvocation(element.name, selector);
+ } else if (element.isSetter()) {
+ Selector selector =
+ new Selector.setter(element.name, element.getLibrary());
+ registerInvokedSetter(element.name, selector);
+ } else if (element.isGetter()) {
+ Selector selector =
+ new Selector.getter(element.name, element.getLibrary());
+ registerInvokedGetter(element.name, selector);
+ } else if (element.isField()) {
+ Selector selector =
+ new Selector.setter(element.name, element.getLibrary());
+ registerInvokedSetter(element.name, selector);
+ selector = new Selector.getter(element.name, element.getLibrary());
+ registerInvokedGetter(element.name, selector);
}
}
}
@@ -384,6 +390,18 @@
void registerNewSymbol(TreeElements elements) {
}
+ void enqueueEverything() {
+ if (hasEnqueuedEverything) return;
+ compiler.log('Enqueuing everything');
+ task.ensureAllElementsByName();
+ for (Link link in task.allElementsByName.values) {
+ for (Element element in link) {
+ pretendElementWasUsed(element, compiler.globalDependencies);
+ }
+ }
+ hasEnqueuedEverything = true;
+ }
+
processLink(Map<String, Link<Element>> map,
SourceString n,
bool f(Element e)) {
@@ -456,6 +474,7 @@
if (element == null) return;
assert(invariant(element, element.isDeclaration));
addToWorkList(element);
+ compiler.backend.registerStaticUse(element, this);
}
void registerGetOfStaticFunction(FunctionElement element) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 419f521..87e7294 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -75,7 +75,6 @@
HType mutableArrayType;
HType fixedArrayType;
HType extendableArrayType;
-
// TODO(9577): Make it so that these are not needed when there are no native
// classes.
@@ -156,6 +155,14 @@
final RuntimeTypes rti;
+ /// Holds the method "disableTreeShaking" in js_mirrors when
+ /// dart:mirrors has been loaded.
+ FunctionElement disableTreeShakingMarker;
+
+ /// Holds the method "preserveNames" in js_mirrors when
+ /// dart:mirrors has been loaded.
+ FunctionElement preserveNamesMarker;
+
JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
: namer = determineNamer(compiler),
usedInterceptors = new Set<Selector>(),
@@ -1114,4 +1121,19 @@
ClassElement get typeImplementation => typeLiteralClass;
ClassElement get boolImplementation => jsBoolClass;
ClassElement get nullImplementation => jsNullClass;
+
+ void enableMirrors() {
+ LibraryElement library = compiler.libraries['dart:_js_mirrors'];
+ disableTreeShakingMarker =
+ library.find(const SourceString('disableTreeShaking'));
+ preserveNamesMarker =
+ library.find(const SourceString('preserveNames'));
+ }
+
+ void registerStaticUse(Element element, Enqueuer enqueuer) {
+ if (element == disableTreeShakingMarker) {
+ enqueuer.enqueueEverything();
+ } else if (element == preserveNamesMarker) {
+ }
+ }
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index 1396a72..e4d3ce1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -214,44 +214,6 @@
return calledInLoop;
}
- // Returns whether an invocation of [selector] on [receiver] will throw a
- // [ArgumentError] if the argument is not of the right type.
- bool willThrowArgumentError(Selector selector,
- HInstruction receiver,
- HType speculativeType) {
- if (receiver != null
- && (receiver.isInteger() || receiver.isString(compiler))) {
- return selector.isOperator()
- && selector.name != const SourceString('==')
- && (speculativeType.isNumber() && !speculativeType.isInteger());
- }
- return false;
- }
-
- // Returns whether an invocation of [selector] will throw a
- // [NoSuchMethodError] if the receiver is not of the type
- // [speculativeType].
- bool willThrowNoSuchMethodErrorIfNot(Selector selector,
- HType speculativeType) {
- return compiler.world.hasSingleMatch(selector)
- // In some cases, we want the receiver to be an integer,
- // but that does not mean we will get a NoSuchMethodError
- // if it's not: the receiver could be a double.
- && !speculativeType.isInteger()
- // We speculate on the [operator==] instruction, but we know it
- // will never throw a [NoSuchMethodError].
- && selector.name != const SourceString('==');
- }
-
- bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) {
- if (!speculativeType.isUseful()) return false;
- // If the types agree we don't need to check.
- if (speculativeType == instruction.instructionType) return false;
- // If a bailout check is more expensive than doing the actual operation
- // don't do it either.
- return typeGuardWouldBeValuable(instruction, speculativeType);
- }
-
HInstruction computeFirstDominatingUserWithSelector(
HInstruction instruction) {
// TODO(ngeoffray): We currently only look at the instruction's
@@ -283,49 +245,43 @@
bool tryTypeConversion(HInstruction instruction, HType speculativeType) {
HInstruction firstUser =
computeFirstDominatingUserWithSelector(instruction);
- if (firstUser == null) return false;
+ if (firstUser is !HInvokeDynamic) return false;
// If we have found a user with a selector, we find out if it
- // will throw [NoSuchMethodError] or [ArgumentError].
+ // will throw [NoSuchMethodError] or [ArgumentError]. If it does,
+ // then we change just add a [HTypeConversion] instruction and
+ // avoid a bailout.
Selector selector = firstUser.selector;
- Selector receiverSelectorOnThrow = null;
+ if (!selector.isOperator()) return false;
HInstruction receiver = firstUser.getDartReceiver(compiler);
- bool willThrow = false;
- if (receiver == instruction) {
- if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) {
- receiverSelectorOnThrow = selector;
- willThrow = true;
- }
- // We need to call the actual method in checked mode to get
- // the right type error.
- } else if (!compiler.enableTypeAssertions
- && willThrowArgumentError(selector, receiver, speculativeType)) {
- willThrow = true;
+
+ if (instruction == receiver) {
+ // If the instruction on which we're speculating the
+ // type is the receiver of the call, check if it will throw
+ // [NoSuchMethodError] if [instruction] is not of the speculated
+ // type.
+ return checkReceiver(firstUser);
+ } else if (!selector.isUnaryOperator()
+ && instruction == firstUser.inputs[2]) {
+ // If the instruction is a parameter of the call, we check if
+ // the method will throw an [ArgumentError] if [instruction] is
+ // not of the speculated type.
+ return checkArgument(firstUser);
}
-
- if (!willThrow) return false;
-
- HTypeConversion check = new HTypeConversion(
- null,
- receiverSelectorOnThrow == null
- ? HTypeConversion.ARGUMENT_TYPE_CHECK
- : HTypeConversion.RECEIVER_TYPE_CHECK,
- speculativeType,
- instruction,
- receiverSelectorOnThrow);
- hasInsertedChecks = true;
- firstUser.block.addBefore(firstUser, check);
- instruction.replaceAllUsersDominatedBy(firstUser, check);
- return true;
+ return false;
}
bool updateType(HInstruction instruction) {
bool hasChanged = super.updateType(instruction);
HType speculativeType = savedTypes[instruction];
- if (speculativeType == null) return hasChanged;
+ if (speculativeType == null
+ || !speculativeType.isUseful()
+ || speculativeType == instruction.instructionType) {
+ return hasChanged;
+ }
- if (shouldInsertTypeGuard(instruction, speculativeType)
- && !tryTypeConversion(instruction, speculativeType)) {
+ if (!tryTypeConversion(instruction, speculativeType)
+ && typeGuardWouldBeValuable(instruction, speculativeType)) {
HInstruction insertionPoint;
if (instruction is HPhi) {
insertionPoint = instruction.block.first;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 1cd2255..61e465b 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -1215,6 +1215,7 @@
Selector selector,
List<HInstruction> providedArguments,
Node currentNode) {
+ backend.registerStaticUse(element, compiler.enqueuer.codegen);
// We cannot inline a method from a deferred library into a method
// which isn't deferred.
// TODO(ahe): But we should still inline into the same
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 01ad49e..b4f0d92 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -2421,8 +2421,14 @@
js.Expression generateTest(HCheck node) {
HInstruction input = node.checkedInput;
+ TypeMask receiver = input.instructionType.computeMask(compiler);
+ TypeMask mask = node.instructionType.computeMask(compiler);
+ bool turnIntoNullCheck = mask.nullable() == receiver;
js.Expression test;
- if (node.isInteger()) {
+ if (turnIntoNullCheck) {
+ use(input);
+ test = new js.Binary("==", pop(), new js.LiteralNull());
+ } else if (node.isInteger()) {
// input is !int
checkInt(input, '!==');
test = pop();
@@ -2486,7 +2492,7 @@
new js.Binary('||', objectTest, notIndexingTest);
test = new js.Binary('&&', stringTest, notObjectOrIndexingTest);
} else {
- compiler.internalError('Unexpected type guard', instruction: input);
+ compiler.internalError('Unexpected check', instruction: input);
}
return test;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index f86ac3c..fdfd0db 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -40,6 +40,10 @@
return null;
}
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return false;
+ }
+
Operation operation(ConstantSystem constantSystem) => null;
static InvokeDynamicSpecializer lookupSpecializer(Selector selector) {
@@ -123,6 +127,10 @@
}
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
}
class IndexSpecializer extends InvokeDynamicSpecializer {
@@ -159,6 +167,10 @@
}
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
}
class BitNotSpecializer extends InvokeDynamicSpecializer {
@@ -194,6 +206,10 @@
if (input.isNumber()) return new HBitNot(input, instruction.selector);
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
}
class UnaryNegateSpecializer extends InvokeDynamicSpecializer {
@@ -230,6 +246,10 @@
if (input.isNumber()) return new HNegate(input, instruction.selector);
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
}
abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
@@ -295,6 +315,10 @@
return null;
}
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
+
HInstruction newBuiltinVariant(HInvokeDynamic instruction);
}
@@ -352,6 +376,10 @@
// Modulo cannot be mapped to the native operator (different semantics).
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return false;
+ }
}
class MultiplySpecializer extends BinaryArithmeticSpecializer {
@@ -391,6 +419,10 @@
// Truncating divide does not have a JS equivalent.
return null;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return false;
+ }
}
abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
@@ -431,11 +463,8 @@
Compiler compiler) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
- if (!left.isNumber() || !right.isConstantInteger()) return null;
- HConstant rightConstant = right;
- IntConstant intConstant = rightConstant.constant;
- int count = intConstant.value;
- if (count >= 0 && count <= 31) {
+ if (!left.isNumber()) return null;
+ if (argumentLessThan32(right)) {
return newBuiltinVariant(instruction);
}
return null;
@@ -445,6 +474,18 @@
return new HShiftLeft(
instruction.inputs[1], instruction.inputs[2], instruction.selector);
}
+
+ bool argumentLessThan32(HInstruction instruction) {
+ if (!instruction.isConstantInteger()) return false;
+ HConstant rightConstant = instruction;
+ IntConstant intConstant = rightConstant.constant;
+ int count = intConstant.value;
+ return count >= 0 && count <= 31;
+ }
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return argumentLessThan32(instruction.inputs[2]);
+ }
}
class ShiftRightSpecializer extends BinaryBitOpSpecializer {
@@ -458,6 +499,10 @@
BinaryOperation operation(ConstantSystem constantSystem) {
return constantSystem.shiftRight;
}
+
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
}
class BitOrSpecializer extends BinaryBitOpSpecializer {
@@ -537,6 +582,10 @@
return null;
}
+ bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+ return true;
+ }
+
HInstruction newBuiltinVariant(HInvokeDynamic instruction);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index c61ff48..ce291f2 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -50,6 +50,9 @@
new SsaDeadPhiEliminator(),
new SsaConstantFolder(constantSystem, backend, work),
new SsaNonSpeculativeTypePropagator(compiler),
+ // Run a dead code eliminator before LICM because dead
+ // interceptors are often in the way of LICM'able instructions.
+ new SsaDeadCodeEliminator(),
new SsaGlobalValueNumberer(compiler),
new SsaCodeMotion(),
new SsaValueRangeAnalyzer(compiler, constantSystem, work),
@@ -1013,6 +1016,7 @@
// were visited before because we are iterating in post-order.
// So instructions that are GVN'ed in an inner loop are in their
// loop entry, and [info.blocks] contains this loop entry.
+ moveLoopInvariantCodeFromBlock(block, block, changesFlags);
for (HBasicBlock other in info.blocks) {
moveLoopInvariantCodeFromBlock(other, block, changesFlags);
}
@@ -1023,14 +1027,15 @@
void moveLoopInvariantCodeFromBlock(HBasicBlock block,
HBasicBlock loopHeader,
int changesFlags) {
- assert(block.parentLoopHeader == loopHeader);
+ assert(block.parentLoopHeader == loopHeader || block == loopHeader);
HBasicBlock preheader = loopHeader.predecessors[0];
int dependsFlags = SideEffects.computeDependsOnFlags(changesFlags);
HInstruction instruction = block.first;
+ bool firstInstructionInLoop = block == loopHeader;
while (instruction != null) {
HInstruction next = instruction.next;
if (instruction.useGvn()
- && !instruction.canThrow()
+ && (!instruction.canThrow() || firstInstructionInLoop)
&& !instruction.sideEffects.dependsOn(dependsFlags)) {
bool loopInvariantInputs = true;
List<HInstruction> inputs = instruction.inputs;
@@ -1046,6 +1051,8 @@
if (loopInvariantInputs) {
block.detach(instruction);
preheader.moveAtExit(instruction);
+ } else {
+ firstInstructionInLoop = false;
}
}
int oldChangesFlags = changesFlags;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index ff49492..188969a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -260,6 +260,10 @@
}
HType simplify(Compiler compiler) => this;
+
+ HType nonNullable(compiler) {
+ return new HType.fromMask(computeMask(compiler).nonNullable(), compiler);
+ }
}
/** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index d2ef66c..9ff7a6c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -7,17 +7,15 @@
abstract class SsaTypePropagator extends HBaseVisitor
implements OptimizationPhase {
- final Map<int, HInstruction> workmap;
- final List<int> worklist;
- final Map<HInstruction, Function> pendingOptimizations;
+ final Map<int, HInstruction> workmap = new Map<int, HInstruction>();
+ final List<int> worklist = new List<int>();
+ final Map<HInstruction, Function> pendingOptimizations =
+ new Map<HInstruction, Function>();
final Compiler compiler;
String get name => 'type propagator';
- SsaTypePropagator(this.compiler)
- : workmap = new Map<int, HInstruction>(),
- worklist = new List<int>(),
- pendingOptimizations = new Map<HInstruction, Function>();
+ SsaTypePropagator(this.compiler);
// Compute the (shared) type of the inputs if any. If all inputs
// have the same known type return it. If any two inputs have
@@ -110,6 +108,7 @@
} while (!worklist.isEmpty);
}
+
void addDependentInstructionsToWorkList(HInstruction instruction) {}
void addToWorkList(HInstruction instruction) {
@@ -121,11 +120,6 @@
}
}
- void processPendingOptimizations() {
- pendingOptimizations.forEach((instruction, action) => action());
- pendingOptimizations.clear();
- }
-
HType visitInvokeDynamic(HInvokeDynamic instruction) {
return instruction.specializer.computeTypeFromInputTypes(
instruction, compiler);
@@ -153,6 +147,107 @@
if (inputsType.isConflicting()) return HType.UNKNOWN;
return inputsType;
}
+
+ void convertInput(HInvokeDynamic instruction,
+ HInstruction input,
+ HType type,
+ int kind) {
+ Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK)
+ ? instruction.selector
+ : null;
+ HTypeConversion converted = new HTypeConversion(
+ null, kind, type, input, selector);
+ instruction.block.addBefore(instruction, converted);
+ input.replaceAllUsersDominatedBy(instruction, converted);
+ }
+
+ bool isCheckEnoughForNsmOrAe(HInstruction instruction,
+ HType type) {
+ // In some cases, we want the receiver to be an integer,
+ // but that does not mean we will get a NoSuchMethodError
+ // if it's not: the receiver could be a double.
+ if (type.isInteger()) {
+ // If the instruction's type is integer or null, the codegen
+ // will emit a null check, which is enough to know if it will
+ // hit a noSuchMethod.
+ return instruction.instructionType.isIntegerOrNull();
+ }
+ return true;
+ }
+
+ // Add a receiver type check when the call can only hit
+ // [noSuchMethod] if the receiver is not of a specific type.
+ // Return true if the receiver type check was added.
+ bool checkReceiver(HInvokeDynamic instruction) {
+ HInstruction receiver = instruction.inputs[1];
+ if (receiver.isNumber()) return false;
+ if (receiver.isNumberOrNull()) {
+ convertInput(instruction,
+ receiver,
+ receiver.instructionType.nonNullable(compiler),
+ HTypeConversion.RECEIVER_TYPE_CHECK);
+ return true;
+ } else if (instruction.element == null) {
+ Iterable<Element> targets =
+ compiler.world.allFunctions.filter(instruction.selector);
+ if (targets.length == 1) {
+ Element target = targets.first;
+ ClassElement cls = target.getEnclosingClass();
+ HType type = new HType.nonNullSubclass(cls.rawType, compiler);
+ // TODO(ngeoffray): We currently only optimize on primitive
+ // types.
+ if (!type.isPrimitive(compiler)) return false;
+ if (!isCheckEnoughForNsmOrAe(receiver, type)) return false;
+ instruction.element = target;
+ convertInput(instruction,
+ receiver,
+ type,
+ HTypeConversion.RECEIVER_TYPE_CHECK);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Add an argument type check if the argument is not of a type
+ // expected by the call.
+ // Return true if the argument type check was added.
+ bool checkArgument(HInvokeDynamic instruction) {
+ // We want the righ error in checked mode.
+ if (compiler.enableTypeAssertions) return false;
+ HInstruction left = instruction.inputs[1];
+ HType receiverType = left.instructionType;
+
+ // A [HTypeGuard] holds the speculated type when it is being
+ // inserted, so we go find the real receiver type.
+ if (left is HTypeGuard) {
+ var guard = left;
+ while (guard is HTypeGuard && !guard.isEnabled) {
+ guard = guard.checkedInput;
+ }
+ receiverType = guard.instructionType;
+ }
+ HInstruction right = instruction.inputs[2];
+ Selector selector = instruction.selector;
+ if (selector.isOperator() && receiverType.isNumber()) {
+ if (right.isNumber()) return false;
+ // TODO(ngeoffray): Some number operations don't have a builtin
+ // variant and will do the check in their method anyway. We
+ // still add a check because it allows to GVN these operations,
+ // but we should find a better way.
+ convertInput(instruction,
+ right,
+ HType.NUMBER,
+ HTypeConversion.ARGUMENT_TYPE_CHECK);
+ return true;
+ }
+ return false;
+ }
+
+ void processPendingOptimizations() {
+ pendingOptimizations.forEach((instruction, action) => action());
+ pendingOptimizations.clear();
+ }
}
class SsaNonSpeculativeTypePropagator extends SsaTypePropagator {
@@ -168,38 +263,29 @@
}
}
- void convertInput(HInstruction instruction, HInstruction input, HType type) {
- HTypeConversion converted = new HTypeConversion(
- null, HTypeConversion.ARGUMENT_TYPE_CHECK, type, input);
- instruction.block.addBefore(instruction, converted);
- Set<HInstruction> dominatedUsers = input.dominatedUsers(instruction);
- for (HInstruction user in dominatedUsers) {
- user.changeUse(input, converted);
- addToWorkList(user);
- }
+ void addAllUsersBut(HInvokeDynamic invoke, HInstruction instruction) {
+ instruction.usedBy.forEach((HInstruction user) {
+ if (user != invoke) addToWorkList(user);
+ });
}
HType visitInvokeDynamic(HInvokeDynamic instruction) {
- // Update the pending optimizations map based on the potentially
- // new types of the operands. If the operand types no longer allow
- // us to optimize, we remove the pending optimization.
- if (instruction.specializer is BinaryArithmeticSpecializer) {
- HInstruction left = instruction.inputs[1];
- HInstruction right = instruction.inputs[2];
- if (left.isNumber()
- && !right.isNumber()
- // We need to call the actual method in checked mode to get
- // the right type error.
- && !compiler.enableTypeAssertions) {
- pendingOptimizations[instruction] = () {
- // This callback function is invoked after we're done
- // propagating types. The types shouldn't have changed.
- assert(left.isNumber() && !right.isNumber());
- convertInput(instruction, right, HType.NUMBER);
- };
- } else {
- pendingOptimizations.remove(instruction);
- }
+ if (instruction.isInterceptedCall) {
+ // We cannot do the following optimization now, because we have
+ // to wait for the type propagation to be stable. The receiver
+ // of [instruction] might move from number to dynamic.
+ pendingOptimizations.putIfAbsent(instruction, () => () {
+ Selector selector = instruction.selector;
+ if (selector.isOperator()
+ && selector.name != const SourceString('==')) {
+ if (checkReceiver(instruction)) {
+ addAllUsersBut(instruction, instruction.inputs[1]);
+ }
+ if (!selector.isUnaryOperator() && checkArgument(instruction)) {
+ addAllUsersBut(instruction, instruction.inputs[2]);
+ }
+ }
+ });
}
return super.visitInvokeDynamic(instruction);
}
@@ -220,10 +306,23 @@
return HType.UNKNOWN;
}
- HType visitBoundsCheck(HBoundsCheck boundsCheck) {
+ HType visitCheck(HCheck check) {
// If the desired type of the input is already a number, we want
// to specialize it to an integer.
- if (input == boundsCheck.index && input.isNumber()) return HType.INTEGER;
+ if (input == check.checkedInput
+ && check.isInteger()
+ && check.checkedInput.isNumberOrNull()) {
+ return HType.INTEGER;
+ }
+ return HType.UNKNOWN;
+ }
+
+ HType visitTypeConversion(HTypeConversion check) {
+ // The following checks are inserted by our optimizers, so we
+ // want to optimize them even more.
+ if (check.isArgumentTypeCheck || check.isReceiverTypeCheck) {
+ return visitCheck(check);
+ }
return HType.UNKNOWN;
}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index e006fa5..25df301 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -90,6 +90,9 @@
patch static _deleteLink(String path) {
throw new UnsupportedError("File._deleteLink");
}
+ patch static _rename(String oldPath, String newPath) {
+ throw new UnsupportedError("File._delete");
+ }
patch static _lengthFromPath(String path) {
throw new UnsupportedError("File._lengthFromPath");
}
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index a4254b8..18d6e6d 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -19,7 +19,18 @@
createInvocationMirror;
import 'dart:_interceptors' show Interceptor;
-String getName(Symbol symbol) => n(symbol);
+/// No-op method that is called to inform the compiler that
+/// tree-shaking needs to be disabled.
+disableTreeShaking() => preserveNames();
+
+/// No-op method that is called to inform the compiler that unmangled
+/// named must be preserved.
+preserveNames() {}
+
+String getName(Symbol symbol) {
+ preserveNames();
+ return n(symbol);
+}
final Map<String, String> mangledNames = JsMirrorSystem.computeMangledNames();
@@ -42,6 +53,7 @@
}
static Map<String, List<LibraryMirror>> computeLibrariesByName() {
+ disableTreeShaking();
var result = new Map<String, List<LibraryMirror>>();
var jsLibraries = JS('=List|Null', 'init.libraries');
if (jsLibraries == null) return result;
@@ -61,6 +73,7 @@
}
static Map<String, String> computeMangledNames() {
+ disableTreeShaking();
var mangledNames = JS('', 'init.mangledNames');
var keys = extractKeys(mangledNames);
var result = <String, String>{};
@@ -71,6 +84,7 @@
}
static Map<String, String> computeReflectiveNames() {
+ disableTreeShaking();
var result = <String, String>{};
mangledNames.forEach((String mangledName, String reflectiveName) {
result[reflectiveName] = mangledName;
@@ -200,6 +214,7 @@
}
ClassMirror reflectClassByName(Symbol symbol) {
+ disableTreeShaking();
String className = n(symbol);
var constructor = Primitives.getConstructor(className);
if (constructor == null) {
@@ -573,6 +588,7 @@
JsClosureMirror(reflectee) : super(reflectee);
MethodMirror get function {
+ disableTreeShaking();
// TODO(ahe): What about optional parameters (named or not).
var extractCallName = JS('', r'''
function(reflectee) {
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 4700896..4813ee4 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -792,7 +792,7 @@
_PairMatcher(this._firstMatcher, this._lastMatcher);
- bool matches(item, MatchState matchState) {
+ bool matches(item, Map matchState) {
if (item is! Pair) return false;
return _firstMatcher.matches(item.first, matchState) &&
_lastMatcher.matches(item.last, matchState);
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
index a0b900a..5a9e55c 100644
--- a/sdk/lib/_internal/pub/test/version_solver_test.dart
+++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -954,7 +954,7 @@
Description describeMismatch(SolveResult result,
Description description,
- MatchState state, bool verbose) {
+ Map state, bool verbose) {
if (!result.succeeded) {
description.add('Solver failed with:\n${result.error}');
return null;
@@ -965,7 +965,7 @@
return description;
}
- bool matches(SolveResult result, MatchState state) {
+ bool matches(SolveResult result, Map state) {
if (!result.succeeded) return false;
var expected = new Map.from(_expected);
@@ -1030,12 +1030,12 @@
Description describeMismatch(SolveResult result,
Description description,
- MatchState state, bool verbose) {
+ Map state, bool verbose) {
description.add(state.state);
return description;
}
- bool matches(SolveResult result, MatchState state) {
+ bool matches(SolveResult result, Map state) {
var failures = new StringBuffer();
if (result.succeeded) {
diff --git a/sdk/lib/_internal/pub/test/version_test.dart b/sdk/lib/_internal/pub/test/version_test.dart
index e4a1b0c..6210264 100644
--- a/sdk/lib/_internal/pub/test/version_test.dart
+++ b/sdk/lib/_internal/pub/test/version_test.dart
@@ -430,14 +430,14 @@
VersionConstraintMatcher(this._expected, this._allow);
- bool matches(item, MatchState matchState) => (item is VersionConstraint) &&
+ bool matches(item, Map matchState) => (item is VersionConstraint) &&
_expected.every((version) => item.allows(version) == _allow);
Description describe(Description description) =>
description.add(' ${_allow ? "allows" : "does not allow"} versions');
Description describeMismatch(item, Description mismatchDescription,
- MatchState matchState, bool verbose) {
+ Map matchState, bool verbose) {
if (item is! VersionConstraint) {
mismatchDescription.add('was not a VersionConstraint');
return mismatchDescription;
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index 163307f..c45fcf5 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.dart
@@ -9,10 +9,16 @@
/**
* Constructs a new Symbol.
*
- * An [ArgumentError] is thrown if [name] starts with an underscore,
- * or if [name] is not a [String]. An [ArgumentError] is thrown if
- * [name] is not an empty string and is not a valid qualified
- * identifier optionally followed by [:'=':].
+ * An [ArgumentError] is thrown if [name] starts with an underscore, or if
+ * [name] is not a [String]. An [ArgumentError] is thrown if [name] is not
+ * an empty string and is not a valid qualified identifier optionally
+ * followed by [:'=':].
+ *
+ * The following text is non-normative:
+ *
+ * Creating non-const Symbol instances may result in larger output. If
+ * possible, use [MirrorsUsed] in "dart:mirrors" to specify which names might
+ * be passed to this constructor.
*/
const factory Symbol(String name) = _collection_dev.Symbol;
}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index ac1a268..450a902 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -80,6 +80,26 @@
void deleteSync();
/**
+ * Renames this file. Returns a `Future<File>` that completes
+ * with a [File] instance for the renamed file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory, the
+ * operation fails and the future completes with an exception.
+ */
+ Future<File> rename(String newPath);
+
+ /**
+ * Synchronously renames this file. Returns a [File]
+ * instance for the renamed file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory the
+ * operation fails and an exception is thrown.
+ */
+ File renameSync(String newPath);
+
+ /**
* Get a [Directory] object for the directory containing this
* file.
*/
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 59695a2..9ad3001 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -202,27 +202,28 @@
const int _EXISTS_REQUEST = 0;
const int _CREATE_REQUEST = 1;
const int _DELETE_REQUEST = 2;
-const int _OPEN_REQUEST = 3;
-const int _FULL_PATH_REQUEST = 4;
-const int _CLOSE_REQUEST = 5;
-const int _POSITION_REQUEST = 6;
-const int _SET_POSITION_REQUEST = 7;
-const int _TRUNCATE_REQUEST = 8;
-const int _LENGTH_REQUEST = 9;
-const int _LENGTH_FROM_PATH_REQUEST = 10;
-const int _LAST_MODIFIED_REQUEST = 11;
-const int _FLUSH_REQUEST = 12;
-const int _READ_BYTE_REQUEST = 13;
-const int _WRITE_BYTE_REQUEST = 14;
-const int _READ_REQUEST = 15;
-const int _READ_LIST_REQUEST = 16;
-const int _WRITE_LIST_REQUEST = 17;
-const int _CREATE_LINK_REQUEST = 18;
-const int _DELETE_LINK_REQUEST = 19;
-const int _LINK_TARGET_REQUEST = 20;
-const int _TYPE_REQUEST = 21;
-const int _IDENTICAL_REQUEST = 22;
-const int _STAT_REQUEST = 23;
+const int _RENAME_REQUEST = 3;
+const int _OPEN_REQUEST = 4;
+const int _FULL_PATH_REQUEST = 5;
+const int _CLOSE_REQUEST = 6;
+const int _POSITION_REQUEST = 7;
+const int _SET_POSITION_REQUEST = 8;
+const int _TRUNCATE_REQUEST = 9;
+const int _LENGTH_REQUEST = 10;
+const int _LENGTH_FROM_PATH_REQUEST = 11;
+const int _LAST_MODIFIED_REQUEST = 12;
+const int _FLUSH_REQUEST = 13;
+const int _READ_BYTE_REQUEST = 14;
+const int _WRITE_BYTE_REQUEST = 15;
+const int _READ_REQUEST = 16;
+const int _READ_LIST_REQUEST = 17;
+const int _WRITE_LIST_REQUEST = 18;
+const int _CREATE_LINK_REQUEST = 19;
+const int _DELETE_LINK_REQUEST = 20;
+const int _LINK_TARGET_REQUEST = 21;
+const int _TYPE_REQUEST = 22;
+const int _IDENTICAL_REQUEST = 23;
+const int _STAT_REQUEST = 24;
// TODO(ager): The only reason for this class is that the patching
// mechanism doesn't seem to like patching a private top level
@@ -316,6 +317,29 @@
throwIfError(result, "Cannot delete file '$_path'");
}
+ Future<File> rename(String newPath) {
+ _ensureFileService();
+ List request = new List(3);
+ request[0] = _RENAME_REQUEST;
+ request[1] = _path;
+ request[2] = newPath;
+ return _fileService.call(request).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot rename file '$_path' to '$newPath'");
+ }
+ return new File(newPath);
+ });
+ }
+
+ external static _rename(String oldPath, String newPath);
+
+ File renameSync(String newPath) {
+ var result = _rename(_path, newPath);
+ throwIfError(result, "Cannot rename file '$_path' to '$newPath'");
+ return new File(newPath);
+ }
+
Directory get directory {
Path path = new Path(_path).directoryPath;
return new Directory.fromPath(path);
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index e82d329..7a59c19 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -468,6 +468,7 @@
if (_headersWritten) return new Future.value();
_headersWritten = true;
headers._synchronize(); // Be sure the 'chunked' option is updated.
+ _dataSink.encoding = encoding;
bool isServerSide = this is _HttpResponse;
if (isServerSide) {
var response = this;
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 6b36f30..f6ba0c9 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -95,6 +95,14 @@
*/
TypeMirror get voidType;
+ /**
+ * Returns the name of [symbol].
+ *
+ * The following text is non-normative:
+ *
+ * Using this method may result in larger output. If possible, use
+ * [MirrorsUsed] to specify which symbols must be retained in clear text.
+ */
external static String getName(Symbol symbol);
}
@@ -112,8 +120,7 @@
/**
* Returns an [InstanceMirror] for some Dart language object.
*
- * This only works if this mirror system is associated with the
- * current running isolate.
+ * This only works with objects local to the current isolate.
*/
external InstanceMirror reflect(Object reflectee);
@@ -225,6 +232,15 @@
/**
* A list of the metadata associated with this declaration.
+ *
+ * Let *D* be the declaration this mirror reflects.
+ * If *D* is decorated with annotations *A1, ..., An*
+ * where *n > 0*, then for each annotation *Ai* associated
+ * with *D, 1 <= i <= n*, let *ci* be the constant object
+ * specified by *Ai*. Then this method returns a list whose
+ * members are instance mirrors on *c1, ..., cn*.
+ * If no annotations are associated with *D*, then
+ * an empty list is returned.
*/
List<InstanceMirror> get metadata;
}
@@ -309,7 +325,7 @@
* the the result is a [MirrorError] wrapping *e*.
*/
/* TODO(turnidge): Handle ambiguous names.*/
- InstanceMirror setField(Symbol fieldName, Object arg);
+ InstanceMirror setField(Symbol fieldName, Object value);
/**
* Invokes the named function and returns a mirror on the result.
@@ -345,8 +361,8 @@
* TODO(turnidge): Handle optional & named arguments.
*/
Future<InstanceMirror> invokeAsync(Symbol memberName,
- List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]);
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
/**
* Invokes a getter and returns a mirror on the result. The getter
@@ -373,7 +389,7 @@
* Invokes a setter and returns a mirror on the result. The setter
* may be either the implicit setter for a non-final field or a
* user-defined setter method.
- * The argument must be an instance of [InstanceMirror], or of
+ * The second argument must be an instance of [InstanceMirror], or of
* a type that is serializable across isolates (currently [num],
* [String], or [bool]).
*
@@ -481,8 +497,8 @@
* If the invocation throws an exception *e* (that it does not catch)
* the the result is a [MirrorError] wrapping *e*.
*/
- InstanceMirror apply(List<Object> positionalArguments,
- [Map<Symbol,Object> namedArguments]);
+ InstanceMirror apply(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
/**
* Executes the closure and returns a mirror on the result.
@@ -511,8 +527,8 @@
* a type that is serializable across isolates (currently [num],
* [String], or [bool]).
*/
- Future<InstanceMirror> applyAsync(List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]);
+ Future<InstanceMirror> applyAsync(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
/**
* Looks up the value of a name in the scope of the closure. The
@@ -754,8 +770,8 @@
* then *k* is completed with a [MirrorError] wrapping *e*.
*/
Future<InstanceMirror> newInstanceAsync(Symbol constructorName,
- List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]);
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]);
/**
* Does this mirror represent a class?
@@ -1078,3 +1094,104 @@
const Comment(this.text, this.trimmedText, this.isDocComment);
}
+
+/**
+ * EXPERIMENTAL API: Description of how "dart:mirrors" is used.
+ *
+ * When used as metadata on an import of "dart:mirrors" in library *L*, this
+ * class describes how "dart:mirrors" is used by library *L* unless overridden.
+ * See [override].
+ *
+ * The following text is non-normative:
+ *
+ * In some scenarios, for example, when minifying Dart code, or when generating
+ * JavaScript code from a Dart program, the size and performance of the output
+ * can suffer from use of reflection. In those cases, telling the compiler
+ * what is used, can have a significant impact.
+ *
+ * Example usage:
+ *
+ * [:
+ * @MirrorsUsed(symbols: 'foo', override: '*')
+ * import 'dart:mirrors';
+ *
+ * class Foo {
+ * noSuchMethod(Invocation invocation) {
+ * print(Mirrors.getName(invocation.memberName));
+ * }
+ * }
+ *
+ * main() {
+ * new Foo().foo(); // Prints "foo".
+ * new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
+ * }
+ * :]
+ */
+// TODO(ahe): Remove ", override: '*'" when it isn't necessary anymore.
+class MirrorsUsed {
+ // Note: the fields of this class are untyped. This is because the most
+ // convenient way to specify to specify symbols today is using a single
+ // string. In some cases, a const list of classes might be convenient. Some
+ // might prefer to use a const list of symbols.
+
+ /**
+ * The list of strings passed to new [Symbol], and symbols that might be
+ * passed to [MirrorSystem.getName].
+ *
+ * Combined with the names of [reflectiveTarget], [metaTargets] and their
+ * members, this forms the complete list of strings passed to new [Symbol],
+ * and symbols that might be passed to [MirrorSystem.getName] by the library
+ * to which this metadata applies.
+ *
+ * The following text is non-normative:
+ *
+ * Specifying this option turns off the following warnings emitted by
+ * dart2js:
+ *
+ * * Using "MirrorSystem.getName" may result in larger output.
+ * * Using "new #{name}" may result in larger output.
+ *
+ * Use symbols = "*" to turn off the warnings mentioned above.
+ *
+ * For example, if using [noSuchMethod] to interact with a database, extract
+ * all the possible column names and include them in this list. Similarly,
+ * if using [noSuchMethod] to interact with another language (JavaScript, for
+ * example) extract all the identifiers from API used and include them in
+ * this list.
+ */
+ final symbols;
+
+ /**
+ * A list of reflective targets.
+ *
+ * Combined with [metaTargets], this provides the complete list of reflective
+ * targets used by the library to which this metadata applies.
+ *
+ * The following text is non-normative:
+ *
+ * For now, there is no formal description of what a reflective target is.
+ * Informally, it is a list of things that are expected to have fully
+ * functional mirrors.
+ */
+ final targets;
+
+ /**
+ * A list of classes that when used as metadata indicates a reflective
+ * target.
+ *
+ * See [targets].
+ */
+ final metaTargets;
+
+ /**
+ * A list of library names or "*".
+ *
+ * When used as metadata on an import of "dart:mirrors", this metadata does
+ * not apply to the library in which the annotation is used, but instead
+ * applies to the other libraries (all libraries if "*" is used).
+ */
+ final override;
+
+ const MirrorsUsed(
+ {this.symbols, this.targets, this.metaTargets, this.override});
+}
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 8e13499..065b1c1 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -3,6 +3,19 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2dart ]
+
+# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
+LibTest/core/double/floor_A01_t05: Fail # issue 428
+LibTest/core/double/ceil_A01_t05: Fail # issue 428
+Language/12_Statements/02_Expression_Statements_A01_t06: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t10: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t08: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t04: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t03: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t02: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t01: Fail # co19 issue 428
+Language/11_Expressions/01_Constants_A01_t01: Fail # co19 issue 428
+
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: Fail # TODO(dart2dart-team): Please triage this failure.
Language/07_Classes/9_Superclasses/1_Inheritance_and_Overriding_A01_t03: Fail # TODO(dart2dart-team): Please triage this failure.
Language/11_Expressions/01_Constants_A18_t06: Fail # TODO(dart2dart-team): Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index b38e62f..6a518b5 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -7,6 +7,19 @@
Language/07_Classes/6_Constructors_A02_t01: Skip # co19 issue 415.
[ $compiler == none && $runtime == vm ]
+
+# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
+LibTest/core/double/floor_A01_t05: Fail # issue 428
+LibTest/core/double/ceil_A01_t05: Fail # issue 428
+Language/12_Statements/02_Expression_Statements_A01_t06: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t10: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t08: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t04: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t03: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t02: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t01: Fail # co19 issue 428
+Language/11_Expressions/01_Constants_A01_t01: Fail # co19 issue 428
+
Language/05_Variables/05_Variables_A07_t01: Fail # TODO(vm-team): Please triage this failure.
Language/05_Variables/05_Variables_A07_t02: Fail # TODO(vm-team): Please triage this failure.
Language/05_Variables/05_Variables_A07_t03: Fail # TODO(vm-team): Please triage this failure.
diff --git a/tests/compiler/dart2js/code_motion_test.dart b/tests/compiler/dart2js/code_motion_test.dart
index 0259492..e45095a 100644
--- a/tests/compiler/dart2js/code_motion_test.dart
+++ b/tests/compiler/dart2js/code_motion_test.dart
@@ -7,14 +7,16 @@
const String TEST_ONE = r"""
foo(int a, int b, bool param2) {
+ // Make sure a and b become numbers.
+ var c = a - b;
for (int i = 0; i < 1; i++) {
- var x = a + 5; // '+' is now GVNed.
if (param2) {
print(a + b);
} else {
print(a + b);
}
}
+ return c;
}
""";
diff --git a/tests/compiler/dart2js/gvn_test.dart b/tests/compiler/dart2js/gvn_test.dart
index b648bca..85bfad9 100644
--- a/tests/compiler/dart2js/gvn_test.dart
+++ b/tests/compiler/dart2js/gvn_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "package:expect/expect.dart";
import 'compiler_helper.dart';
const String TEST_ONE = r"""
@@ -60,6 +61,49 @@
}
""";
+// Check that a gvn'able instruction in the loop header gets hoisted.
+const String TEST_SIX = r"""
+class A {
+ final field = 54;
+}
+
+main() {
+ var a = new A();
+ while (a.field == 54) { a.field = 42; }
+}
+""";
+
+// Check that a gvn'able instruction that may throw in the loop header
+// gets hoisted.
+const String TEST_SEVEN = r"""
+class A {
+ final field;
+ A() : field = null;
+ A.bar() : field = 42;
+}
+
+main() {
+ var a = new A();
+ var b = new A.bar();
+ while (a.field == 54) { a.field = 42; b.field = 42; }
+}
+""";
+
+// Check that a check in a loop header gets hoisted.
+const String TEST_EIGHT = r"""
+class A {
+ final field;
+ A() : field = null;
+ A.bar() : field = 42;
+}
+
+main() {
+ var a = new A();
+ var b = new A.bar();
+ for (int i = 0; i < a.field; i++) { a.field = 42; b.field = 42; }
+}
+""";
+
main() {
String generated = compile(TEST_ONE, entry: 'foo');
RegExp regexp = new RegExp(r"1 \+ [a-z]+");
@@ -77,4 +121,13 @@
generated = compileAll(TEST_FIVE);
checkNumberOfMatches(
new RegExp("get\\\$foo").allMatches(generated).iterator, 1);
+
+ generated = compileAll(TEST_SIX);
+ Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
+
+ generated = compileAll(TEST_SEVEN);
+ Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
+
+ generated = compileAll(TEST_EIGHT);
+ Expect.isTrue(generated.contains('for (; i < t1; ++i)'));
}
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index e0f544d..9b9da69 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -17,7 +17,7 @@
const String TEST_TWO = r"""
foo(a) {
- var myVariableName = a + 42;
+ var myVariableName = a.toString();
print(myVariableName);
print(myVariableName);
}
@@ -42,7 +42,7 @@
// Check that one-shot interceptors preserve variable names, see
// https://code.google.com/p/dart/issues/detail?id=8106.
generated = compile(TEST_TWO, entry: 'foo');
- Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.\$add\$n\(a, 42\)')));
+ Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.toString\$0\(a\)')));
Expect.isTrue(generated.contains('myVariableName'));
// Check that an intercepted getter that does not need to be
diff --git a/tests/compiler/dart2js/is_inference_test.dart b/tests/compiler/dart2js/is_inference_test.dart
index 7bb12fb..d648913 100644
--- a/tests/compiler/dart2js/is_inference_test.dart
+++ b/tests/compiler/dart2js/is_inference_test.dart
@@ -7,6 +7,7 @@
const String TEST_IF = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is int) {
param = param + 42;
}
@@ -16,6 +17,7 @@
const String TEST_IF_ELSE = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is int) {
param = param + 42;
} else {
@@ -27,6 +29,7 @@
const String TEST_IF_RETURN = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is int) {
return param + 42;
}
@@ -36,6 +39,7 @@
const String TEST_IF_NOT_ELSE = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is !int) {
param = param + 53;
} else {
@@ -47,6 +51,7 @@
const String TEST_IF_NOT_RETURN = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is !int) return param + 53;
return param + 42;
}
@@ -54,6 +59,7 @@
const String TEST_IF_NOT_ELSE_RETURN = r"""
test(param) {
+ print('Printing this ensures that String+ is in the system.');
if (param is !int) {
return param + 53;
} else {
diff --git a/tests/compiler/dart2js/mirror_tree_shaking_test.dart b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
new file mode 100644
index 0000000..7025c41
--- /dev/null
+++ b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
@@ -0,0 +1,64 @@
+// 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 tree-shaking hasn't been turned off.
+
+import 'package:expect/expect.dart';
+import 'memory_source_file_helper.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ show NullSink;
+
+import '../../../sdk/lib/_internal/compiler/compiler.dart'
+ show Diagnostic;
+
+import 'dart:async';
+
+main() {
+ Uri script = currentDirectory.resolve(nativeToUriPath(new Options().script));
+ Uri libraryRoot = script.resolve('../../../sdk/');
+ Uri packageRoot = script.resolve('./packages/');
+
+ MemorySourceFileProvider.MEMORY_SOURCE_FILES = MEMORY_SOURCE_FILES;
+ var provider = new MemorySourceFileProvider();
+ void diagnosticHandler(Uri uri, int begin, int end,
+ String message, Diagnostic kind) {
+ if (kind == Diagnostic.VERBOSE_INFO || kind == Diagnostic.WARNING) {
+ return;
+ }
+ throw '$uri:$begin:$end:$message:$kind';
+ }
+
+ EventSink<String> outputProvider(String name, String extension) {
+ return new NullSink('$name.$extension');
+ }
+
+ Compiler compiler = new Compiler(provider.readStringFromUri,
+ outputProvider,
+ diagnosticHandler,
+ libraryRoot,
+ packageRoot,
+ []);
+ compiler.run(Uri.parse('memory:main.dart'));
+ Expect.isFalse(compiler.compilationFailed);
+ Expect.isFalse(compiler.enqueuer.resolution.hasEnqueuedEverything);
+ Expect.isFalse(compiler.enqueuer.codegen.hasEnqueuedEverything);
+}
+
+const Map MEMORY_SOURCE_FILES = const {
+ 'main.dart': r"""
+import 'dart:mirrors';
+
+class Foo {
+ noSuchMethod(invocation) {
+ print('Invoked ${MirrorSystem.getName(invocation.memberName)}');
+ return reflect('foobar').delegate(invocation);
+ }
+}
+
+void main() {
+ print(new Foo().substring(3));
+}
+""",
+};
diff --git a/tests/compiler/dart2js/value_range_test.dart b/tests/compiler/dart2js/value_range_test.dart
index 474d2a1..940b615 100644
--- a/tests/compiler/dart2js/value_range_test.dart
+++ b/tests/compiler/dart2js/value_range_test.dart
@@ -159,7 +159,7 @@
main(value) {
// Force [value] to be an int by having the speculative optimizer
// want an int.
- int sum = 0;
+ int sum = ~value;
for (int i = 0; i < 42; i++) sum += (value & 4);
var a = new List();
if (value > a.length - 1) return;
@@ -173,7 +173,7 @@
main(value) {
// Force [value] to be an int by having the speculative optimizer
// want an int.
- int sum = 0;
+ int sum = ~value;
for (int i = 0; i < 42; i++) sum += (value & 4);
var a = new List();
if (value <= a.length - 1) {
@@ -188,7 +188,7 @@
main(value) {
// Force [value] to be an int by having the speculative optimizer
// want an int.
- int sum = 0;
+ int sum = ~value;
for (int i = 0; i < 42; i++) sum += (value & 4);
var a = new List();
if (value >= a.length) return;
@@ -261,6 +261,7 @@
operator ==(other) {}
}
class JSInt extends JSNumber {
+ operator~() => this;
}
class JSDouble extends JSNumber {
}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 527f220..f449e11 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -138,33 +138,8 @@
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari ) ]
isolate_stress_test: Pass, Timeout # http://dartbug.com/10697
-[ $arch == simarm && $mode == debug ]
-message_test: Crash # Issue: 11207
-unresolved_ports_test: Pass, Crash # Issue: 11207
-
-[ ($arch == arm || $arch == simarm) && $checked ]
-count_test: Pass, Crash # Issue: 11207
-isolate_complex_messages_test: Pass, Crash # Issue: 11207
-mandel_isolate_test: Pass, Crash # Issue 11207
-cross_isolate_message_test: Pass, Crash # Issue: 11207
-nested_spawn_test: Pass, Crash # Issue: 11207
-
[ $arch == arm || $arch == simarm ]
-request_reply_test: Pass, Crash # Issue: 11207
-nested_spawn_test: Pass, Crash # Issue: 11207
-nested_spawn2_test: Pass, Crash # Issue: 11207
-count_stream_test: Pass, Crash # Issue: 11207
-cross_isolate_message_stream_test: Crash # Issue: 11207
-mandel_isolate_stream_test: Crash # Issue: 11207
-message2_test: Pass, Crash # Issue: 11207
-message_stream2_test: Crash # Issue: 11207
-nested_spawn_stream_test: Crash, Pass # Issue: 11207
-nested_spawn_stream2_test: Pass, Crash # Issue: 11207
-spawn_function_negative_test: Pass, Crash # Issue: 11207
-spawn_uri_vm_negative_test: Crash, Pass # Issue: 11207 (Pass on Mac)
-stream_mangling_test: Crash # Issue: 11207
-message_test: Pass, Crash # Issue: 11207
-mint_maker_test: Pass, Crash # Issue: 11207
+*: Skip
[ $arch == mips ]
*: Skip
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 456c164..27a984d 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -173,7 +173,6 @@
syntax_test/31: fail
syntax_test/32: fail
syntax_test/33: fail
-ternary_test: fail
throw7_negative_test: fail
type_error_test: fail
type_parameter_test/01: fail
@@ -196,8 +195,6 @@
type_variable_bounds_test/09: fail
type_variable_identifier_expression_negative_test: fail
type_variable_static_context_negative_test: fail
-unary2_test: fail
-unary_test: fail
unresolved_in_factory_negative_test: fail
unresolved_top_level_method_negative_test: fail
unresolved_top_level_var_negative_test: fail
diff --git a/tests/language/ternary_test.dart b/tests/language/ternary_test.dart
index 6549990..b20c188 100644
--- a/tests/language/ternary_test.dart
+++ b/tests/language/ternary_test.dart
@@ -9,11 +9,11 @@
static true_cond() { return true; }
static false_cond() { return false; }
static foo() { return -4; }
- static moo() { return +5; }
+ static moo() { return 5; }
static testMain() {
Expect.equals(-4, (TernaryTest.true_cond() ? TernaryTest.foo()
: TernaryTest.moo()));
- Expect.equals(+5, (TernaryTest.false_cond() ? TernaryTest.foo()
+ Expect.equals(5, (TernaryTest.false_cond() ? TernaryTest.foo()
: TernaryTest.moo()));
}
}
diff --git a/tests/language/unary2_test.dart b/tests/language/unary2_test.dart
index 81d3335..19b4825 100644
--- a/tests/language/unary2_test.dart
+++ b/tests/language/unary2_test.dart
@@ -7,10 +7,9 @@
class UnaryTest {
static foo() { return -4; }
- static moo() { return +5; }
+ static moo() { return 5; }
static testMain() {
Expect.equals(1, (UnaryTest.foo() + UnaryTest.moo()));
- var x = +.5; // Legal number, '+' is not a unary operator.
}
}
diff --git a/tests/language/unary_test.dart b/tests/language/unary_test.dart
index a4001e7..08a6ced 100644
--- a/tests/language/unary_test.dart
+++ b/tests/language/unary_test.dart
@@ -8,7 +8,7 @@
class UnaryTest {
static foo() { return 4; }
- static moo() { return +5; }
+ static moo() { return 5; }
static testMain() {
Expect.equals(9.0, (UnaryTest.foo() + UnaryTest.moo()));
}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index cdf2a9d..ed775e2 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -20,13 +20,15 @@
typed_data/byte_data_test: Fail, OK # d8/ie9 doesn't support DataView
[ $compiler == dart2js && $minified ]
+mirrors/metadata_test: Fail
mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # Issue 6490
mirrors/disable_tree_shaking_test: Fail # Issue 6490
mirrors/reflect_model_test: Fail # Issue 6490
[ $csp ]
-mirrors/metadata_test: Fail # Issue 6490
+mirrors/library_metadata_test: Fail # Issue 10906
+mirrors/metadata_test: Fail # Issue 10906
mirrors/reflect_runtime_type_test: Fail # Issue 6490
mirrors/reflect_uninstantiated_class_test: Fail # Issue 6490
mirrors/superclass_test: Fail # Issue 6490
@@ -62,10 +64,12 @@
# implement timer (currently only in d8)
[ $compiler == dart2dart ]
+mirrors/metadata_test: Fail
mirrors/mirrors_test: Fail # Issue 10957
mirrors/library_uri_package_test: Fail # Issue 10957
async/run_async6_test: Fail # Issue 10957 - may be related to issue 10910
mirrors/reflect_model_test: Fail # http://dartbug.com/11219
+mirrors/disable_tree_shaking_test: Fail
[ $compiler == dart2dart && $minified ]
json/json_test: Fail # Issue 10961
@@ -75,7 +79,6 @@
typed_data/float32x4_unbox_regress_test: Fail # Issue 10961
mirrors/reflect_runtime_type_test: Fail
mirrors/reflect_uninstantiated_class_test: Fail
-mirrors/disable_tree_shaking_test: Fail
[ $runtime == ff ]
@@ -101,7 +104,7 @@
[ $runtime == vm || ($compiler == none && $runtime == drt) ]
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
-mirrors/metadata_test: Fail # http://dartbug.com/10906
+mirrors/library_metadata_test: Fail # http://dartbug.com/10906
mirrors/superclass_test: Fail # http://dartbug.com/11142
mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # http://dartbug.com/11187
mirrors/reflect_model_test: Fail # http://dartbug.com/11219
@@ -119,33 +122,7 @@
[ $arch == arm || $arch == simarm ]
-async/future_test: Pass, Crash # Issue: 11207
-async/run_async6_test: Pass, Fail # Issue: 11207
-async/run_async_test: Pass, Crash # Issue: 11207
-async/slow_consumer2_test: Pass, Crash # Issue: 11207
-async/slow_consumer3_test: Pass, Crash # Issue: 11207
-async/slow_consumer_test: Pass, Crash # Issue: 11207
-async/stream_controller_async_test: Pass, Crash # Issue: 11207
-async/stream_controller_test: Timeout, Pass, Crash # Issue: 11207
-async/stream_from_iterable_test: Pass, Crash # Issue: 11207
-async/stream_periodic2_test: Pass, Crash # Issue: 11207
-async/stream_periodic3_test: Pass, Crash # Issue: 11207
-async/stream_periodic4_test: Pass, Crash # Issue: 11207
-async/stream_periodic5_test: Pass, Crash # Issue: 11207
-async/stream_single_to_multi_subscriber_test: Pass, Crash # Issue: 11207
-async/stream_state_nonzero_timer_test: Pass, Crash # Issue: 11207
-async/stream_state_test: Pass, Crash # Issue: 11207
-async/stream_subscription_as_future_test: Pass, Crash # Issue: 11207
-async/stream_transform_test: Pass, Crash # Issue: 11207
-async/timer_cancel1_test: Pass, Crash # Issue: 11207
-async/timer_cancel2_test: Pass, Crash # Issue: 11207
-math/pi_test: Crash, Fail # Issue: 11207
-math/random_test: Fail # Issue: 11207
-mirrors/reflect_model_test: Pass, Crash # Issue: 11207
-typed_data/float32x4_list_test: Crash # Issue: 11207
-typed_data/float32x4_test: Crash # Issue: 11207
-typed_data/float32x4_unbox_phi_test: Crash # Issue: 11207
-typed_data/float32x4_unbox_regress_test: Crash # Issue: 11207
+*: Skip
[ $arch == mips ]
*: Skip
diff --git a/tests/lib/math/math2_test.dart b/tests/lib/math/math2_test.dart
index 2f741d4..7ba8c3f 100644
--- a/tests/lib/math/math2_test.dart
+++ b/tests/lib/math/math2_test.dart
@@ -209,6 +209,11 @@
Expect.equals(9, int.parse("09"));
Expect.equals(9, int.parse(" 09 "));
Expect.equals(-9, int.parse("-09"));
+ Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+ Expect.equals(0x1234567890, int.parse(" +0x1234567890 "));
+ Expect.equals(0x100, int.parse("+0x100"));
+ Expect.equals(0x100, int.parse(" +0x100 "));
+
Expect.equals(true, parseIntThrowsFormatException("1b"));
Expect.equals(true, parseIntThrowsFormatException(" 1b "));
Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
@@ -236,10 +241,6 @@
Expect.equals(true, parseIntThrowsFormatException("- 5"));
Expect.equals(true, parseIntThrowsFormatException(""));
Expect.equals(true, parseIntThrowsFormatException(" "));
- Expect.equals(true, parseIntThrowsFormatException("+0x1234567890"));
- Expect.equals(true, parseIntThrowsFormatException(" +0x1234567890 "));
- Expect.equals(true, parseIntThrowsFormatException("+0x100"));
- Expect.equals(true, parseIntThrowsFormatException(" +0x100 "));
}
static testMain() {
diff --git a/tests/lib/math/math_test.dart b/tests/lib/math/math_test.dart
index 2bc7741..04a5022 100644
--- a/tests/lib/math/math_test.dart
+++ b/tests/lib/math/math_test.dart
@@ -206,6 +206,10 @@
Expect.equals(9, int.parse("09"));
Expect.equals(9, int.parse(" 09 "));
Expect.equals(-9, int.parse("-09"));
+ Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+ Expect.equals(0x1234567890,int.parse(" +0x1234567890 "));
+ Expect.equals(0x100, int.parse("+0x100"));
+ Expect.equals(0x100, int.parse(" +0x100 "));
Expect.equals(true, parseIntThrowsFormatException("1b"));
Expect.equals(true, parseIntThrowsFormatException(" 1b "));
Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
@@ -233,10 +237,6 @@
Expect.equals(true, parseIntThrowsFormatException("- 5"));
Expect.equals(true, parseIntThrowsFormatException(""));
Expect.equals(true, parseIntThrowsFormatException(" "));
- Expect.equals(true, parseIntThrowsFormatException("+0x1234567890"));
- Expect.equals(true, parseIntThrowsFormatException(" +0x1234567890 "));
- Expect.equals(true, parseIntThrowsFormatException("+0x100"));
- Expect.equals(true, parseIntThrowsFormatException(" +0x100 "));
}
static testMain() {
diff --git a/tests/lib/mirrors/library_metadata_test.dart b/tests/lib/mirrors/library_metadata_test.dart
new file mode 100644
index 0000000..3ae8b11
--- /dev/null
+++ b/tests/lib/mirrors/library_metadata_test.dart
@@ -0,0 +1,45 @@
+// 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.
+
+@string @symbol
+library test.library_metadata_test;
+
+import 'dart:mirrors';
+
+const string = 'a metadata string';
+
+const symbol = const Symbol('symbol');
+
+const hest = 'hest';
+
+checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
+ List metadata = mirror.metadata.map((m) => m.reflectee).toList();
+ if (metadata == null) {
+ throw 'Null metadata on $mirror';
+ }
+ int expectedLength = expectedMetadata.length;
+ int actualLength = metadata.length;
+ if (expectedLength != actualLength) {
+ throw 'Expected length = $expectedLength, but got length = $actualLength.';
+ }
+ for (int i = 0; i < expectedLength; i++) {
+ if (metadata[i] != expectedMetadata[i]) {
+ throw '${metadata[i]} is not "${expectedMetadata[i]}"'
+ ' in $mirror at index $i';
+ }
+ }
+ print(metadata);
+}
+
+main() {
+ if (MirrorSystem.getName(symbol) != 'symbol') {
+ // This happened in dart2js due to how early library metadata is
+ // computed.
+ throw 'Bad constant: $symbol';
+ }
+
+ MirrorSystem mirrors = currentMirrorSystem();
+ checkMetadata(mirrors.findLibrary(const Symbol('test.library_metadata_test')).first,
+ [string, symbol]);
+}
diff --git a/tests/lib/mirrors/metadata_test.dart b/tests/lib/mirrors/metadata_test.dart
index fbd888a..6db3e55 100644
--- a/tests/lib/mirrors/metadata_test.dart
+++ b/tests/lib/mirrors/metadata_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-@string @symbol
library test.metadata_test;
import 'dart:mirrors';
@@ -51,14 +50,13 @@
}
MirrorSystem mirrors = currentMirrorSystem();
- checkMetadata(mirrors.findLibrary(const Symbol('test.metadata_test')).first,
- [string, symbol]);
ClassMirror myClassMirror = reflectClass(MyClass);
checkMetadata(myClassMirror, [symbol, string]);
- ClosureMirror closure = reflect(main);
- checkMetadata(closure.function, [symbol, string, symbol]);
- closure = reflect(new MyClass().myMethod);
- checkMetadata(closure.function, [string, symbol, string]);
+ LibraryMirror lib = mirrors.findLibrary(const Symbol('test.metadata_test')).first;
+ MethodMirror function = lib.functions[const Symbol('main')];
+ checkMetadata(function, [symbol, string, symbol]);
+ MethodMirror method = myClassMirror.methods[const Symbol('myMethod')];
+ checkMetadata(method, [string, symbol, string]);
VariableMirror xMirror = myClassMirror.variables[const Symbol('x')];
checkMetadata(xMirror, [hest, hest, symbol]);
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index b931475..c34b823 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -1218,6 +1218,59 @@
Expect.isFalse(file.existsSync());
}
+ // Test that opens the same file for writing then for appending to test
+ // that the file is not truncated when opened for appending.
+ static void testRename() {
+ var file = new File('${tempDirectory.path}/rename_name');
+ file.create().then((file) {
+ file.rename("${tempDirectory.path}/rename_newname").then((newfile) {
+ file.exists().then((e) {
+ Expect.isFalse(e);
+ newfile.exists().then((e) {
+ Expect.isTrue(e);
+ newfile.delete().then((_) {
+ file.exists().then((e) {
+ Expect.isFalse(e);
+ if (Platform.operatingSystem != "windows") {
+ var brokenLink =
+ new Link('${tempDirectory.path}/rename_name');
+ brokenLink.create(
+ '${tempDirectory.path}/rename_newname').then((_) {
+ file.rename("xxx").then((_) {
+ throw "Rename of broken link succeeded";
+ }).catchError((e) {
+ Expect.isTrue(e is FileException);
+ asyncTestDone("testRename");
+ });
+ });
+
+ } else {
+ asyncTestDone("testRename");
+ }
+ });
+ });
+ });
+ });
+ });
+ });
+ asyncTestStarted();
+ }
+
+ static void testRenameSync() {
+ var file = new File('${tempDirectory.path}/rename_name_sync');
+ file.createSync();
+ var newfile = file.renameSync('${tempDirectory.path}/rename_newname_sync');
+ Expect.isFalse(file.existsSync());
+ Expect.isTrue(newfile.existsSync());
+ newfile.deleteSync();
+ Expect.isFalse(newfile.existsSync());
+ if (Platform.operatingSystem != "windows") {
+ var brokenLink = new Link('${tempDirectory.path}/rename_name_sync');
+ brokenLink.createSync('${tempDirectory.path}/rename_newname_sync');
+ Expect.throws(() => file.renameSync('xxx'));
+ }
+ }
+
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
static String getFilename(String path) =>
@@ -1276,6 +1329,8 @@
testDirectorySync();
testWriteStringUtf8();
testWriteStringUtf8Sync();
+ testRename();
+ testRenameSync();
});
}
}
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index 232cf43..fb5f916 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -46,21 +46,16 @@
});
// Bind to a port already in use.
- // Either an error or a successful bind is allowed.
- // Windows platforms allow multiple binding to the same socket, with
- // unpredictable results.
RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
RawSecureServerSocket.bind(HOST_NAME,
s.port,
CERTIFICATE).then((t) {
- Expect.equals('windows', Platform.operatingSystem);
- Expect.equals(s.port, t.port);
+ Expect.fail("Multiple listens on same port");
s.close();
t.close();
port.toSendPort().send(1);
})
.catchError((error) {
- Expect.notEquals('windows', Platform.operatingSystem);
Expect.isTrue(error is SocketException);
s.close();
port.toSendPort().send(1);
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
index 381c0ed..08ed693 100644
--- a/tests/standalone/io/raw_socket_test.dart
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -48,19 +48,14 @@
});
// Bind to a port already in use.
- // Either an error or a successful bind is allowed.
- // Windows platforms allow multiple binding to the same socket, with
- // unpredictable results.
RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0)
.then((s) {
RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, s.port)
.then((t) {
- Expect.equals('windows', Platform.operatingSystem);
- Expect.equals(s.port, t.port);
+ Expect.fail("Multiple listens on same port");
port.toSendPort().send(1);
})
.catchError((error) {
- Expect.notEquals('windows', Platform.operatingSystem);
Expect.isTrue(error is SocketException);
port.toSendPort().send(1);
});
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index a7c0801..9563fc9 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -46,20 +46,13 @@
});
// Bind to a port already in use.
- // Either an error or a successful bind is allowed.
- // Windows platforms allow multiple binding to the same socket, with
- // unpredictable results.
SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
SecureServerSocket.bind(HOST_NAME,
s.port,
CERTIFICATE).then((t) {
- Expect.equals('windows', Platform.operatingSystem);
- Expect.equals(s.port, t.port);
- s.close();
- t.close();
+ Expect.fail("Multiple listens on same port");
port.toSendPort().send(1);
}).catchError((error) {
- Expect.notEquals('windows', Platform.operatingSystem);
Expect.isTrue(error is SocketException);
s.close();
port.toSendPort().send(1);
diff --git a/tests/standalone/io/socket_test.dart b/tests/standalone/io/socket_test.dart
index 32e7742..4220980 100644
--- a/tests/standalone/io/socket_test.dart
+++ b/tests/standalone/io/socket_test.dart
@@ -48,20 +48,16 @@
});
// Bind to a port already in use.
- // Either an error or a successful bind is allowed.
- // Windows platforms allow multiple binding to the same socket, with
- // unpredictable results.
ServerSocket.bind("127.0.0.1", 0)
.then((s) {
ServerSocket.bind("127.0.0.1", s.port)
.then((t) {
- Expect.equals('windows', Platform.operatingSystem);
- Expect.equals(s.port, t.port);
+ Expect.fail("Multiple listens on same port");
port.toSendPort().send(1);
})
.catchError((error) {
- Expect.notEquals('windows', Platform.operatingSystem);
Expect.isTrue(error is SocketException);
+ s.close();
port.toSendPort().send(1);
});
});
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 3f8543e..9f81106 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -162,144 +162,16 @@
# Skip until we stabilize language tests.
*: Skip
-[ $arch == simarm ]
-io/file_system_links_test: Crash # Issue: 11207
-io/process_exit_negative_test: Timeout, Pass, Crash # Issue: 11207
-io/socket_many_connections_test: Pass, Crash # Issue: 11207
-out_of_memory_test: Pass, Crash # Issue: 11207 (Pass on Mac)
-
-[ $arch == arm ]
-io/process_shell_test: Crash # Issue: 11207
-io/raw_secure_server_socket_argument_test: Crash # Issue: 11207
-io/secure_socket_argument_test: Crash # Issue: 11207
-
[ $arch == arm || $arch == simarm ]
-constant_left_shift_test: Fail # Issue: 11207
coverage_test: Crash # Issue: 11207
debugger/basic_debugger_test: Crash # Issue: 11207
debugger/closure_debugger_test: Crash # Issue: 11207
-deoptimization_test: Crash # Issue: 11207
-float_array_test: Crash # Issue: 11207
http_launch_test: Crash # Issue: 11207
-io/dart_std_io_pipe_test: Fail, Crash # Issue: 11207
-io/delete_symlink_test: Crash # Issue: 11207
-io/directory_test: Crash, Timeout # Issue: 11207
-io/echo_server_stream_test: Crash # Issue: 11207
-io/file_error_test: Pass, Crash # Issue: 11207
-io/file_fuzz_test: Crash # Issue: 11207
-io/file_input_stream_test: Pass, Crash # Issue: 11207
-io/file_non_ascii_test: Pass, Crash # Issue: 11207
-io/file_output_stream_test: Pass, Crash # Issue 11207
-io/file_read_special_device_test: Crash, Fail, Timeout # Issue: 11207
-io/file_stat_test: Crash # Issue: 11207
-io/file_system_async_links_test: Crash # Issue: 11207
-io/file_system_delete_test: Pass, Crash # Issue: 11207
-io/file_system_links_test: Timeout, Pass, Crash # Issue: 11207
-io/file_test: Timeout, Crash # Issue: 11207
-io/file_write_as_test: Crash # Issue: 11207
-io/http_10_test: Crash # Issue: 11207
-io/http_advanced_test: Crash # Issue: 11207
-io/http_auth_digest_test: Crash # Issue: 11207
-io/http_auth_test: Crash # Issue: 11207
-io/http_basic_test: Crash # Issue: 11207
-io/http_body_test: Crash # Issue: 11207
-io/http_client_connect_test: Crash # Issue: 11207
-io/http_client_exception_test: Pass, Crash # Issue: 11207
-io/http_client_request_test: Crash # Issue: 11207
-io/http_client_timeout_test: Crash # Issue: 11207
-io/http_close_test: Crash # Issue: 11207
-io/http_compression_test: Crash # Issue: 11207
-io/http_connection_close_test: Crash # Issue: 11207
-io/http_connection_header_test: Crash # Issue: 11207
-io/http_connection_info_test: Crash # Issue: 11207
-io/http_content_length_test: Crash # Issue: 11207
-io/http_cookie_test: Crash # Issue: 11207
-io/http_detach_socket_test: Crash # Issue: 11207
-io/http_headers_state_test: Crash # Issue: 11207
-io/http_head_test: Crash # Issue: 11207
-io/http_keep_alive_test: Crash # Issue: 11207
-io/http_multipart_test: Crash # Issue: 11207
-io/http_parser_test: Pass, Crash # Issue 11207
-io/http_proxy_test: Crash # Issue: 11207
-io/http_read_test: Crash # Issue: 11207
-io/http_redirect_test: Crash # Issue: 11207
-io/http_request_pipeling_test: Crash # Issue: 11207
-io/https_client_certificate_test: Crash # Issue: 11207
-io/http_server_early_client_close2_test: Crash # Issue: 11207
-io/http_server_early_client_close_test: Crash # Issue: 11207
-io/http_server_early_server_close_test: Crash # Issue: 11207
-io/http_server_response_test: Crash # Issue: 11207
-io/http_server_test: Crash # Issue: 11207
-io/http_session_test: Crash # Issue: 11207
-io/http_shutdown_test: Crash # Issue: 11207
-io/https_server_test: Crash # Issue: 11207
-io/http_stream_close_test: Crash # Issue: 11207
-io/link_async_test: Pass, Crash # Issue: 11207
-io/link_test: Pass, Crash # Issue: 11207
-io/mime_multipart_parser_test: Pass, Crash # Issue 11207
-io/pipe_server_test: Crash # Issue: 11207
-io/process_broken_pipe_test: Pass, Crash # Issue: 11207
-io/process_check_arguments_test: Pass, Crash # Issue: 11207
-io/process_environment_test: Crash # Issue: 11207
-io/process_exit_test: Crash # Issue: 11207
-io/process_invalid_arguments_test: Crash # Issue: 11207
-io/process_kill_test: Pass, Crash # Issue: 11207
-io/process_non_ascii_test: Pass, Crash # Issue: 11207
-io/process_path_environment_test: Crash # Issue: 11207
-io/process_path_test: Pass, Crash # Issue: 11207
-io/process_pid_test: Pass, Crash # Issue: 11207
-io/process_run_output_test: Pass, Crash # Issue: 11207
-io/process_segfault_test: Crash # Issue: 11207
-io/process_set_exit_code_test: Crash # Issue: 11207
-io/process_shell_test: Pass, Crash # Issue: 11207
-io/process_stderr_test: Pass, Crash # Issue: 11207
-io/process_stdin_transform_unsubscribe_test: Crash # Issue: 11207
-io/process_stdout_test: Pass, Crash # Issue: 11207
-io/process_working_directory_test: Crash # Issue: 11207
-io/raw_secure_server_closing_test: Crash # Issue: 11207
-io/raw_secure_server_socket_test: Crash # Issue: 11207
-io/raw_secure_socket_pause_test: Crash # Issue: 11207
-io/raw_secure_socket_test: Crash # Issue: 11207
-io/raw_socket_test: Crash # Issue: 11207
-io/raw_socket_typed_data_test: Pass, Crash # Issue: 11207
-io/raw_socket_write_destroy_test: Pass, Crash # Issue: 11207
-io/regress_10026_test: Crash # Issue: 11207
-io/regress_7191_test: Crash # Issue: 11207
-io/regress_8828_test: Crash # Issue: 11207
-io/regress_9194_test: Crash # Issue: 11207
-io/secure_builtin_roots_database_test: Crash # Issue: 11207
-io/secure_builtin_roots_test: Crash # Issue: 11207
-io/secure_client_raw_server_test: Crash, Timeout # Issue: 11207
-io/secure_client_server_test: Timeout, Crash # Issue: 11207
-io/secure_multiple_client_server_test: Crash # Issue: 11207
-io/secure_no_builtin_roots_database_test: Crash # Issue: 11207
-io/secure_no_builtin_roots_test: Crash # Issue: 11207
-io/secure_server_client_certificate_test: Crash # Issue: 11207
-io/secure_server_closing_test: Crash # Issue: 11207
-io/secure_server_socket_test: Crash # Issue: 11207
-io/secure_session_resume_test: Crash # Issue: 11207
-io/secure_socket_bad_certificate_test: Pass, Crash # Issue: 11207
-io/secure_socket_test: Crash # Issue: 11207
-io/socket_close_test: Crash # Issue: 11207
-io/socket_exception_test: Crash, Timeout # Issue: 11207
-io/socket_info_test: Pass, Crash # Issue: 11207
-io/socket_invalid_arguments_test: Crash # Issue: 11207
-io/socket_ipv6_test: Pass, Crash # Issue: 11207
-io/socket_port_test: Pass, Crash # Issue: 11207
-io/socket_test: Crash # Issue: 11207
-io/socket_upgrade_to_secure_test: Crash # Issue: 11207
-io/status_file_parser_test: Crash # Issue: 11207
-io/stdout_stderr_test: Pass, Crash # Issue: 11207
-io/stream_pipe_test: Pass, Crash # Issue: 11207
-io/test_extension_fail_test: Crash # Issue: 11207
-io/test_extension_test: Crash # Issue: 11207
-io/web_socket_protocol_processor_test: Crash # Issue: 11207
-io/web_socket_test: Crash # Issue: 11207
-io/web_socket_typed_data_test: Pass, Crash # Issue: 11207
left_shift_bit_and_op_test: Fail # Issue: 11207
package/package_isolate_test: Pass, Crash # Issue: 11207
-typed_data_test: Crash # Issue: 11207
-io/regress_7679_test: Pass, Crash
+out_of_memory_test: Pass, Crash # Issue: 11207 (Pass on Mac)
+typed_data_test: Timeout, Crash # Issue: 11207
+io/*: Skip # Skip IO tests for now as they are still quite flaky.
[ $arch == mips ]
*: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 1954d2f..28542e6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 5
-BUILD 18
+BUILD 19
PATCH 0