| // 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 core = dart_sdk.core; |
| const collection = dart_sdk.collection; |
| const dart = dart_sdk.dart; |
| const dartx = dart.dartx; |
| |
| |
| 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.list([1, 2, 3], core.int); |
| let s = l[dartx.join](); |
| assert.equal(s, '123'); |
| }); |
| }); |
| |
| |
| suite('instanceOf', () => { |
| "use strict"; |
| |
| let expect = assert.equal; |
| let isGroundType = dart.isGroundType; |
| let generic = dart.generic; |
| let intIsNonNullable = false; |
| let cast = dart.as; |
| let instanceOf = dart.is; |
| let strongInstanceOf = dart.strongInstanceOf; |
| let getReifiedType = dart.getReifiedType; |
| let functionType = dart.functionType; |
| 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 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 {}); |
| let AA = AA$(); |
| let BB$ = generic((T, U) => class BB extends AA$(U, T) {}); |
| let BB = BB$(); |
| class CC extends BB$(String, List) {} |
| |
| let Func2 = typedef('Func2', () => functionType(dynamic, [dynamic, dynamic])); |
| let Foo = typedef('Foo', () => functionType(B, [B, String])); |
| |
| let FuncG$ = generic((T, U) => typedef('FuncG', () => functionType(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.definiteFunctionType(A, [C, String])); |
| |
| // bar2(B b, String s) => null; |
| function bar2(b, s) { return null; } |
| dart.fn(bar2, dart.definiteFunctionType(dynamic, [B, String])); |
| |
| // B bar3(B b, Object o) => null; |
| function bar3(b, o) { return null; } |
| dart.fn(bar3, dart.definiteFunctionType(B, [B, Object])); |
| |
| // B bar4(B b, o) => null; |
| function bar4(b, o) { return null; } |
| dart.fn(bar4, dart.definiteFunctionType(B, [B, dynamic])); |
| |
| // C bar5(A a, Object o) => null; |
| function bar5(a, o) { return null; } |
| dart.fn(bar5, dart.definiteFunctionType(C, [A, Object])); |
| |
| // B bar6(B b, String s, String o) => null; |
| function bar6(b, s, o) { return null; } |
| dart.fn(bar6, dart.definiteFunctionType(B, [B, String, String])); |
| |
| // B bar7(B b, String s, [Object o]) => null; |
| function bar7(b, s, o) { return null; } |
| dart.fn(bar7, dart.definiteFunctionType(B, [B, String], [Object])); |
| |
| // B bar8(B b, String s, {Object p}) => null; |
| function bar8(b, s, o) { return null; } |
| dart.fn(bar8, dart.definiteFunctionType(B, [B, String], {p: Object})); |
| |
| let cls1 = dart.fn((c, s) => { return null; }, |
| dart.definiteFunctionType(A, [C, String])); |
| |
| let cls2 = dart.fn((b, s) => { return null; }, |
| dart.definiteFunctionType(dynamic, [B, String])); |
| |
| let cls3 = dart.fn((b, o) => { return null; }, |
| dart.definiteFunctionType(B, [B, Object])); |
| |
| let cls4 = dart.fn((b, o) => { return null; }, |
| dart.definiteFunctionType(B, [B, dynamic])); |
| |
| let cls5 = dart.fn((a, o) => { return null; }, |
| dart.definiteFunctionType(C, [A, Object])); |
| |
| let cls6 = dart.fn((b, s, o) => { return null; }, |
| dart.definiteFunctionType(B, [B, String, String])); |
| |
| let cls7 = dart.fn((b, s, o) => { return null; }, |
| dart.definiteFunctionType(B, [B, String], [Object])); |
| |
| let cls8 = |
| dart.fn((b, s, o) => { return null; }, |
| dart.definiteFunctionType(B, [B, String], {p: Object})); |
| |
| function checkType(x, type, expectedTrue, strongOnly) { |
| if (expectedTrue === undefined) expectedTrue = true; |
| if (strongOnly == undefined) strongOnly = false; |
| if (!strongOnly) { |
| assert.doesNotThrow(() => instanceOf(x, type)); |
| expect(instanceOf(x, type), expectedTrue); |
| } else { |
| assert.throws(() => instanceOf(x, type), dart.StrongModeError); |
| expect(expectedTrue, false); |
| expect(strongInstanceOf(x, type), null); |
| } |
| } |
| |
| test('int', () => { |
| expect(isGroundType(int), true); |
| expect(isGroundType(getReifiedType(5)), true); |
| |
| 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', () => { |
| expect(isGroundType(dynamic), true); |
| checkType(new Object(), dynamic); |
| checkType(null, dynamic); |
| |
| expect(cast(null, dynamic), null); |
| }); |
| |
| test('Object', () => { |
| expect(isGroundType(Object), true); |
| checkType(new Object(), 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', () => { |
| expect(isGroundType(String), true); |
| expect(isGroundType(getReifiedType("foo")), true); |
| checkType("foo", String); |
| checkType("foo", Object); |
| checkType("foo", dynamic); |
| |
| expect(cast(null, String), null); |
| }); |
| |
| test('Map', () => { |
| let m1 = new (Map$(String, String))(); |
| let m2 = new (Map$(Object, Object))(); |
| let m3 = new Map(); |
| let m4 = new (collection.HashMap$(dart.dynamic, dart.dynamic))(); |
| let m5 = new collection.LinkedHashMap(); |
| let m6 = new (Map$(String, dart.dynamic))(); |
| |
| |
| expect(isGroundType(Map), true); |
| expect(isGroundType(getReifiedType(m1)), false); |
| expect(isGroundType(Map$(String, String)), false); |
| expect(isGroundType(getReifiedType(m2)), true); |
| expect(isGroundType(Map$(Object, Object)), true); |
| expect(isGroundType(getReifiedType(m3)), true); |
| expect(isGroundType(Map), true); |
| expect(isGroundType(getReifiedType(m4)), true); |
| expect(isGroundType(collection.HashMap$(dynamic, dynamic)), true); |
| expect(isGroundType(getReifiedType(m5)), true); |
| expect(isGroundType(collection.LinkedHashMap), true); |
| expect(isGroundType(collection.LinkedHashMap), true); |
| |
| // 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.throws(() => dart.is(m3, Map$(String, String)), |
| dart.StrongModeError); |
| assert.throws(() => dart.is(m6, Map$(String, String)), |
| dart.StrongModeError); |
| 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 { |
| new(x) {}; |
| named(x, y) {}; |
| } |
| dart.defineNamedConstructor(C, 'named'); |
| dart.setSignature(C, { |
| constructors: () => ({ |
| new: dart.definiteFunctionType(C, [core.int]), |
| named: dart.definiteFunctionType(C, [core.int, core.int]) |
| }) |
| }); |
| let getType = dart.classGetConstructorType; |
| isSubtype(getType(C), dart.functionType(C, [core.int])); |
| isSubtype(getType(C), dart.functionType(C, [core.String]), false); |
| isSubtype(getType(C, 'new'), dart.functionType(C, [core.int])); |
| isSubtype(getType(C, 'new'), dart.functionType(C, [core.String]), false); |
| isSubtype(getType(C, 'named'), dart.functionType(C, [core.int, core.int])); |
| isSubtype(getType(C, 'named'), |
| dart.functionType(C, [core.int, core.String]), false); |
| }); |
| |
| test('generic and inheritance', () => { |
| let aaraw = new AA(); |
| let aarawtype = getReifiedType(aaraw); |
| let aadynamic = new (AA$(dynamic, dynamic))(); |
| let aadynamictype = getReifiedType(aadynamic); |
| let aa = new (AA$(String, List))(); |
| let aatype = getReifiedType(aa); |
| let bb = new (BB$(String, List))(); |
| let bbtype = getReifiedType(bb); |
| let cc = new CC(); |
| 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))(); |
| let aabadtype = getReifiedType(aabad); |
| |
| expect(isGroundType(aatype), false); |
| expect(isGroundType(AA$(String, List)), false); |
| expect(isGroundType(bbtype), false); |
| expect(isGroundType(BB$(String, List)), false); |
| expect(isGroundType(cctype), true); |
| expect(isGroundType(CC), true); |
| 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, true); |
| checkType(aabad, AA$(String, List), false, true); |
| 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))(); |
| |
| 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(functionType(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. |
| expect(isGroundType(Func2), true); |
| expect(isGroundType(Foo), false); |
| expect(isGroundType(functionType(B, [B, String])), false); |
| checkType(bar1, Foo, false, true); |
| checkType(cls1, Foo, false, true); |
| checkType(bar1, functionType(B, [B, String]), false, true); |
| checkType(cls1, functionType(B, [B, String]), false, true); |
| checkType(bar2, Foo, false, true); |
| checkType(cls2, Foo, false, true); |
| checkType(bar2, functionType(B, [B, String]), false, true); |
| checkType(cls2, functionType(B, [B, String]), false, true); |
| checkType(bar3, Foo); |
| checkType(cls3, Foo); |
| checkType(bar3, functionType(B, [B, String])); |
| checkType(cls3, functionType(B, [B, String])); |
| checkType(bar4, Foo, true); |
| checkType(cls4, Foo, true); |
| checkType(bar4, functionType(B, [B, String]), true); |
| checkType(cls4, functionType(B, [B, String]), true); |
| checkType(bar5, Foo); |
| checkType(cls5, Foo); |
| checkType(bar5, functionType(B, [B, String])); |
| checkType(cls5, functionType(B, [B, String])); |
| checkType(bar6, Foo, false); |
| checkType(cls6, Foo, false); |
| checkType(bar6, functionType(B, [B, String]), false); |
| checkType(cls6, functionType(B, [B, String]), false); |
| checkType(bar7, Foo); |
| checkType(cls7, Foo); |
| checkType(bar7, functionType(B, [B, String])); |
| checkType(cls7, functionType(B, [B, String])); |
| checkType(bar7, getReifiedType(bar6)); |
| checkType(cls7, getReifiedType(bar6)); |
| checkType(bar8, Foo); |
| checkType(cls8, Foo); |
| checkType(bar8, functionType(B, [B, String])); |
| checkType(cls8, functionType(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 |
| expect(isGroundType(FuncG), true); |
| expect(isGroundType(FuncG$(B, String)), false); |
| checkType(bar1, FuncG$(B, String), false, true); |
| checkType(cls1, FuncG$(B, String), false, true); |
| 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.definiteFunctionType(core.int, [core.int, core.int])); |
| function ii_2i(x, y) {return x}; |
| dart.fn(ii_2i, dart.definiteFunctionType(core.int, [core.int], [core.int])); |
| function i_i2i(x, opts) {return x}; |
| dart.fn(i_i2i, |
| dart.definiteFunctionType(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 { |
| new() { |
| this.f = dart.fn(x => x, |
| dart.definiteFunctionType(core.int, [core.int])); |
| this.me = this; |
| } |
| m(x, y) {return x;} |
| call(x) {return x;} |
| static s(x, y) { return x;} |
| } |
| dart.setSignature(Tester, { |
| methods: () => ({ |
| m: dart.definiteFunctionType(core.int, [core.int, core.int]), |
| call: dart.definiteFunctionType(core.int, [core.int]) |
| }), |
| statics: () => ({ |
| s: dart.definiteFunctionType(core.String, [core.String]) |
| }), |
| names: ['s'] |
| }) |
| let o = new Tester(); |
| |
| // 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.functionType(core.int, [core.Object])); |
| // Test the normal path |
| checkType(core.identical, |
| dart.functionType(core.bool, |
| [core.Object, core.Object])); |
| |
| // Hand crafted tests |
| // All dynamic |
| function dd2d(x, y) {return x}; |
| dart.fn(dd2d); |
| checkType(dd2d, dart.functionType(dart.dynamic, |
| [dart.dynamic, dart.dynamic])); |
| |
| // Set the type eagerly |
| function ii2i(x, y) {return x}; |
| dart.fn(ii2i, dart.definiteFunctionType(core.int, [core.int, core.int])); |
| checkType(ii2i, dart.functionType(core.int, |
| [core.int, core.int])); |
| |
| // Set the type lazily |
| function ss2s(x, y) {return x}; |
| var coreString; |
| dart.lazyFn(ss2s, |
| () => dart.definiteFunctionType(coreString, |
| [coreString, coreString])); |
| coreString = core.String; |
| checkType(ss2s, dart.functionType(core.String, |
| [core.String, core.String])); |
| |
| // Optional types |
| function ii_2i(x, y) {return x}; |
| dart.fn(ii_2i, dart.definiteFunctionType(core.int, [core.int], [core.int])); |
| checkType(ii_2i, dart.functionType(core.int, [core.int], |
| [core.int])); |
| checkType(ii_2i, dart.functionType(core.int, [core.int, |
| core.int])); |
| checkType(ii_2i, dart.functionType(core.int, [], [core.int, |
| core.int]), |
| false); |
| checkType(ii_2i, dart.functionType(core.int, [core.int], |
| {extra: core.int}), false); |
| |
| // Named types |
| function i_i2i(x, opts) {return x}; |
| dart.fn(i_i2i, dart.definiteFunctionType(core.int, [core.int], |
| {extra: core.int})); |
| checkType(i_i2i, dart.functionType(core.int, [core.int], |
| {extra: core.int})); |
| checkType(i_i2i, dart.functionType(core.int, |
| [core.int, core.int]), false); |
| checkType(i_i2i, dart.functionType(core.int, [core.int], {})); |
| checkType(i_i2i, |
| dart.functionType(core.int, [], {extra: core.int, |
| also: core.int}), false); |
| checkType(i_i2i, |
| dart.functionType(core.int, [core.int], [core.int]), false); |
| }); |
| |
| test('Method tearoffs', () => { |
| let c = collection; |
| // Tear off of an inherited method |
| let map = new (Map$(core.int, core.String))(); |
| checkType(dart.bind(map, 'toString'), |
| dart.functionType(String, [])); |
| checkType(dart.bind(map, 'toString'), |
| dart.functionType(int, []), false, true); |
| |
| // Tear off of a method directly on the object |
| let smap = new (c.SplayTreeMap$(core.int, core.String))(); |
| checkType(dart.bind(smap, 'forEach'), |
| dart.functionType(dart.void, |
| [dart.functionType(dart.void, [core.int, core.String])])); |
| checkType(dart.bind(smap, 'forEach'), |
| dart.functionType(dart.void, |
| [dart.functionType(dart.void, |
| [core.String, core.String])]), false, true); |
| |
| // Tear off of a mixed in method |
| let mapB = new (c.MapBase$(core.int, core.int))(); |
| checkType(dart.bind(mapB, 'forEach'), |
| dart.functionType(dart.void, [ |
| dart.functionType(dart.void, [core.int, core.int])])); |
| checkType(dart.bind(mapB, 'forEach'), |
| dart.functionType(dart.void, [ |
| dart.functionType(dart.void, [core.int, core.String])]), |
| false, true); |
| |
| // Tear off of a method with a symbol name |
| let listB = new (c.ListBase$(core.int))(); |
| checkType(dart.bind(listB, dartx.add), |
| dart.functionType(dart.void, [core.int])); |
| checkType(dart.bind(listB, dartx.add), |
| dart.functionType(dart.void, [core.String]), false, true); |
| |
| // Tear off of a static method |
| checkType(c.ListBase.listToString, |
| dart.functionType(core.String, [core.List])); |
| checkType(c.ListBase.listToString, |
| dart.functionType(core.String, [core.String]), false, true); |
| |
| // Tear-off of extension methods on primitives |
| checkType(dart.bind(3.0, dartx.floor), |
| dart.functionType(core.int, [])); |
| checkType(dart.bind(3.0, dartx.floor), |
| dart.functionType(core.String, []), false, true); |
| checkType(dart.bind("", dartx.endsWith), |
| dart.functionType(core.bool, [core.String])); |
| checkType(dart.bind("", dartx.endsWith), |
| dart.functionType(core.bool, [core.int]), false, true); |
| |
| // Tear off a mixin method |
| class Base { |
| m(x) {return x;} |
| }; |
| dart.setSignature(Base, { |
| methods: () => ({ |
| m: dart.definiteFunctionType(core.int, [core.int]), |
| }) |
| }); |
| |
| class M1 { |
| m(x) {return x;} |
| }; |
| dart.setSignature(M1, { |
| methods: () => ({ |
| m: dart.definiteFunctionType(core.num, [core.int]), |
| }) |
| }); |
| |
| class M2 { |
| m(x) {return x;} |
| }; |
| dart.setSignature(M2, { |
| methods: () => ({ |
| m: dart.definiteFunctionType(core.Object, [core.int]), |
| }) |
| }); |
| |
| class O extends dart.mixin(Base, M1, M2) { |
| new() {}; |
| }; |
| dart.setSignature(O, {}); |
| var obj = new O(); |
| var m = dart.bind(obj, 'm'); |
| checkType(m, dart.functionType(core.Object, [core.int])); |
| checkType(m, dart.functionType(core.int, [core.int]), false, true); |
| |
| // Test inherited signatures |
| class P extends O { |
| new() {}; |
| m(x) {return x;}; |
| }; |
| dart.setSignature(P, {}); |
| var obj = new P(); |
| var m = dart.bind(obj, 'm'); |
| checkType(m, dart.functionType(core.Object, [core.int])); |
| checkType(m, dart.functionType(core.int, [core.int]), false, true); |
| }); |
| |
| test('Object members', () => { |
| let nullHash = dart.hashCode(null); |
| assert.equal(nullHash, 0); |
| let nullString = dart.toString(null); |
| assert.equal(nullString, 'null'); |
| |
| let map = new Map(); |
| 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 functionType = dart.functionType; |
| let definiteFunctionType = dart.definiteFunctionType; |
| 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); |
| } |
| function never(t1, t2) { |
| assert.equal(isSubtype(t1, t2), false); |
| } |
| function maybe(t1, t2) { |
| assert.equal(isSubtype(t1, t2), null); |
| } |
| |
| function always2(t1, t2) { |
| assert.equal(isSubtype(t1, t2), true); |
| always(functionType(t1, [t2]), functionType(t2, [t1])); |
| } |
| function never2(t1, t2) { |
| assert.equal(isSubtype(t1, t2), false); |
| maybe(functionType(t1, [t2]), functionType(t2, [t1])); |
| } |
| function maybe2(t1, t2) { |
| assert.equal(isSubtype(t1, t2), null); |
| maybe(functionType(t1, [t2]), functionType(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 functionType(S, []); |
| } |
| |
| function func2(S, T) { |
| return functionType(S, [T]); |
| } |
| |
| function func2opt(S, T) { |
| return functionType(S, [], [T]); |
| } |
| |
| function func1extra(S) { |
| return functionType(S, [], {extra: int}); |
| } |
| |
| function func2extra(S, T) { |
| return functionType(S, [T], {extra: int}); |
| } |
| |
| run_test(func1, func2, func2opt, func1extra, func2extra); |
| }); |
| |
| test('basic typedefs', () => { |
| function func1(S) { |
| return dart.typedef('Func1', () => functionType(S, [])) |
| } |
| |
| function func2(S, T) { |
| return dart.typedef('Func2', () => functionType(S, [T])) |
| } |
| |
| function func2opt(S, T) { |
| return dart.typedef('Func2', () => functionType(S, [], [T])) |
| } |
| |
| function func1extra(S) { |
| return dart.typedef('Func1', () => functionType(S, [], {extra: int})) |
| } |
| |
| function func2extra(S, T) { |
| return dart.typedef('Func2', () => functionType(S, [T], {extra: int})) |
| } |
| |
| run_test(func1, func2, func2opt, func1extra, func2extra); |
| }); |
| |
| test('basic generic typedefs', () => { |
| let func1 = dart.generic( |
| (S) => dart.typedef('Func1', () => functionType(S, []))); |
| |
| let func2 = dart.generic( |
| (S, T) => dart.typedef('Func2', () => functionType(S, [T]))); |
| |
| let func2opt = dart.generic( |
| (S, T) => dart.typedef('Func2', () => functionType(S, [], [T]))); |
| |
| let func1extra = dart.generic( |
| (S) => dart.typedef('Func1', () => functionType(S, [], {extra: int}))); |
| |
| let func2extra = dart.generic( |
| (S, T) => dart.typedef('Func2', |
| () => functionType(S, [T], {extra: int}))); |
| |
| run_test(func1, func2, func2opt, func1extra, func2extra); |
| }); |
| |
| test('fuzzy function types', () => { |
| always(functionType(int, [int]), functionType(dyn, [dyn])); |
| always(functionType(int, [], [int]), functionType(dyn, [], [dyn])); |
| always(functionType(int, [], [int]), functionType(dyn, [dyn])); |
| always(functionType(int, [], [int]), functionType(dyn, [])); |
| always(functionType(int, [int], {extra: int}), functionType(dyn, [dyn])); |
| |
| always(functionType(dyn, [dyn]), functionType(dyn, [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dyn, [], [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dyn, [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dyn, [])); |
| always(functionType(dyn, [dyn], {extra: dyn}), functionType(dyn, [dyn])); |
| |
| }); |
| |
| test('void function types', () => { |
| always(functionType(int, [int]), functionType(dart.void, [dyn])); |
| always(functionType(int, [], [int]), functionType(dart.void, [], [dyn])); |
| always(functionType(int, [], [int]), functionType(dart.void, [dyn])); |
| always(functionType(int, [], [int]), functionType(dart.void, [])); |
| always(functionType(int, [int], {extra: int}), functionType(dart.void, [dyn])); |
| |
| always(functionType(dart.void, [int]), functionType(dart.void, [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dart.void, [], [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dart.void, [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dart.void, [])); |
| always(functionType(dart.void, [int], {extra: int}), functionType(dart.void, [dyn])); |
| |
| always(functionType(dyn, [dyn]), functionType(dart.void, [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dart.void, [], [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dart.void, [dyn])); |
| always(functionType(dyn, [], [dyn]), functionType(dart.void, [])); |
| always(functionType(dyn, [dyn], {extra: dyn}), functionType(dart.void, [dyn])); |
| |
| always(functionType(dart.void, [dyn]), functionType(dart.void, [dyn])); |
| always(functionType(dart.void, [], [dyn]), functionType(dart.void, [], [dyn])); |
| always(functionType(dart.void, [], [dyn]), functionType(dart.void, [dyn])); |
| always(functionType(dart.void, [], [dyn]), functionType(dart.void, [])); |
| always(functionType(dart.void, [dyn], {extra: dyn}), functionType(dart.void, [dyn])); |
| |
| always(functionType(dart.void, [int]), functionType(dyn, [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dyn, [], [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dyn, [dyn])); |
| always(functionType(dart.void, [], [int]), functionType(dyn, [])); |
| always(functionType(dart.void, [int], {extra: int}), functionType(dyn, [dyn])); |
| |
| never(functionType(dart.void, [int]), functionType(int, [dyn])); |
| never(functionType(dart.void, [], [int]), functionType(int, [], [dyn])); |
| never(functionType(dart.void, [], [int]), functionType(int, [dyn])); |
| never(functionType(dart.void, [], [int]), functionType(int, [])); |
| never(functionType(dart.void, [int], {extra: int}), functionType(int, [dyn])); |
| |
| never(functionType(dart.void, [int]), functionType(int, [int])); |
| never(functionType(dart.void, [], [int]), functionType(int, [], [int])); |
| never(functionType(dart.void, [], [int]), functionType(int, [int])); |
| never(functionType(dart.void, [], [int]), functionType(int, [])); |
| never(functionType(dart.void, [int], {extra: int}), functionType(int, [int])); |
| |
| }); |
| |
| test('higher-order typedef', () => { |
| let Func$ = dart.generic((S, T) => |
| dart.typedef('Func', () => |
| functionType(T, [S]))); |
| let Func2$ = dart.generic((R, S, T) => |
| dart.typedef('Func2', () => |
| functionType(T, [Func$(R, S)]))); |
| |
| maybe(functionType(int, [functionType(int, [num])]), |
| functionType(num, [functionType(int, [int])])); |
| maybe(functionType(int, [Func$(num, int)]), |
| functionType(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 {}); |
| |
| always(int, dyn); |
| maybe(dyn, int); |
| |
| never(functionType(int, [int]), int); |
| |
| never(int, functionType(int, [int])); |
| |
| always(AA$(int), AA$(dyn)); |
| maybe(AA$(dyn), AA$(int)); |
| never(AA$(core.Object), AA$(int)); |
| |
| always(AA$(functionType(int, [int])), AA$(dyn)); |
| maybe(AA$(dyn), AA$(functionType(int, [int]))); |
| never(AA$(core.Object), AA$(functionType(int, [int]))); |
| |
| always(AA$(functionType(int, [int])), AA$(functionType(dyn, [dyn]))); |
| maybe(AA$(functionType(dyn, [dyn])), AA$(functionType(int, [int]))); |
| maybe(AA$(functionType(core.Object, [core.Object])), |
| AA$(functionType(int, [int]))); |
| |
| |
| }); |
| |
| }); |
| |
| suite('canonicalization', function() { |
| 'use strict'; |
| let functionType = dart.functionType; |
| let definiteFunctionType = dart.definiteFunctionType; |
| 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 {}); |
| let AA = AA$(); |
| |
| let Func2 = typedef('Func2', () => functionType(dynamic, [dynamic, dynamic])); |
| |
| let FuncG$ = generic((T, U) => typedef('FuncG', () => functionType(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(functionType(dynamic, [dynamic, dynamic]), |
| functionType(dynamic, [dynamic, dynamic])) |
| |
| assert.notEqual(definiteFunctionType(dynamic, [dynamic, dynamic]), |
| functionType(dynamic, [dynamic, dynamic])) |
| |
| assert.equal(functionType(dynamic, [dynamic, dynamic]), |
| functionType(dynamic, [bottom, bottom])) |
| |
| assert.equal(functionType(dynamic, [], [dynamic, dynamic]), |
| functionType(dynamic, [], [dynamic, dynamic])) |
| |
| assert.notEqual(definiteFunctionType(dynamic, [], [dynamic, dynamic]), |
| functionType(dynamic, [], [dynamic, dynamic])) |
| |
| assert.equal(functionType(dynamic, [], [dynamic, dynamic]), |
| functionType(dynamic, [], [bottom, bottom])) |
| |
| assert.equal(functionType(dynamic, [], {extra: dynamic}), |
| functionType(dynamic, [], {extra: dynamic})) |
| |
| assert.notEqual(definiteFunctionType(dynamic, [], {extra: dynamic}), |
| functionType(dynamic, [], {extra: dynamic})) |
| |
| assert.equal(functionType(dynamic, [], {extra: dynamic}), |
| functionType(dynamic, [], {extra: bottom})) |
| |
| assert.equal(functionType(int, [int, int]), |
| functionType(int, [int, int])) |
| |
| assert.equal(functionType(int, [], [int, int]), |
| functionType(int, [], [int, int])) |
| |
| assert.equal(functionType(int, [int, int], {extra: int}), |
| functionType(int, [int, int], {extra: int})) |
| |
| assert.equal(functionType(int, [int, int, int, int, int]), |
| functionType(int, [int, int, int, int, int])) |
| |
| assert.notEqual(functionType(int, [int, int, int, int, int]), |
| functionType(int, [int, int, int], [int, int])) |
| |
| assert.notEqual(functionType(String, [int, int, int, int, int]), |
| functionType(int, [int, int, int, int, int])) |
| |
| assert.notEqual(functionType(String, []), |
| functionType(int, [])) |
| }); |
| }); |
| |
| suite('primitives', function() { |
| 'use strict'; |
| |
| test('fixed length list', () => { |
| let list = new core.List(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)'); |
| }); |
| }); |
| }); |