Index: tool/input_sdk/private/ddc_runtime/types.dart |
diff --git a/tool/input_sdk/private/ddc_runtime/types.dart b/tool/input_sdk/private/ddc_runtime/types.dart |
index c5470d1a5fbb291d5f57a1b150eb2c12e6657c8b..0b0098731c29271cb36134dc049a9e57e183bb27 100644 |
--- a/tool/input_sdk/private/ddc_runtime/types.dart |
+++ b/tool/input_sdk/private/ddc_runtime/types.dart |
@@ -11,9 +11,11 @@ final _mixins = JS('', 'Symbol("mixins")'); |
final implements_ = JS('', 'Symbol("implements")'); |
final metadata = JS('', 'Symbol("metadata")'); |
+/// The symbol used to store the cached `Type` object associated with a class. |
+final _typeObject = JS('', 'Symbol("typeObject")'); |
+/// Types in dart are represented internally at runtime as follows. |
/// |
-/// Types in dart are represented at runtime as follows. |
/// - Normal nominal types, produced from classes, are represented |
/// at runtime by the JS class of which they are an instance. |
/// If the type is the result of instantiating a generic class, |
@@ -33,11 +35,15 @@ final metadata = JS('', 'Symbol("metadata")'); |
/// - As an instance of TypeDef. The TypeDef representation lazily |
/// computes an instance of FunctionType, and delegates to that instance. |
/// |
-/// All types satisfy the following interface: |
-/// get String name; |
-/// String toString(); |
-/// |
+/// These above "runtime types" are what is used for implementing DDC's |
+/// internal type checks. These objects are distinct from the objects exposed |
+/// to user code by class literals and calling `Object.runtimeType`. In DDC, |
+/// the latter are represented by instances of WrappedType which contain a |
+/// real runtime type internally. This ensures that the returned object only |
+/// exposes the API that Type defines: |
/// |
+/// get String name; |
+/// String toString(); |
final TypeRep = JS('', ''' |
class TypeRep { |
get name() { return this.toString(); } |
@@ -75,6 +81,16 @@ final JSObject = JS('', ''' |
'''); |
final jsobject = JS('', 'new $JSObject()'); |
+final WrappedType = JS('', ''' |
+ class WrappedType extends $TypeRep { |
+ constructor(type) { |
+ super(); |
+ this._runtimeType = type; |
+ } |
+ toString() { return $typeName(this._runtimeType); } |
+ } |
+'''); |
+ |
final AbstractFunctionType = JS('', ''' |
class AbstractFunctionType extends $TypeRep { |
constructor() { |
@@ -303,15 +319,26 @@ typeName(type) => JS('', '''(() => { |
if (tag === $Type) { |
let name = $type.name; |
let args = $getGenericArgs($type); |
- if (args) { |
- name += '<'; |
- for (let i = 0; i < args.length; ++i) { |
- if (i > 0) name += ', '; |
- name += $typeName(args[i]); |
- } |
- name += '>'; |
+ if (!args) return name; |
+ |
+ let result = name; |
+ let allDynamic = true; |
+ |
+ result += '<'; |
+ for (let i = 0; i < args.length; ++i) { |
+ if (i > 0) name += ', '; |
+ |
+ let argName = $typeName(args[i]); |
+ if (argName != 'dynamic') allDynamic = false; |
+ |
+ result += argName; |
} |
- return name; |
+ result += '>'; |
+ |
+ // Don't print the type arguments if they are all dynamic. Show "raw" |
+ // types as just the bare type name. |
+ if (allDynamic) return name; |
+ return result; |
} |
if (tag) return "Not a type: " + tag.name; |
return "JSObject<" + $type.name + ">"; |
@@ -405,18 +432,18 @@ isFunctionSubType(ft1, ft2) => JS('', '''(() => { |
/// This maps JS types onto their corresponding Dart Type. |
/// |
// TODO(jmesserly): lots more needs to be done here. |
-canonicalType(t) { |
- if (JS('bool', '# === Object', t)) return Object; |
- if (JS('bool', '# === Function', t)) return Function; |
- if (JS('bool', '# === Array', t)) return List; |
+canonicalType(t) => JS('', '''(() => { |
+ if (t === Object) return Object; |
+ if (t === Function) return Function; |
+ if (t === Array) return List; |
// We shouldn't normally get here with these types, unless something strange |
// happens like subclassing Number in JS and passing it to Dart. |
- if (JS('bool', '# === String', t)) return String; |
- if (JS('bool', '# === Number', t)) return double; |
- if (JS('bool', '# === Boolean', t)) return bool; |
- return t; |
-} |
+ if (t === String) return String; |
+ if (t === Number) return double; |
+ if (t === Boolean) return bool; |
+ return t; |
+})()'''); |
final subtypeMap = JS('', 'new Map()'); |
isSubtype(t1, t2) => JS('', '''(() => { |