@@ -19,6 +19,32 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
19
19
const copyProperties = dart_utils . copyProperties ;
20
20
const safeGetOwnProperty = dart_utils . safeGetOwnProperty ;
21
21
22
+ /**
23
+ * Types in dart are represented at runtime as follows.
24
+ * - Normal nominal types, produced from classes, are represented
25
+ * at runtime by the JS class of which they are an instance.
26
+ * If the type is the result of instantiating a generic class,
27
+ * then the "classes" module manages the association between the
28
+ * instantiated class and the original class declaration
29
+ * and the type arguments with which it was instantiated. This
30
+ * assocation can be queried via the "classes" module".
31
+ *
32
+ * - All other types are represented as instances of class TypeRep,
33
+ * defined in this module.
34
+ * - Dynamic, Void, and Bottom are singleton instances of sentinal
35
+ * classes.
36
+ * - Function types are instances of subclasses of AbstractFunctionType.
37
+ *
38
+ * Function types are represented in one of two ways:
39
+ * - As an instance of FunctionType. These are eagerly computed.
40
+ * - As an instance of TypeDef. The TypeDef representation lazily
41
+ * computes an instance of FunctionType, and delegates to that instance.
42
+ *
43
+ * All types satisfy the following interface:
44
+ * get String name;
45
+ * String toString();
46
+ *
47
+ */
22
48
class TypeRep extends rtti . LazyTagged ( ( ) => core . Type ) {
23
49
get name ( ) { return this . toString ( ) ; }
24
50
}
@@ -90,12 +116,51 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
90
116
}
91
117
92
118
class FunctionType extends AbstractFunctionType {
93
- constructor ( returnType , args , optionals , named ) {
119
+ /**
120
+ * Construct a function type. There are two arrow constructors,
121
+ * distinguished by the "definite" flag.
122
+ *
123
+ * The fuzzy arrow (definite is false) treats any arguments
124
+ * of type dynamic as having type bottom, and will always be
125
+ * called with a dynamic invoke.
126
+ *
127
+ * The definite arrow (definite is true) leaves arguments unchanged.
128
+ *
129
+ * We eagerly canonize the argument types to avoid having to deal with
130
+ * this logic in multiple places.
131
+ *
132
+ * TODO(leafp): Figure out how to present this to the user. How
133
+ * should these be printed out?
134
+ */
135
+ constructor ( definite , returnType , args , optionals , named ) {
94
136
super ( ) ;
137
+ this . definite = definite ;
95
138
this . returnType = returnType ;
96
139
this . args = args ;
97
140
this . optionals = optionals ;
98
141
this . named = named ;
142
+ this . _canonize ( ) ;
143
+ }
144
+ _canonize ( ) {
145
+ if ( this . definite ) return ;
146
+
147
+ function replace ( a ) {
148
+ return ( a == dynamicR ) ? bottomR : a ;
149
+ }
150
+
151
+ this . args = this . args . map ( replace ) ;
152
+
153
+ if ( this . optionals . length > 0 ) {
154
+ this . optionals = this . optionals . map ( replace ) ;
155
+ }
156
+
157
+ if ( Object . keys ( this . named ) . length > 0 ) {
158
+ let r = { } ;
159
+ for ( let name of getOwnPropertyNames ( this . named ) ) {
160
+ r [ name ] = replace ( this . named [ name ] ) ;
161
+ }
162
+ this . named = r ;
163
+ }
99
164
}
100
165
}
101
166
@@ -107,6 +172,10 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
107
172
this . _functionType = null ;
108
173
}
109
174
175
+ get definite ( ) {
176
+ return this . _functionType . definite ;
177
+ }
178
+
110
179
get name ( ) {
111
180
return this . _name ;
112
181
}
@@ -135,7 +204,7 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
135
204
}
136
205
}
137
206
138
- function functionType ( returnType , args , extra ) {
207
+ function _functionType ( definite , returnType , args , extra ) {
139
208
// TODO(vsm): Cache / memomize?
140
209
let optionals ;
141
210
let named ;
@@ -149,10 +218,27 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
149
218
optionals = [ ] ;
150
219
named = extra ;
151
220
}
152
- return new FunctionType ( returnType , args , optionals , named ) ;
221
+ return new FunctionType ( definite , returnType , args , optionals , named ) ;
222
+ }
223
+
224
+ /**
225
+ * Create a "fuzzy" function type. If any arguments are dynamic
226
+ * they will be replaced with bottom.
227
+ */
228
+ function functionType ( returnType , args , extra ) {
229
+ return _functionType ( false , returnType , args , extra ) ;
153
230
}
154
231
exports . functionType = functionType ;
155
232
233
+ /**
234
+ * Create a definite function type. No substitution of dynamic for
235
+ * bottom occurs.
236
+ */
237
+ function definiteFunctionType ( returnType , args , extra ) {
238
+ return _functionType ( true , returnType , args , extra ) ;
239
+ }
240
+ exports . definiteFunctionType = definiteFunctionType ;
241
+
156
242
function typedef ( name , closure ) {
157
243
return new Typedef ( name , closure ) ;
158
244
}
@@ -218,7 +304,7 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
218
304
}
219
305
220
306
for ( let i = 0 ; i < args1 . length ; ++ i ) {
221
- if ( ! isSubtype_ ( args2 [ i ] , args1 [ i ] , true ) ) {
307
+ if ( ! isSubtype_ ( args2 [ i ] , args1 [ i ] ) ) {
222
308
return false ;
223
309
}
224
310
}
@@ -232,13 +318,13 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
232
318
233
319
let j = 0 ;
234
320
for ( let i = args1 . length ; i < args2 . length ; ++ i , ++ j ) {
235
- if ( ! isSubtype_ ( args2 [ i ] , optionals1 [ j ] , true ) ) {
321
+ if ( ! isSubtype_ ( args2 [ i ] , optionals1 [ j ] ) ) {
236
322
return false ;
237
323
}
238
324
}
239
325
240
326
for ( let i = 0 ; i < optionals2 . length ; ++ i , ++ j ) {
241
- if ( ! isSubtype_ ( optionals2 [ i ] , optionals1 [ j ] , true ) ) {
327
+ if ( ! isSubtype_ ( optionals2 [ i ] , optionals1 [ j ] ) ) {
242
328
return false ;
243
329
}
244
330
}
@@ -254,7 +340,7 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
254
340
if ( n1 === void 0 ) {
255
341
return false ;
256
342
}
257
- if ( ! isSubtype_ ( n2 , n1 , true ) ) {
343
+ if ( ! isSubtype_ ( n2 , n1 ) ) {
258
344
return false ;
259
345
}
260
346
}
@@ -298,33 +384,26 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
298
384
}
299
385
exports . isSubtype = isSubtype ;
300
386
301
- function _isBottom ( type , dynamicIsBottom ) {
302
- return ( type == dynamicR && dynamicIsBottom ) || type == bottomR ;
387
+ function _isBottom ( type ) {
388
+ return type == bottomR ;
303
389
}
304
390
305
- function _isTop ( type , dynamicIsBottom ) {
306
- return type == core . Object || ( type == dynamicR && ! dynamicIsBottom ) ;
391
+ function _isTop ( type ) {
392
+ return type == core . Object || ( type == dynamicR ) ;
307
393
}
308
394
309
- function isSubtype_ ( t1 , t2 , opt_dynamicIsBottom ) {
310
- let dynamicIsBottom =
311
- opt_dynamicIsBottom === void 0 ? false : opt_dynamicIsBottom ;
312
-
395
+ function isSubtype_ ( t1 , t2 ) {
313
396
t1 = canonicalType ( t1 ) ;
314
397
t2 = canonicalType ( t2 ) ;
315
398
if ( t1 == t2 ) return true ;
316
399
317
- // In Dart, dynamic is effectively both top and bottom.
318
- // Here, we treat dynamic as one or the other depending on context,
319
- // but not both.
320
-
321
400
// Trivially true.
322
- if ( _isTop ( t2 , dynamicIsBottom ) || _isBottom ( t1 , dynamicIsBottom ) ) {
401
+ if ( _isTop ( t2 ) || _isBottom ( t1 ) ) {
323
402
return true ;
324
403
}
325
404
326
405
// Trivially false.
327
- if ( _isTop ( t1 , dynamicIsBottom ) || _isBottom ( t2 , dynamicIsBottom ) ) {
406
+ if ( _isTop ( t1 ) || _isBottom ( t2 ) ) {
328
407
return false ;
329
408
}
330
409
@@ -413,16 +492,16 @@ dart_library.library('dart_runtime/_types', null, /* Imports */[
413
492
// TODO(vsm): Cache this if we start using it at runtime.
414
493
415
494
if ( type instanceof AbstractFunctionType ) {
416
- if ( ! _isTop ( type . returnType , false ) ) return false ;
495
+ if ( ! _isTop ( type . returnType ) ) return false ;
417
496
for ( let i = 0 ; i < type . args . length ; ++ i ) {
418
- if ( ! _isBottom ( type . args [ i ] , true ) ) return false ;
497
+ if ( ! _isBottom ( type . args [ i ] ) ) return false ;
419
498
}
420
499
for ( let i = 0 ; i < type . optionals . length ; ++ i ) {
421
- if ( ! _isBottom ( type . optionals [ i ] , true ) ) return false ;
500
+ if ( ! _isBottom ( type . optionals [ i ] ) ) return false ;
422
501
}
423
502
let names = getOwnPropertyNames ( type . named ) ;
424
503
for ( let i = 0 ; i < names . length ; ++ i ) {
425
- if ( ! _isBottom ( type . named [ names [ i ] ] , true ) ) return false ;
504
+ if ( ! _isBottom ( type . named [ names [ i ] ] ) ) return false ;
426
505
}
427
506
return true ;
428
507
}
0 commit comments