blob: a4b29fec362151880d59cb4f92df2659c3709cbe [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
define(['dart_sdk'], function(dart_sdk) {
const assert = chai.assert;
const async = dart_sdk.async;
const core = dart_sdk.core;
const collection = dart_sdk.collection;
const dart = dart_sdk.dart;
const dartx = dart.dartx;
dart.trapRuntimeErrors(false);
suite('ignore', () => {
"use strict";
let FutureOr = async.FutureOr$;
let Future = async.Future$;
let List = core.List$;
setup(() => {
dart_sdk.dart.ignoreWhitelistedErrors(false);
});
teardown(() => {
dart_sdk.dart.ignoreWhitelistedErrors(false);
});
test('FutureOr', () => {
let f = Future(dart.dynamic).value(42);
let l = [1, 2, 3];
assert.throws(() => { dart.as(f, FutureOr(core.int)); });
assert.throws(() => { dart.as(l, FutureOr(List(core.int)))});
dart_sdk.dart.ignoreWhitelistedErrors(true);
assert.equal(f, dart.as(f, FutureOr(core.int)));
assert.equal(l, dart.as(l, FutureOr(List(core.int))));
});
});
suite('generic', () => {
"use strict";
let generic = dart.generic;
test('zero arguments is not allowed', () => {
assert.throws(() => { generic(function(){}); });
});
test('dcall noSuchMethod has correct error target', () => {
assert.throws(() => dart.dcall(42),
new RegExp('NoSuchMethodError.*\nReceiver: 42', 'm'),
'Calls with non-function receiver should throw a NoSuchMethodError' +
' with correct target');
// TODO(jmesserly): we should show the name "print" in there somewhere.
assert.throws(() => dart.dcall(core.print, 1, 2, 3),
new RegExp('NoSuchMethodError.*\n' +
"Receiver: Instance of '\\(Object\\) -> void'", 'm'),
'Calls with incorrect argument types should throw a NoSuchMethodError' +
' with correct target');
});
test('can throw number', () => {
try {
dart.throw(42);
} catch (e) {
assert.equal(e, 42);
}
});
test('argument count cannot change', () => {
let SomeType = generic(function(x) { return {x: x}; });
assert.throws(() => { SomeType(1,2) });
let obj = {};
assert.equal(SomeType(obj).x, obj);
assert.equal(SomeType(obj).x, obj);
assert.equal(SomeType().x, dart.dynamic);
});
test('undefined/null are not allowed', () => {
let SomeType = generic(function(x) {});
assert.throws(() => { SomeType(void 0) });
SomeType(1);
assert.throws(() => { SomeType(void 0) });
SomeType(1);
assert.throws(() => { SomeType(null) });
});
test('result is memoized', () => {
let t1 = Object.create(null);
let t2 = Object.create(null);
let count = 0;
let SomeType = generic(function(x, y) {
count++;
return Object.create(null);
});
let x12 = SomeType(1, 2);
assert.strictEqual(SomeType(1, 2), x12);
assert.strictEqual(SomeType(1, 2), x12);
assert.strictEqual(count, 1);
let x11 = SomeType(1, 1);
assert.strictEqual(count, 2);
assert.strictEqual(SomeType(1, 1), x11);
assert.strictEqual(count, 2);
count = 0;
let t1t2 = SomeType(t1, t2);
assert.strictEqual(count, 1);
let t2t1 = SomeType(t2, t1);
assert.strictEqual(count, 2);
assert.notStrictEqual(t1t2, t2t1);
assert.strictEqual(SomeType(t1, t2), t1t2);
assert.strictEqual(SomeType(t2, t1), t2t1);
assert.strictEqual(SomeType(t1, t2), t1t2);
count = 0;
// Nothing has been stored on the object
assert.strictEqual(Object.keys(t1).length, 0);
assert.strictEqual(Object.keys(t2).length, 0);
});
test('type constructor is reflectable', () => {
let SomeType = generic(function(x, y) { return Object.create(null); });
let someValue = SomeType('hi', 123);
assert.equal(dart.getGenericClass(someValue), SomeType);
assert.deepEqual(dart.getGenericArgs(someValue), ['hi', 123]);
});
test('proper type constructor is called', () => {
// This tests https://github.com/dart-lang/dev_compiler/issues/178
let l = dart_sdk._interceptors.JSArray$(core.int).of([1, 2, 3]);
let s = l[dartx.join]();
assert.equal(s, '123');
});
});
suite('instanceOf', () => {
"use strict";
let expect = assert.equal;
let generic = dart.generic;
let intIsNonNullable = false;
let cast = dart.as;
let instanceOf = dart.is;
let strongInstanceOf = dart.strongInstanceOf;
let getReifiedType = dart.getReifiedType;
let fnTypeFuzzy = dart.fnTypeFuzzy;
let typedef = dart.typedef;
let isSubtype = dart.isSubtype;
let Object = core.Object;
let String = core.String;
let dynamic = dart.dynamic;
let List = core.List;
let Map = core.Map;
let Map$ = core.Map$;
let double = core.double;
let int = core.int;
let num = core.num;
let bool = core.bool;
class A {}
class B extends A {}
class C extends B {}
let AA$ = generic((T, U) => {
class AA extends core.Object {}
(AA.new = function() {}).prototype = AA.prototype;
return AA;
});
let AA = AA$();
let BB$ = generic((T, U) => {
class BB extends AA$(U, T) {}
(BB.new = function() {}).prototype = BB.prototype;
return BB;
});
let BB = BB$();
class CC extends BB$(String, List) {}
(CC.new = function() {}).prototype = CC.prototype;
let Func2 = typedef('Func2', () => fnTypeFuzzy(dynamic, [dynamic, dynamic]));
let Foo = typedef('Foo', () => fnTypeFuzzy(B, [B, String]));
let FuncG$ = generic((T, U) => typedef('FuncG', () => fnTypeFuzzy(T, [T, U])))
let FuncG = FuncG$();
// TODO(vsm): Revisit when we encode types on functions properly.
// A bar1(C c, String s) => null;
function bar1(c, s) { return null; }
dart.fn(bar1, dart.fnType(A, [C, String]));
// bar2(B b, String s) => null;
function bar2(b, s) { return null; }
dart.fn(bar2, dart.fnType(dynamic, [B, String]));
// B bar3(B b, Object o) => null;
function bar3(b, o) { return null; }
dart.fn(bar3, dart.fnType(B, [B, Object]));
// B bar4(B b, o) => null;
function bar4(b, o) { return null; }
dart.fn(bar4, dart.fnType(B, [B, dynamic]));
// C bar5(A a, Object o) => null;
function bar5(a, o) { return null; }
dart.fn(bar5, dart.fnType(C, [A, Object]));
// B bar6(B b, String s, String o) => null;
function bar6(b, s, o) { return null; }
dart.fn(bar6, dart.fnType(B, [B, String, String]));
// B bar7(B b, String s, [Object o]) => null;
function bar7(b, s, o) { return null; }
dart.fn(bar7, dart.fnType(B, [B, String], [Object]));
// B bar8(B b, String s, {Object p}) => null;
function bar8(b, s, o) { return null; }
dart.fn(bar8, dart.fnType(B, [B, String], {p: Object}));
let cls1 = dart.fn((c, s) => { return null; },
dart.fnType(A, [C, String]));
let cls2 = dart.fn((b, s) => { return null; },
dart.fnType(dynamic, [B, String]));
let cls3 = dart.fn((b, o) => { return null; },
dart.fnType(B, [B, Object]));
let cls4 = dart.fn((b, o) => { return null; },
dart.fnType(B, [B, dynamic]));
let cls5 = dart.fn((a, o) => { return null; },
dart.fnType(C, [A, Object]));
let cls6 = dart.fn((b, s, o) => { return null; },
dart.fnType(B, [B, String, String]));
let cls7 = dart.fn((b, s, o) => { return null; },
dart.fnType(B, [B, String], [Object]));
let cls8 =
dart.fn((b, s, o) => { return null; },
dart.fnType(B, [B, String], {p: Object}));
function checkType(x, type, expectedTrue) {
if (expectedTrue === undefined) expectedTrue = true;
expect(instanceOf(x, type), expectedTrue,
'"' + x + '" ' +
(expectedTrue ? 'should' : 'should not') +
' be an instance of "' + dart.typeName(type) + '"');
}
test('int', () => {
checkType(5, int);
checkType(5, dynamic);
checkType(5, Object);
checkType(5, num);
checkType(5, bool, false);
checkType(5, String, false);
expect(cast(5, int), 5);
if (intIsNonNullable) {
expect(() => cast(null, int), throws);
} else {
expect(cast(null, int), null);
}
});
test('dynamic', () => {
checkType(new Object.new(), dynamic);
checkType(null, dynamic);
expect(cast(null, dynamic), null);
});
test('Object', () => {
checkType(new Object.new(), dynamic);
checkType(null, Object);
expect(cast(null, Object), null);
});
test('null', () => {
// Object, dynamic cases are already handled above.
checkType(null, core.Null);
checkType(null, core.String, false);
checkType(null, core.int, false);
checkType(null, Map, false);
checkType(void 0, core.Null);
checkType(void 0, core.Object);
checkType(void 0, dart.dynamic);
});
test('String', () => {
checkType("foo", String);
checkType("foo", Object);
checkType("foo", dynamic);
expect(cast(null, String), null);
});
test('FutureOr', () => {
let FutureOr = async.FutureOr$;
assert.equal(dart.as(3, FutureOr(int)), 3);
assert.equal(dart.as(3, FutureOr(double)), 3);
assert.throws(() => dart.as(3.5, FutureOr(int)));
assert.equal(dart.as(3.5, FutureOr(double)), 3.5);
assert.isTrue(dart.is(3, FutureOr(int)));
assert.isTrue(dart.is(3, FutureOr(double)));
assert.isFalse(dart.is(3.5, FutureOr(int)));
assert.isTrue(dart.is(3.5, FutureOr(double)));
assert.equal(dart.as(3, FutureOr(FutureOr(double))), 3);
assert.isTrue(dart.is(3, FutureOr(FutureOr(double))));
});
test('Map', () => {
let m1 = Map$(String, String).new();
let m2 = Map$(Object, Object).new();
let m3 = Map.new();
let m4 = collection.HashMap$(dart.dynamic, dart.dynamic).new();
let m5 = collection.LinkedHashMap.new();
let m6 = Map$(String, dart.dynamic).new();
// Map<T1,T2> <: Map
checkType(m1, Map);
checkType(m1, Object);
// Instance of self
checkType(m1, getReifiedType(m1));
checkType(m1, Map$(String, String));
// Covariance on generics
checkType(m1, getReifiedType(m2));
checkType(m1, Map$(Object, Object));
// No contravariance on generics.
checkType(m2, getReifiedType(m1), false);
checkType(m2, Map$(String, String), false);
// null is! Map
checkType(null, Map, false);
// Raw generic types
checkType(m5, Map);
checkType(m4, Map);
// Is checks
assert.isFalse(dart.is(m3, Map$(String, String)));
assert.isFalse(dart.is(m6, Map$(String, String)));
assert.isTrue(dart.is(m1, Map$(String, String)));
assert.isFalse(dart.is(m2, Map$(String, String)));
// As checks
// TODO(vsm): Enable these. We're currently only logging warnings on
// StrongModeErrors.
// assert.throws(() => dart.as(m3, Map$(String, String)),
// dart.StrongModeError);
// assert.throws(() => dart.as(m6, Map$(String, String)),
// dart.StrongModeError);
assert.equal(dart.as(m1, Map$(String, String)), m1);
// assert.throws(() => dart.as(m2, Map$(String, String)),
// dart.StrongModeError);
});
test('constructors', () => {
class C extends core.Object {
}
(C.new = function(x) {}).prototype = C.prototype;
(C.named = function(x, y) {}).prototype = C.prototype;
dart.setSignature(C, {
constructors: () => ({
new: dart.fnType(C, [core.int]),
named: dart.fnType(C, [core.int, core.int])
})
});
let getType = dart.classGetConstructorType;
isSubtype(getType(C), dart.fnTypeFuzzy(C, [core.int]));
isSubtype(getType(C), dart.fnTypeFuzzy(C, [core.String]), false);
isSubtype(getType(C, 'new'), dart.fnTypeFuzzy(C, [core.int]));
isSubtype(getType(C, 'new'), dart.fnTypeFuzzy(C, [core.String]), false);
isSubtype(getType(C, 'named'), dart.fnTypeFuzzy(C, [core.int, core.int]));
isSubtype(getType(C, 'named'),
dart.fnTypeFuzzy(C, [core.int, core.String]), false);
});
test('generic and inheritance', () => {
let aaraw = new AA.new();
let aarawtype = getReifiedType(aaraw);
let aadynamic = new (AA$(dynamic, dynamic).new)();
let aadynamictype = getReifiedType(aadynamic);
let aa = new (AA$(String, List).new)();
let aatype = getReifiedType(aa);
let bb = new (BB$(String, List).new)();
let bbtype = getReifiedType(bb);
let cc = new CC.new();
let cctype = getReifiedType(cc);
// We don't allow constructing bad types.
// This was AA<String> in Dart (wrong number of type args).
let aabad = new (AA$(dart.dynamic, dart.dynamic).new)();
let aabadtype = getReifiedType(aabad);
checkType(cc, aatype, false);
checkType(cc, AA$(String, List), false);
checkType(cc, bbtype);
checkType(cc, BB$(String, List));
checkType(aa, cctype, false);
checkType(aa, CC, false);
checkType(aa, bbtype, false);
checkType(aa, BB$(String, List), false);
checkType(bb, cctype, false);
checkType(bb, CC, false);
checkType(aa, aabadtype);
checkType(aa, dynamic);
checkType(aabad, aatype, false);
checkType(aabad, AA$(String, List), false);
checkType(aabad, aarawtype);
checkType(aabad, AA);
checkType(aaraw, aabadtype);
checkType(aaraw, AA$(dart.dynamic, dart.dynamic));
checkType(aaraw, aadynamictype);
checkType(aaraw, AA$(dynamic, dynamic));
checkType(aadynamic, aarawtype);
checkType(aadynamic, AA);
});
test('void', () => {
//checkType((x) => x, type((void _(x)) {}));
});
test('mixins', () => {
let c = collection;
var s1 = new (c.SplayTreeSet$(String).new)();
checkType(s1, c.IterableMixin);
checkType(s1, c.IterableMixin$(String));
checkType(s1, c.IterableMixin$(int), false);
checkType(s1, c.SetMixin);
checkType(s1, c.SetMixin$(String));
checkType(s1, c.SetMixin$(int), false);
});
test('Type', () => {
checkType(int, core.Type, true);
checkType(num, core.Type, true);
checkType(bool, core.Type, true);
checkType(String, core.Type, true);
checkType(dynamic, core.Type, true);
checkType(Object, core.Type, true);
checkType(List, core.Type, true);
checkType(Map, core.Type, true);
checkType(Map$(int, String), core.Type, true);
checkType(Func2, core.Type, true);
checkType(fnTypeFuzzy(dynamic, [dynamic]), core.Type, true);
checkType(core.Type, core.Type, true);
checkType(3, core.Type, false);
checkType("hello", core.Type, false);
})
test('Functions', () => {
// - return type: Dart is bivariant. We're covariant.
// - param types: Dart is bivariant. We're contravariant.
checkType(bar1, Foo, false);
checkType(cls1, Foo, false);
checkType(bar1, fnTypeFuzzy(B, [B, String]), false);
checkType(cls1, fnTypeFuzzy(B, [B, String]), false);
checkType(bar2, Foo, false);
checkType(cls2, Foo, false);
checkType(bar2, fnTypeFuzzy(B, [B, String]), false);
checkType(cls2, fnTypeFuzzy(B, [B, String]), false);
checkType(bar3, Foo);
checkType(cls3, Foo);
checkType(bar3, fnTypeFuzzy(B, [B, String]));
checkType(cls3, fnTypeFuzzy(B, [B, String]));
checkType(bar4, Foo, true);
checkType(cls4, Foo, true);
checkType(bar4, fnTypeFuzzy(B, [B, String]), true);
checkType(cls4, fnTypeFuzzy(B, [B, String]), true);
checkType(bar5, Foo);
checkType(cls5, Foo);
checkType(bar5, fnTypeFuzzy(B, [B, String]));
checkType(cls5, fnTypeFuzzy(B, [B, String]));
checkType(bar6, Foo, false);
checkType(cls6, Foo, false);
checkType(bar6, fnTypeFuzzy(B, [B, String]), false);
checkType(cls6, fnTypeFuzzy(B, [B, String]), false);
checkType(bar7, Foo);
checkType(cls7, Foo);
checkType(bar7, fnTypeFuzzy(B, [B, String]));
checkType(cls7, fnTypeFuzzy(B, [B, String]));
checkType(bar7, getReifiedType(bar6));
checkType(cls7, getReifiedType(bar6));
checkType(bar8, Foo);
checkType(cls8, Foo);
checkType(bar8, fnTypeFuzzy(B, [B, String]));
checkType(cls8, fnTypeFuzzy(B, [B, String]));
checkType(bar8, getReifiedType(bar6), false);
checkType(cls8, getReifiedType(bar6), false);
checkType(bar7, getReifiedType(bar8), false);
checkType(cls7, getReifiedType(bar8), false);
checkType(bar8, getReifiedType(bar7), false);
checkType(cls8, getReifiedType(bar7), false);
// Parameterized typedefs
checkType(bar1, FuncG$(B, String), false);
checkType(cls1, FuncG$(B, String), false);
checkType(bar3, FuncG$(B, String));
checkType(cls3, FuncG$(B, String));
});
test('dcall', () => {
function dd2d(x, y) {return x};
dart.fn(dd2d);
function ii2i(x, y) {return x};
dart.fn(ii2i, dart.fnType(core.int, [core.int, core.int]));
function ii_2i(x, y) {return x};
dart.fn(ii_2i, dart.fnType(core.int, [core.int], [core.int]));
function i_i2i(x, opts) {return x};
dart.fn(i_i2i,
dart.fnType(core.int, [core.int], {extra: core.int}));
assert.equal(dart.dcall(dd2d, 0, 1), 0);
assert.equal(dart.dcall(dd2d, "hello", "world"), "hello");
assert.throws(() => dart.dcall(dd2d, 0));
assert.throws(() => dart.dcall(dd2d, 0, 1, 2));
assert.throws(() => dart.dcall(dd2d, 0, 1, {extra : 3}));
// This should throw but currently doesn't.
// assert.throws(() => dart.dcall(dd2d, 0, {extra:3}));
assert.equal(dart.dcall(ii2i, 0, 1), 0);
assert.throws(() => dart.dcall(ii2i, "hello", "world"));
assert.throws(() => dart.dcall(ii2i, 0));
assert.throws(() => dart.dcall(ii2i, 0, 1, 2));
assert.equal(dart.dcall(ii_2i, 0, 1), 0);
assert.throws(() => dart.dcall(ii_2i, "hello", "world"));
assert.equal(dart.dcall(ii_2i, 0), 0);
assert.throws(() => dart.dcall(ii_2i, 0, 1, 2));
assert.throws(() => dart.dcall(i_i2i, 0, 1));
assert.throws(() => dart.dcall(i_i2i, "hello", "world"));
assert.equal(dart.dcall(i_i2i, 0), 0);
assert.throws(() => dart.dcall(i_i2i, 0, 1, 2));
assert.equal(dart.dcall(i_i2i, 0, {extra: 3}), 0);
});
test('dsend', () => {
class Tester extends core.Object {
m(x, y) {return x;}
call(x) {return x;}
static s(x, y) { return x;}
}
(Tester.new = function() {
this.f = dart.fn(x => x,
dart.fnType(core.int, [core.int]));
this.me = this;
}).prototype = Tester.prototype;
dart.setSignature(Tester, {
methods: () => ({
m: dart.fnType(core.int, [core.int, core.int]),
call: dart.fnType(core.int, [core.int])
}),
statics: () => ({
s: dart.fnType(core.String, [core.String])
}),
names: ['s']
})
let o = new Tester.new();
// Method send
assert.equal(dart.dsend(o, 'm', 3, 4), 3);
assert.equal(dart.dsend(o, 'm', null, 4), null);
assert.throws(() => dart.dsend(o, 'm', 3));
assert.throws(() => dart.dsend(o, 'm', "hello", "world"));
assert.throws(() => dart.dsend(o, 'q', 3));
// Method send through a field
assert.equal(dart.dsend(o, 'f', 3), 3);
assert.equal(dart.dsend(o, 'f', null), null);
assert.throws(() => dart.dsend(o, 'f', "hello"));
assert.throws(() => dart.dsend(o, 'f', 3, 4));
// Static method call
assert.equal(dart.dcall(Tester.s, "hello"), "hello");
assert.equal(dart.dcall(Tester.s, null), null);
assert.throws(() => dart.dcall(Tester.s, "hello", "world"));
assert.throws(() => dart.dcall(Tester.s, 0, 1));
// Calling an object with a call method
assert.equal(dart.dcall(o, 3), 3);
assert.equal(dart.dcall(o, null), null);
assert.throws(() => dart.dcall(o, "hello"));
assert.throws(() => dart.dcall(o, 3, 4));
// Calling through a field containing an object with a call method
assert.equal(dart.dsend(o, 'me', 3), 3);
assert.equal(dart.dsend(o, 'me', null), null);
assert.throws(() => dart.dsend(o, 'me', "hello"));
assert.throws(() => dart.dsend(o, 'me', 3, 4));
});
test('Types on top level functions', () => {
// Test some generated code
// Test the lazy path
checkType(core.identityHashCode,
dart.fnTypeFuzzy(core.int, [core.Object]));
// Test the normal path
checkType(core.identical,
dart.fnTypeFuzzy(core.bool,
[core.Object, core.Object]));
// Hand crafted tests
// All dynamic
function dd2d(x, y) {return x};
dart.fn(dd2d);
checkType(dd2d, dart.fnTypeFuzzy(dart.dynamic,
[dart.dynamic, dart.dynamic]));
// Set the type eagerly
function ii2i(x, y) {return x};
dart.fn(ii2i, dart.fnType(core.int, [core.int, core.int]));
checkType(ii2i, dart.fnTypeFuzzy(core.int,
[core.int, core.int]));
// Set the type lazily
function ss2s(x, y) {return x};
var coreString;
dart.lazyFn(ss2s,
() => dart.fnType(coreString,
[coreString, coreString]));
coreString = core.String;
checkType(ss2s, dart.fnTypeFuzzy(core.String,
[core.String, core.String]));
// Optional types
function ii_2i(x, y) {return x};
dart.fn(ii_2i, dart.fnType(core.int, [core.int], [core.int]));
checkType(ii_2i, dart.fnTypeFuzzy(core.int, [core.int],
[core.int]));
checkType(ii_2i, dart.fnTypeFuzzy(core.int, [core.int,
core.int]));
checkType(ii_2i, dart.fnTypeFuzzy(core.int, [], [core.int,
core.int]),
false);
checkType(ii_2i, dart.fnTypeFuzzy(core.int, [core.int],
{extra: core.int}), false);
// Named types
function i_i2i(x, opts) {return x};
dart.fn(i_i2i, dart.fnType(core.int, [core.int],
{extra: core.int}));
checkType(i_i2i, dart.fnTypeFuzzy(core.int, [core.int],
{extra: core.int}));
checkType(i_i2i, dart.fnTypeFuzzy(core.int,
[core.int, core.int]), false);
checkType(i_i2i, dart.fnTypeFuzzy(core.int, [core.int], {}));
checkType(i_i2i,
dart.fnTypeFuzzy(core.int, [], {extra: core.int,
also: core.int}), false);
checkType(i_i2i,
dart.fnTypeFuzzy(core.int, [core.int], [core.int]), false);
});
test('Method tearoffs', () => {
let c = collection;
// Tear off of an inherited method
let map = Map$(core.int, core.String).new();
checkType(dart.bind(map, 'toString'),
dart.fnTypeFuzzy(String, []));
checkType(dart.bind(map, 'toString'),
dart.fnTypeFuzzy(int, []), false, true);
// Tear off of a method directly on the object
let smap = new (c.SplayTreeMap$(core.int, core.String).new)();
checkType(dart.bind(smap, 'forEach'),
dart.fnTypeFuzzy(dart.void,
[dart.fnTypeFuzzy(dart.void, [core.int, core.String])]));
checkType(dart.bind(smap, 'forEach'),
dart.fnTypeFuzzy(dart.void,
[dart.fnTypeFuzzy(dart.void,
[core.String, core.String])]), false, true);
// Tear off of a mixed in method
let mapB = new (c.MapBase$(core.int, core.int).new)();
checkType(dart.bind(mapB, 'forEach'),
dart.fnTypeFuzzy(dart.void, [
dart.fnTypeFuzzy(dart.void, [core.int, core.int])]));
checkType(dart.bind(mapB, 'forEach'),
dart.fnTypeFuzzy(dart.void, [
dart.fnTypeFuzzy(dart.void, [core.int, core.String])]),
false, true);
// Tear off of a method with a symbol name
let listB = new (c.ListBase$(core.int).new)();
// List.add is reified as taking Object
checkType(dart.bind(listB, dartx.add),
dart.fnTypeFuzzy(dart.void, [core.int]));
checkType(dart.bind(listB, dartx.add),
dart.fnTypeFuzzy(dart.void, [core.String]), true);
checkType(dart.bind(listB, dartx.removeAt),
dart.fnTypeFuzzy(dart.void, [core.String]), false);
// Tear off of a static method
checkType(c.ListBase.listToString,
dart.fnTypeFuzzy(core.String, [core.List]));
checkType(c.ListBase.listToString,
dart.fnTypeFuzzy(core.String, [core.String]), false);
// Tear-off of extension methods on primitives
checkType(dart.bind(3.0, dartx.floor),
dart.fnTypeFuzzy(core.int, []));
checkType(dart.bind(3.0, dartx.floor),
dart.fnTypeFuzzy(core.String, []), false);
checkType(dart.bind("", dartx.endsWith),
dart.fnTypeFuzzy(core.bool, [core.String]));
checkType(dart.bind("", dartx.endsWith),
dart.fnTypeFuzzy(core.bool, [core.int]), false);
// Tear off a mixin method
class Base {
m(x) {return x;}
};
dart.setSignature(Base, {
methods: () => ({
m: dart.fnType(core.int, [core.int]),
})
});
class M1 {
m(x) {return x;}
};
dart.setSignature(M1, {
methods: () => ({
m: dart.fnType(core.num, [core.int]),
})
});
class M2 {
m(x) {return x;}
};
dart.setSignature(M2, {
methods: () => ({
m: dart.fnType(core.Object, [core.int]),
})
});
class O extends dart.mixin(Base, M1, M2) {}
(O.new = function() {}).prototype = O.prototype;
dart.setSignature(O, {});
var obj = new O.new();
var m = dart.bind(obj, 'm');
checkType(m, dart.fnTypeFuzzy(core.Object, [core.int]));
checkType(m, dart.fnTypeFuzzy(core.int, [core.int]), false);
// Test inherited signatures
class P extends O {
m(x) {return x;};
};
(P.new = function() {}).prototype = P.prototype;
dart.setSignature(P, {});
var obj = new P.new();
var m = dart.bind(obj, 'm');
checkType(m, dart.fnTypeFuzzy(core.Object, [core.int]));
checkType(m, dart.fnTypeFuzzy(core.int, [core.int]), false);
});
test('Object members', () => {
let nullHash = dart.hashCode(null);
assert.equal(nullHash, 0);
let nullString = dart.toString(null);
assert.equal(nullString, 'null');
let map = Map.new();
let mapHash = dart.hashCode(map);
checkType(mapHash, core.int);
assert.equal(mapHash, map.hashCode);
let mapString = dart.toString(map);
assert.equal(mapString, map.toString());
checkType(mapString, core.String);
let str = "A string";
let strHash = dart.hashCode(str);
checkType(strHash, core.int);
let strString = dart.toString(str);
checkType(strString, core.String);
assert.equal(str, strString);
let n = 42;
let intHash = dart.hashCode(n);
checkType(intHash, core.int);
let intString = dart.toString(n);
assert.equal(intString, '42');
});
});
suite('subtyping', function() {
'use strict';
let fnTypeFuzzy = dart.fnTypeFuzzy;
let fnType = dart.fnType;
let typedef = dart.typedef;
let isSubtype = dart.isSubtype;
let int = core.int;
let num = core.num;
let dyn = dart.dynamic;
function always(t1, t2) {
assert.equal(isSubtype(t1, t2), true,
dart.toString(t1) +
" should always be a subtype of " +
dart.toString(t2));
}
function never(t1, t2) {
assert.equal(isSubtype(t1, t2), false,
dart.toString(t1) +
" should never be a subtype of " +
dart.toString(t2));
}
function maybe(t1, t2) {
assert.equal(isSubtype(t1, t2), null,
dart.toString(t1) +
" should maybe be a subtype of " +
dart.toString(t2));
}
function always2(t1, t2) {
always(t1, t2);
always(fnTypeFuzzy(t1, [t2]), fnTypeFuzzy(t2, [t1]));
}
function never2(t1, t2) {
never(t1, t2);
maybe(fnTypeFuzzy(t1, [t2]), fnTypeFuzzy(t2, [t1]));
}
function maybe2(t1, t2) {
maybe(t1, t2);
maybe(fnTypeFuzzy(t1, [t2]), fnTypeFuzzy(t2, [t1]));
}
function run_test(func1, func2, func2opt, func1extra, func2extra) {
always2(func2(int, int), func2(int, int));
always2(func2(int, num), func2(int, int));
always2(func2(int, int), func2(num, int));
always2(func2opt(int, int), func2opt(int, int));
always2(func2opt(int, num), func2opt(int, int));
always2(func2opt(int, int), func2opt(num, int));
always2(func2opt(int, int), func2(int, int));
always2(func2opt(int, num), func2(int, int));
always2(func2opt(int, int), func2(num, int));
always2(func2opt(int, int), func1(int));
always2(func2opt(int, num), func1(int));
always2(func2opt(int, int), func1(num));
always2(func2extra(int, int), func2(int, int));
always2(func2extra(int, num), func2(int, int));
always2(func2extra(int, int), func2(num, int));
maybe2(func2(int, int), func2(int, num));
maybe2(func2(num, int), func2(int, int));
maybe2(func2opt(num, num), func1(int));
maybe2(func2opt(int, int), func2opt(int, num));
maybe2(func2opt(num, int), func2opt(int, int));
maybe2(func2opt(int, int), func2(int, num));
maybe2(func2opt(num, int), func2(int, int));
maybe2(func2extra(int, int), func2(int, num));
maybe2(func2extra(num, int), func2(int, int));
never2(func1(int), func2(int, num));
never2(func1(num), func2(int, int));
never2(func1(num), func2(num, num));
never2(func2(int, int), func1(int));
never2(func2(num, int), func1(int));
never2(func2(num, num), func1(num));
never2(func1(int), func2opt(int, num));
never2(func1(num), func2opt(int, int));
never2(func1(num), func2opt(num, num));
never2(func2(int, int), func2opt(int, num));
never2(func2(num, int), func2opt(int, int));
never2(func2(num, num), func2opt(num, num));
never2(func1extra(int), func2(int, num));
never2(func1extra(num), func2(int, int));
never2(func1extra(num), func2(num, num));
never2(func1extra(int), func2opt(int, num));
never2(func1extra(num), func2opt(int, int));
never2(func1extra(num), func2opt(num, num));
never2(func1(int), func1extra(int));
never2(func1(num), func1extra(int));
never2(func1(num), func1extra(num));
never2(func2(int, int), func1extra(int));
never2(func2(num, int), func1extra(int));
never2(func2(num, num), func1extra(num));
never2(func2(int, int), func2extra(int, int));
never2(func2(num, int), func2extra(int, int));
never2(func2(num, num), func2extra(num, num));
};
test('basic function types', () => {
function func1(S) {
return fnTypeFuzzy(S, []);
}
function func2(S, T) {
return fnTypeFuzzy(S, [T]);
}
function func2opt(S, T) {
return fnTypeFuzzy(S, [], [T]);
}
function func1extra(S) {
return fnTypeFuzzy(S, [], {extra: int});
}
function func2extra(S, T) {
return fnTypeFuzzy(S, [T], {extra: int});
}
run_test(func1, func2, func2opt, func1extra, func2extra);
});
test('top and bottom types', () => {
let FutureOr = async.FutureOr$;
let tops = [
dart.dynamic,
core.Object,
dart.void,
FutureOr(dart.dynamic),
FutureOr(core.Object),
FutureOr(dart.void),
FutureOr(FutureOr(core.Object)),
// ... skip the (infinite) rest of the top types :D
];
let bottoms = [dart.bottom, core.Null];
for (let top of tops) {
for (let bottom of bottoms) {
always(bottom, top);
always(
fnType(bottom, [top]),
fnType(top, [bottom]));
}
}
for (let equalTypes of [tops, bottoms]) {
for (let t1 of equalTypes) {
for (let t2 of equalTypes) {
always(t1, t2);
always(t2, t1);
let t11 = fnType(t1, [t1]);
let t22 = fnType(t2, [t2]);
always(t11, t22);
always(t22, t11);
}
}
}
});
test('basic typedefs', () => {
function func1(S) {
return dart.typedef('Func1', () => fnTypeFuzzy(S, []))
}
function func2(S, T) {
return dart.typedef('Func2', () => fnTypeFuzzy(S, [T]))
}
function func2opt(S, T) {
return dart.typedef('Func2', () => fnTypeFuzzy(S, [], [T]))
}
function func1extra(S) {
return dart.typedef('Func1', () => fnTypeFuzzy(S, [], {extra: int}))
}
function func2extra(S, T) {
return dart.typedef('Func2', () => fnTypeFuzzy(S, [T], {extra: int}))
}
run_test(func1, func2, func2opt, func1extra, func2extra);
});
test('basic generic typedefs', () => {
let func1 = dart.generic(
(S) => dart.typedef('Func1', () => fnTypeFuzzy(S, [])));
let func2 = dart.generic(
(S, T) => dart.typedef('Func2', () => fnTypeFuzzy(S, [T])));
let func2opt = dart.generic(
(S, T) => dart.typedef('Func2', () => fnTypeFuzzy(S, [], [T])));
let func1extra = dart.generic(
(S) => dart.typedef('Func1', () => fnTypeFuzzy(S, [], {extra: int})));
let func2extra = dart.generic(
(S, T) => dart.typedef('Func2',
() => fnTypeFuzzy(S, [T], {extra: int})));
run_test(func1, func2, func2opt, func1extra, func2extra);
});
test('fuzzy function types', () => {
always(fnTypeFuzzy(int, [int]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dyn, [], [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dyn, []));
always(fnTypeFuzzy(int, [int], {extra: int}), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(dyn, [dyn]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dyn, [], [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dyn, []));
always(fnTypeFuzzy(dyn, [dyn], {extra: dyn}), fnTypeFuzzy(dyn, [dyn]));
});
test('void function types', () => {
always(fnTypeFuzzy(int, [int]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dart.void, [], [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(int, [], [int]), fnTypeFuzzy(dart.void, []));
always(fnTypeFuzzy(int, [int], {extra: int}), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [int]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dart.void, [], [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dart.void, []));
always(fnTypeFuzzy(dart.void, [int], {extra: int}), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dyn, [dyn]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dart.void, [], [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dyn, [], [dyn]), fnTypeFuzzy(dart.void, []));
always(fnTypeFuzzy(dyn, [dyn], {extra: dyn}), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [dyn]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [], [dyn]), fnTypeFuzzy(dart.void, [], [dyn]));
always(fnTypeFuzzy(dart.void, [], [dyn]), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [], [dyn]), fnTypeFuzzy(dart.void, []));
always(fnTypeFuzzy(dart.void, [dyn], {extra: dyn}), fnTypeFuzzy(dart.void, [dyn]));
always(fnTypeFuzzy(dart.void, [int]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dyn, [], [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dyn, [dyn]));
always(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(dyn, []));
always(fnTypeFuzzy(dart.void, [int], {extra: int}), fnTypeFuzzy(dyn, [dyn]));
never(fnTypeFuzzy(dart.void, [int]), fnTypeFuzzy(int, [dyn]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, [], [dyn]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, [dyn]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, []));
never(fnTypeFuzzy(dart.void, [int], {extra: int}), fnTypeFuzzy(int, [dyn]));
never(fnTypeFuzzy(dart.void, [int]), fnTypeFuzzy(int, [int]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, [], [int]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, [int]));
never(fnTypeFuzzy(dart.void, [], [int]), fnTypeFuzzy(int, []));
never(fnTypeFuzzy(dart.void, [int], {extra: int}), fnTypeFuzzy(int, [int]));
});
test('higher-order typedef', () => {
let Func$ = dart.generic((S, T) =>
dart.typedef('Func', () =>
fnTypeFuzzy(T, [S])));
let Func2$ = dart.generic((R, S, T) =>
dart.typedef('Func2', () =>
fnTypeFuzzy(T, [Func$(R, S)])));
maybe(fnTypeFuzzy(int, [fnTypeFuzzy(int, [num])]),
fnTypeFuzzy(num, [fnTypeFuzzy(int, [int])]));
maybe(fnTypeFuzzy(int, [Func$(num, int)]),
fnTypeFuzzy(num, [Func$(int, int)]));
maybe(Func2$(num, int, int), Func2$(int, int, num));
});
test('mixed types', () => {
let AA$ = dart.generic((T) => {
class AA extends core.Object {}
(AA.new = function() {}).prototype = AA.prototype;
return AA;
});
always(int, dyn);
maybe(dyn, int);
never(fnTypeFuzzy(int, [int]), int);
never(int, fnTypeFuzzy(int, [int]));
always(AA$(int), AA$(dyn));
maybe(AA$(dyn), AA$(int));
never(AA$(core.Object), AA$(int));
always(AA$(fnTypeFuzzy(int, [int])), AA$(dyn));
maybe(AA$(dyn), AA$(fnTypeFuzzy(int, [int])));
never(AA$(core.Object), AA$(fnTypeFuzzy(int, [int])));
always(AA$(fnTypeFuzzy(int, [int])), AA$(fnTypeFuzzy(dyn, [dyn])));
maybe(AA$(fnTypeFuzzy(dyn, [dyn])), AA$(fnTypeFuzzy(int, [int])));
maybe(AA$(fnTypeFuzzy(core.Object, [core.Object])),
AA$(fnTypeFuzzy(int, [int])));
});
});
suite('canonicalization', function() {
'use strict';
let fnTypeFuzzy = dart.fnTypeFuzzy;
let fnType = dart.fnType;
let typedef = dart.typedef;
let generic = dart.generic;
let Object = core.Object;
let String = core.String;
let int = core.int;
let dynamic = dart.dynamic;
let bottom = dart.bottom;
let Map = core.Map;
let Map$ = core.Map$;
class A {}
let AA$ = generic((T, U) => {
class AA extends core.Object {}
(AA.new = function() {}).prototype = AA.prototype;
return AA;
});
let AA = AA$();
let Func2 = typedef('Func2', () => fnTypeFuzzy(dynamic, [dynamic, dynamic]));
let FuncG$ = generic((T, U) => typedef('FuncG', () => fnTypeFuzzy(T, [T, U])))
let FuncG = FuncG$();
test('base types', () => {
assert.equal(Object, Object);
assert.equal(String, String);
assert.equal(dynamic, dynamic);
});
test('class types', () => {
assert.equal(A, A);
});
test('generic class types', () => {
assert.equal(AA, AA);
assert.equal(AA, AA$(dynamic, dynamic));
assert.equal(AA$(dynamic, dynamic), AA$(dynamic, dynamic));
assert.equal(AA$(AA, Object), AA$(AA, Object));
assert.equal(Map, Map);
assert.equal(Map$(dynamic, dynamic), Map);
assert.equal(Map$(int, Map$(int, int)), Map$(int, Map$(int, int)));
});
test('typedefs', () => {
assert.equal(Func2, Func2);
assert.equal(FuncG, FuncG$(dynamic, dynamic));
assert.equal(FuncG$(dynamic, dynamic), FuncG$(dynamic, dynamic));
assert.equal(FuncG$(String, Func2), FuncG$(String, Func2));
});
test('function types', () => {
assert.equal(fnTypeFuzzy(dynamic, [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [dynamic, dynamic]))
assert.notEqual(fnType(dynamic, [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [dynamic, dynamic]))
assert.equal(fnTypeFuzzy(dynamic, [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [bottom, bottom]))
assert.equal(fnTypeFuzzy(dynamic, [], [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [], [dynamic, dynamic]))
assert.notEqual(fnType(dynamic, [], [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [], [dynamic, dynamic]))
assert.equal(fnTypeFuzzy(dynamic, [], [dynamic, dynamic]),
fnTypeFuzzy(dynamic, [], [bottom, bottom]))
assert.equal(fnTypeFuzzy(dynamic, [], {extra: dynamic}),
fnTypeFuzzy(dynamic, [], {extra: dynamic}))
assert.notEqual(fnType(dynamic, [], {extra: dynamic}),
fnTypeFuzzy(dynamic, [], {extra: dynamic}))
assert.equal(fnTypeFuzzy(dynamic, [], {extra: dynamic}),
fnTypeFuzzy(dynamic, [], {extra: bottom}))
assert.equal(fnTypeFuzzy(int, [int, int]),
fnTypeFuzzy(int, [int, int]))
assert.equal(fnTypeFuzzy(int, [], [int, int]),
fnTypeFuzzy(int, [], [int, int]))
assert.equal(fnTypeFuzzy(int, [int, int], {extra: int}),
fnTypeFuzzy(int, [int, int], {extra: int}))
assert.equal(fnTypeFuzzy(int, [int, int, int, int, int]),
fnTypeFuzzy(int, [int, int, int, int, int]))
assert.notEqual(fnTypeFuzzy(int, [int, int, int, int, int]),
fnTypeFuzzy(int, [int, int, int], [int, int]))
assert.notEqual(fnTypeFuzzy(String, [int, int, int, int, int]),
fnTypeFuzzy(int, [int, int, int, int, int]))
assert.notEqual(fnTypeFuzzy(String, []),
fnTypeFuzzy(int, []))
});
});
suite('primitives', function() {
'use strict';
test('fixed length list', () => {
let list = core.List.new(10);
list[0] = 42;
assert.throws(() => list.add(42));
});
test('toString on ES Symbol', () => {
let sym = Symbol('_foobar');
assert.equal(dart.toString(sym), 'Symbol(_foobar)');
});
});
});