Skip to content

Commit 44db042

Browse files
committed
Redo how Type objects are exposed from DDC.
- Instead of using the raw runtime type that DDC uses for its type checks, use a WrappedType that correctly implements Type's interface. - Compile class literals to wrap the type in a WrappedType. - Make Object.runtimeType() do the same thing. Fixes #488. Fixes #511. [email protected] Review URL: https://codereview.chromium.org/1944483002 .
1 parent 6485751 commit 44db042

File tree

16 files changed

+299
-172
lines changed

16 files changed

+299
-172
lines changed

pkg/dev_compiler/lib/runtime/dart_library.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,6 @@ var dart_library =
107107

108108
// Force import of core.
109109
var dart_sdk = import_('dart_sdk');
110-
var core = dart_sdk.core;
111-
112-
// TODO(jmesserly): this can't be right.
113-
// See: https://github.com/dart-lang/dev_compiler/issues/488
114-
core.Object.toString = function() {
115-
// Interface types are represented by the corresponding constructor
116-
// function. This ensures that Dart interface types print properly.
117-
return this.name;
118-
}
119110

120111
// TODO(vsm): DOM facades?
121112
// See: https://github.com/dart-lang/dev_compiler/issues/173

pkg/dev_compiler/lib/runtime/dart_sdk.js

Lines changed: 81 additions & 60 deletions
Large diffs are not rendered by default.

pkg/dev_compiler/lib/src/compiler/code_generator.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class CodeGenerator extends GeneralizingAstVisitor
116116

117117
String _buildRoot;
118118

119+
/// Whether we are currently generating code for the body of a `JS()` call.
120+
bool _isInForeignJS = false;
121+
119122
CodeGenerator(AnalysisContext c, this.options, this._extensionTypes)
120123
: context = c,
121124
types = c.typeProvider,
@@ -219,7 +222,6 @@ class CodeGenerator extends GeneralizingAstVisitor
219222
// Add implicit dart:core dependency so it is first.
220223
emitLibraryName(dartCoreLibrary);
221224

222-
//
223225
// Visit each compilation unit and emit its code.
224226
//
225227
// NOTE: declarations are not necessarily emitted in this order.
@@ -2009,7 +2011,18 @@ class CodeGenerator extends GeneralizingAstVisitor
20092011

20102012
// type literal
20112013
if (element is TypeDefiningElement) {
2012-
return _emitTypeName(fillDynamicTypeArgs(element.type));
2014+
var typeName = _emitTypeName(fillDynamicTypeArgs(element.type));
2015+
2016+
// If the type is a type literal expression in Dart code, wrap the raw
2017+
// runtime type in a "Type" instance.
2018+
if (!_isInForeignJS &&
2019+
node.parent is! MethodInvocation &&
2020+
node.parent is! PrefixedIdentifier &&
2021+
node.parent is! PropertyAccess) {
2022+
typeName = js.call('dart.wrapType(#)', typeName);
2023+
}
2024+
2025+
return typeName;
20132026
}
20142027

20152028
// library member
@@ -2477,8 +2490,20 @@ class CodeGenerator extends GeneralizingAstVisitor
24772490
source = (code as StringLiteral).stringValue;
24782491
}
24792492

2493+
// TODO(rnystrom): The JS() calls are almost never nested, and probably
2494+
// really shouldn't be, but there are at least a couple of calls in the
2495+
// HTML library where an argument to JS() is itself a JS() call. If those
2496+
// go away, this can just assert(!_isInForeignJS).
2497+
// Inside JS(), type names evaluate to the raw runtime type, not the
2498+
// wrapped Type object.
2499+
var wasInForeignJS = _isInForeignJS;
2500+
_isInForeignJS = true;
2501+
24802502
var template = js.parseForeignJS(source);
24812503
var result = template.instantiate(_visitList(templateArgs));
2504+
2505+
_isInForeignJS = wasInForeignJS;
2506+
24822507
// `throw` is emitted as a statement by `parseForeignJS`.
24832508
assert(result is JS.Expression || node.parent is ExpressionStatement);
24842509
return result;

pkg/dev_compiler/test/browser/runtime_tests.js

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ suite('instanceOf', () => {
119119
let cast = dart.as;
120120
let instanceOf = dart.is;
121121
let strongInstanceOf = dart.strongInstanceOf;
122-
let runtimeType = dart.realRuntimeType;
122+
let getReifiedType = dart.getReifiedType;
123123
let functionType = dart.functionType;
124124
let typedef = dart.typedef;
125125
let isSubtype = dart.isSubtype;
@@ -213,7 +213,7 @@ suite('instanceOf', () => {
213213

214214
test('int', () => {
215215
expect(isGroundType(int), true);
216-
expect(isGroundType(runtimeType(5)), true);
216+
expect(isGroundType(getReifiedType(5)), true);
217217

218218
checkType(5, int);
219219
checkType(5, dynamic);
@@ -260,7 +260,7 @@ suite('instanceOf', () => {
260260

261261
test('String', () => {
262262
expect(isGroundType(String), true);
263-
expect(isGroundType(runtimeType("foo")), true);
263+
expect(isGroundType(getReifiedType("foo")), true);
264264
checkType("foo", String);
265265
checkType("foo", Object);
266266
checkType("foo", dynamic);
@@ -278,15 +278,15 @@ suite('instanceOf', () => {
278278

279279

280280
expect(isGroundType(Map), true);
281-
expect(isGroundType(runtimeType(m1)), false);
281+
expect(isGroundType(getReifiedType(m1)), false);
282282
expect(isGroundType(Map$(String, String)), false);
283-
expect(isGroundType(runtimeType(m2)), true);
283+
expect(isGroundType(getReifiedType(m2)), true);
284284
expect(isGroundType(Map$(Object, Object)), true);
285-
expect(isGroundType(runtimeType(m3)), true);
285+
expect(isGroundType(getReifiedType(m3)), true);
286286
expect(isGroundType(Map), true);
287-
expect(isGroundType(runtimeType(m4)), true);
287+
expect(isGroundType(getReifiedType(m4)), true);
288288
expect(isGroundType(collection.HashMap$(dynamic, dynamic)), true);
289-
expect(isGroundType(runtimeType(m5)), true);
289+
expect(isGroundType(getReifiedType(m5)), true);
290290
expect(isGroundType(collection.LinkedHashMap), true);
291291
expect(isGroundType(collection.LinkedHashMap), true);
292292

@@ -295,15 +295,15 @@ suite('instanceOf', () => {
295295
checkType(m1, Object);
296296

297297
// Instance of self
298-
checkType(m1, runtimeType(m1));
298+
checkType(m1, getReifiedType(m1));
299299
checkType(m1, Map$(String, String));
300300

301301
// Covariance on generics
302-
checkType(m1, runtimeType(m2));
302+
checkType(m1, getReifiedType(m2));
303303
checkType(m1, Map$(Object, Object));
304304

305305
// No contravariance on generics.
306-
checkType(m2, runtimeType(m1), false, true);
306+
checkType(m2, getReifiedType(m1), false, true);
307307
checkType(m2, Map$(String, String), false, true);
308308

309309
// null is! Map
@@ -358,19 +358,19 @@ suite('instanceOf', () => {
358358

359359
test('generic and inheritance', () => {
360360
let aaraw = new AA();
361-
let aarawtype = runtimeType(aaraw);
361+
let aarawtype = getReifiedType(aaraw);
362362
let aadynamic = new (AA$(dynamic, dynamic))();
363-
let aadynamictype = runtimeType(aadynamic);
363+
let aadynamictype = getReifiedType(aadynamic);
364364
let aa = new (AA$(String, List))();
365-
let aatype = runtimeType(aa);
365+
let aatype = getReifiedType(aa);
366366
let bb = new (BB$(String, List))();
367-
let bbtype = runtimeType(bb);
367+
let bbtype = getReifiedType(bb);
368368
let cc = new CC();
369-
let cctype = runtimeType(cc);
369+
let cctype = getReifiedType(cc);
370370
// We don't allow constructing bad types.
371371
// This was AA<String> in Dart (wrong number of type args).
372372
let aabad = new (AA$(dart.dynamic, dart.dynamic))();
373-
let aabadtype = runtimeType(aabad);
373+
let aabadtype = getReifiedType(aabad);
374374

375375
expect(isGroundType(aatype), false);
376376
expect(isGroundType(AA$(String, List)), false);
@@ -471,18 +471,18 @@ suite('instanceOf', () => {
471471
checkType(cls7, Foo);
472472
checkType(bar7, functionType(B, [B, String]));
473473
checkType(cls7, functionType(B, [B, String]));
474-
checkType(bar7, runtimeType(bar6));
475-
checkType(cls7, runtimeType(bar6));
474+
checkType(bar7, getReifiedType(bar6));
475+
checkType(cls7, getReifiedType(bar6));
476476
checkType(bar8, Foo);
477477
checkType(cls8, Foo);
478478
checkType(bar8, functionType(B, [B, String]));
479479
checkType(cls8, functionType(B, [B, String]));
480-
checkType(bar8, runtimeType(bar6), false, true);
481-
checkType(cls8, runtimeType(bar6), false, true);
482-
checkType(bar7, runtimeType(bar8), false, true);
483-
checkType(cls7, runtimeType(bar8), false, true);
484-
checkType(bar8, runtimeType(bar7), false, true);
485-
checkType(cls8, runtimeType(bar7), false, true);
480+
checkType(bar8, getReifiedType(bar6), false, true);
481+
checkType(cls8, getReifiedType(bar6), false, true);
482+
checkType(bar7, getReifiedType(bar8), false, true);
483+
checkType(cls7, getReifiedType(bar8), false, true);
484+
checkType(bar8, getReifiedType(bar7), false, true);
485+
checkType(cls8, getReifiedType(bar7), false, true);
486486

487487
// Parameterized typedefs
488488
expect(isGroundType(FuncG), true);
@@ -747,8 +747,6 @@ suite('instanceOf', () => {
747747
assert.equal(nullHash, 0);
748748
let nullString = dart.toString(null);
749749
assert.equal(nullString, 'null');
750-
let nullType = dart.runtimeType(null);
751-
assert.equal(nullType, core.Null);
752750

753751
let map = new Map();
754752
let mapHash = dart.hashCode(map);
@@ -758,8 +756,6 @@ suite('instanceOf', () => {
758756
let mapString = dart.toString(map);
759757
assert.equal(mapString, map.toString());
760758
checkType(mapString, core.String);
761-
let mapType = dart.runtimeType(map);
762-
assert.equal(mapType, map.runtimeType);
763759

764760
let str = "A string";
765761
let strHash = dart.hashCode(str);
@@ -768,17 +764,13 @@ suite('instanceOf', () => {
768764
let strString = dart.toString(str);
769765
checkType(strString, core.String);
770766
assert.equal(str, strString);
771-
let strType = dart.runtimeType(str);
772-
assert.equal(strType, core.String);
773767

774768
let n = 42;
775769
let intHash = dart.hashCode(n);
776770
checkType(intHash, core.int);
777771

778772
let intString = dart.toString(n);
779773
assert.equal(intString, '42');
780-
let intType = dart.runtimeType(n);
781-
assert.equal(intType, core.int);
782774
});
783775
});
784776

pkg/dev_compiler/test/codegen/expect/misc.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ dart_library.library('misc', null, /* Imports */[
1717
misc.Generic$ = dart.generic(T => {
1818
class Generic extends core.Object {
1919
get type() {
20-
return misc.Generic;
20+
return dart.wrapType(misc.Generic);
2121
}
2222
m() {
23-
return core.print(T);
23+
return core.print(dart.wrapType(T));
2424
}
2525
}
2626
dart.setSignature(Generic, {
@@ -57,8 +57,8 @@ dart_library.library('misc', null, /* Imports */[
5757
core.print(dart.toString(1.0));
5858
core.print(dart.toString(1.1));
5959
let x = 42;
60-
core.print(dart.equals(x, dart.dynamic));
61-
core.print(dart.equals(x, misc.Generic));
60+
core.print(dart.equals(x, dart.wrapType(dart.dynamic)));
61+
core.print(dart.equals(x, dart.wrapType(misc.Generic)));
6262
core.print(new (misc.Generic$(core.int))().type);
6363
core.print(dart.equals(new misc.Derived(), new misc.Derived()));
6464
new (misc.Generic$(core.int))().m();
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "package:expect/expect.dart";
6+
7+
// TODO(rnystrom): This test has a lot of overlap with some other language
8+
// tests, but those are sort of all over the place so I thought it useful to
9+
// test all of the relevant bits in one place here.
10+
11+
class Foo {}
12+
13+
class Box<T> {
14+
Type get typeArg => T;
15+
}
16+
17+
typedef int Func(bool b);
18+
typedef int GenericFunc<T>(T t);
19+
20+
main() {
21+
// Primitive types.
22+
testType(Object, "Object");
23+
testType(Null, "Null");
24+
testType(bool, "bool");
25+
testType(double, "double");
26+
testType(int, "int");
27+
testType(num, "num");
28+
testType(String, "String");
29+
30+
// Class types.
31+
testType(Foo, "Foo");
32+
33+
// Generic classes.
34+
testType(Box, "Box");
35+
testType(new Box<Foo>().typeArg, "Foo");
36+
testType(new Box<dynamic>().typeArg, "dynamic");
37+
testType(new Box<Box<Foo>>().typeArg, "Box<Foo>");
38+
39+
// Typedef.
40+
testType(Func, "Func");
41+
testType(GenericFunc, "GenericFunc");
42+
43+
// TODO(rnystrom): This should print "GenericFunc<int>", but that isn't
44+
// implemented yet.
45+
testType(new Box<GenericFunc<int>>().typeArg, "GenericFunc");
46+
47+
// Literals are canonicalized.
48+
Expect.identical(Foo, Foo);
49+
Expect.identical(Box, Box);
50+
Expect.identical(new Box<Foo>().typeArg, new Box<Foo>().typeArg);
51+
Expect.identical(Func, Func);
52+
}

pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ Object _convertToDart(o) {
487487
var ms = JS('num', '#.getTime()', o);
488488
return new DateTime.fromMillisecondsSinceEpoch(ms);
489489
} else if (o is _DartObject &&
490-
JS('bool', 'dart.jsobject != dart.realRuntimeType(#)', o)) {
490+
JS('bool', 'dart.jsobject != dart.getReifiedType(#)', o)) {
491491
return o._dartObj;
492492
} else {
493493
return _putIfAbsent(_dartProxies, o, _wrapToDart);

pkg/dev_compiler/tool/input_sdk/patch/core_patch.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Object {
4242
}
4343

4444
@patch
45-
Type get runtimeType => JS('Type', 'dart.realRuntimeType(#)', this);
45+
Type get runtimeType => JS('Type', 'dart.objectRuntimeType(#)', this);
4646
}
4747

4848
// Patch for Function implementation.

pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ _ignoreTypeFailure(actual, type) => JS('', '''(() => {
195195
})()''');
196196

197197
strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => {
198-
let actual = $realRuntimeType($obj);
198+
let actual = $getReifiedType($obj);
199199
if ($isSubtype(actual, $type) || actual == $jsobject ||
200200
actual == $int && type == $double) return true;
201201
if ($ignoreFromWhiteList == void 0) return false;
@@ -217,7 +217,7 @@ instanceOf(obj, type) => JS('', '''(() => {
217217
// TODO(vsm): We can statically detect many cases where this
218218
// check is unnecessary.
219219
if ($isGroundType($type)) return false;
220-
let actual = $realRuntimeType($obj);
220+
let actual = $getReifiedType($obj);
221221
$throwStrongModeError('Strong mode is check failure: ' +
222222
$typeName(actual) + ' does not soundly subtype ' +
223223
$typeName($type));
@@ -228,7 +228,7 @@ cast(obj, type) => JS('', '''(() => {
228228
// TODO(#296): This is perhaps too eager to throw a StrongModeError?
229229
// TODO(vsm): handle non-nullable types
230230
if ($instanceOfOrNull($obj, $type)) return $obj;
231-
let actual = $realRuntimeType($obj);
231+
let actual = $getReifiedType($obj);
232232
if ($isGroundType($type)) $throwCastError(actual, $type);
233233
234234
if ($_ignoreTypeFailure(actual, $type)) return $obj;
@@ -243,7 +243,7 @@ asInt(obj) => JS('', '''(() => {
243243
}
244244
if (Math.floor($obj) != $obj) {
245245
// Note: null will also be caught by this check
246-
$throwCastError($realRuntimeType($obj), $int);
246+
$throwCastError($getReifiedType($obj), $int);
247247
}
248248
return $obj;
249249
})()''');
@@ -390,7 +390,7 @@ final constants = JS('', 'new Map()');
390390
///
391391
@JSExportName('const')
392392
const_(obj) => JS('', '''(() => {
393-
let objectKey = [$realRuntimeType($obj)];
393+
let objectKey = [$getReifiedType($obj)];
394394
// TODO(jmesserly): there's no guarantee in JS that names/symbols are
395395
// returned in the same order.
396396
//

0 commit comments

Comments
 (0)