Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dev_compiler.runtime.dart_runtime; | 5 library dev_compiler.runtime.dart_runtime; |
| 6 | 6 |
| 7 import 'dart:mirrors'; | 7 import 'dart:mirrors'; |
| 8 | 8 |
| 9 import 'package:dev_compiler/config.dart'; | 9 import 'package:dev_compiler/config.dart'; |
| 10 | 10 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 if (obj == null) { | 55 if (obj == null) { |
| 56 // Only true for the Object type. | 56 // Only true for the Object type. |
| 57 return staticType == Object || staticType == dynamic || staticType == Null; | 57 return staticType == Object || staticType == dynamic || staticType == Null; |
| 58 } | 58 } |
| 59 | 59 |
| 60 Type runtimeType = obj.runtimeType; | 60 Type runtimeType = obj.runtimeType; |
| 61 return _isSubType(reflectType(runtimeType), reflectType(staticType)); | 61 return _isSubType(reflectType(runtimeType), reflectType(staticType)); |
| 62 } | 62 } |
| 63 | 63 |
| 64 bool isGroundType(Type type) { | 64 bool isGroundType(Type type) { |
| 65 // These are types allow in is / as expressions. | 65 // These are types allowed in is / as expressions. |
| 66 final mirror = reflectType(type); | 66 final mirror = reflectType(type); |
| 67 // Disallow functions. | 67 return _isGroundTypeMirror(mirror); |
| 68 if (mirror is FunctionTypeMirror) return false; | |
| 69 if (mirror is TypedefMirror) return false; | |
| 70 // Disallow generic type parameters. | |
| 71 if (mirror is TypeVariableMirror) return false; | |
| 72 | |
| 73 if (mirror is ClassMirror) { | |
| 74 return _isRawClass(mirror); | |
| 75 } | |
| 76 | |
| 77 // Only dynamic should be left. Should this be allowed? | |
| 78 // It's not particularly useful. | |
| 79 assert(mirror.reflectedType == dynamic); | |
| 80 return true; | |
| 81 } | 68 } |
| 82 | 69 |
| 83 final _primitiveMap = { | 70 final _primitiveMap = { |
| 84 'int': int, | 71 'int': int, |
| 85 'double': double, | 72 'double': double, |
| 86 'num': num, | 73 'num': num, |
| 87 'bool': bool, | 74 'bool': bool, |
| 88 'String': String, | 75 'String': String, |
| 89 }; | 76 }; |
| 90 | 77 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 | 131 |
| 145 if (params1.length < params2.length) { | 132 if (params1.length < params2.length) { |
| 146 return false; | 133 return false; |
| 147 } | 134 } |
| 148 | 135 |
| 149 for (int i = 0; i < params2.length; ++i) { | 136 for (int i = 0; i < params2.length; ++i) { |
| 150 ParameterMirror p1 = params1[i]; | 137 ParameterMirror p1 = params1[i]; |
| 151 ParameterMirror p2 = params2[i]; | 138 ParameterMirror p2 = params2[i]; |
| 152 | 139 |
| 153 // Contravariant parameter types. | 140 // Contravariant parameter types. |
| 154 if (!_isSubType(p2.type, p1.type)) { | 141 if (!_isSubType(p2.type, p1.type, dynamicIsBottom: true)) { |
| 155 return false; | 142 return false; |
| 156 } | 143 } |
| 157 | 144 |
| 158 // Optional parameters. | 145 // Optional parameters. |
| 159 if (p2.isOptional) { | 146 if (p2.isOptional) { |
| 160 // If the base param is optional, the sub param must be optional: | 147 // If the base param is optional, the sub param must be optional: |
| 161 if (!p1.isOptional) return false; | 148 if (!p1.isOptional) return false; |
| 162 if (!p2.isNamed) { | 149 if (!p2.isNamed) { |
| 163 // either neither are named or | 150 // either neither are named or |
| 164 if (p1.isNamed) return false; | 151 if (p1.isNamed) return false; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 184 bool _isClassSubType(ClassMirror m1, ClassMirror m2) { | 171 bool _isClassSubType(ClassMirror m1, ClassMirror m2) { |
| 185 // TODO(vsm): Consider some caching for efficiency here. | 172 // TODO(vsm): Consider some caching for efficiency here. |
| 186 | 173 |
| 187 // We support Dart's covariant generics with the caveat that we do not | 174 // We support Dart's covariant generics with the caveat that we do not |
| 188 // substitute bottom for dynamic in subtyping rules. | 175 // substitute bottom for dynamic in subtyping rules. |
| 189 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: | 176 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: |
| 190 // - S !<: S<T1, ..., Tn> | 177 // - S !<: S<T1, ..., Tn> |
| 191 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> | 178 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> |
| 192 if (m1 == m2) return true; | 179 if (m1 == m2) return true; |
| 193 | 180 |
| 194 if (m1.hasReflectedType && m1.reflectedType == Object) return false; | 181 if (_isTop(m1)) return false; |
| 195 | 182 |
| 196 // Check if m1 and m2 have the same raw type. If so, check covariance on | 183 // Check if m1 and m2 have the same raw type. If so, check covariance on |
| 197 // type parameters. | 184 // type parameters. |
| 198 if (m1.originalDeclaration == m2.originalDeclaration) { | 185 if (m1.originalDeclaration == m2.originalDeclaration) { |
| 186 if (_isRawClass(m2)) return true; | |
| 187 if (_isRawClass(m1)) return false; | |
| 188 | |
| 199 final typeArguments1 = m1.typeArguments; | 189 final typeArguments1 = m1.typeArguments; |
| 200 final typeArguments2 = m2.typeArguments; | 190 final typeArguments2 = m2.typeArguments; |
| 201 final length = typeArguments1.length; | 191 final length = typeArguments1.length; |
| 202 if (typeArguments2.length == 0) { | 192 assert(typeArguments1.isNotEmpty && typeArguments2.isNotEmpty); |
| 203 // m2 is the raw form of m1 | |
| 204 return true; | |
| 205 } else if (typeArguments1.length == 0) { | |
| 206 // m1 is raw, but m2 is not | |
| 207 return false; | |
| 208 } | |
| 209 assert(typeArguments2.length == length); | 193 assert(typeArguments2.length == length); |
| 210 for (var i = 0; i < length; ++i) { | 194 for (var i = 0; i < length; ++i) { |
| 211 var typeArgument1 = typeArguments1[i]; | 195 var typeArgument1 = typeArguments1[i]; |
| 212 var typeArgument2 = typeArguments2[i]; | 196 var typeArgument2 = typeArguments2[i]; |
| 213 if (!_isSubType(typeArgument1, typeArgument2)) { | 197 if (!_isSubType(typeArgument1, typeArgument2)) { |
| 214 return false; | 198 return false; |
| 215 } | 199 } |
| 216 } | 200 } |
| 217 return true; | 201 return true; |
| 218 } | 202 } |
| 219 | 203 |
| 220 // Check superclass. | 204 // Check superclass. |
| 221 if (_isClassSubType(m1.superclass, m2)) return true; | 205 if (_isClassSubType(m1.superclass, m2)) return true; |
| 222 | 206 |
| 207 // Check for mixins. The mixin getter returns the original class if there is | |
| 208 // no mixin. | |
| 209 if (m1 != m1.mixin && _isClassSubType(m1.mixin, m2)) return true; | |
| 210 | |
| 223 // Check interfaces. | 211 // Check interfaces. |
| 224 for (final parent in m1.superinterfaces) { | 212 for (final parent in m1.superinterfaces) { |
| 225 if (_isClassSubType(parent, m2)) return true; | 213 if (_isClassSubType(parent, m2)) return true; |
| 226 } | 214 } |
| 227 | 215 |
| 228 return false; | 216 return false; |
| 229 } | 217 } |
| 230 | 218 |
| 219 final _dynamicMirror = reflectType(dynamic); | |
| 220 final _objectMirror = reflectType(Object); | |
| 221 final _nullMirror = reflectType(Null); | |
| 222 | |
| 223 bool _isBottom(TypeMirror t, {bool dynamicIsBottom: false}) { | |
| 224 if (t == _dynamicMirror && dynamicIsBottom) return true; | |
| 225 // TODO(vsm): We need direct support for non-nullability in DartType. | |
| 226 // This should check on "true/nonnullable" Bottom | |
| 227 if (t == _nullMirror && _typeOptions.nonnullableTypes.isEmpty) return true; | |
|
Jennifer Messerly
2015/04/01 19:12:46
is this check needed? Normally isSubtype does not
vsm
2015/04/01 21:04:04
Yes, I'd been treating Null as bottom (as in the s
| |
| 228 return false; | |
| 229 } | |
| 230 | |
| 231 bool _isTop(TypeMirror t, {bool dynamicIsBottom: false}) { | |
| 232 if (t == _dynamicMirror && !dynamicIsBottom) return true; | |
| 233 if (t == _objectMirror) return true; | |
| 234 return false; | |
| 235 } | |
| 236 | |
| 237 bool _isGroundTypeMirror(TypeMirror mirror) { | |
| 238 // Disallow generic type parameters. | |
| 239 if (mirror is TypeVariableMirror) return false; | |
|
Jennifer Messerly
2015/04/01 19:12:46
Does this happen at runtime?
$ cat test.dart
impo
vsm
2015/04/01 21:04:04
I think you are right. Changed this to an assert.
| |
| 240 | |
| 241 // Allow only 'raw' functions. | |
| 242 if (mirror is TypedefMirror) { | |
| 243 return _isRawFunction(mirror.referent); | |
| 244 } | |
| 245 if (mirror is FunctionTypeMirror) { | |
| 246 return _isRawFunction(mirror); | |
| 247 } | |
| 248 | |
| 249 // Allow only 'raw' classes. | |
| 250 if (mirror is ClassMirror) { | |
| 251 return _isRawClass(mirror); | |
| 252 } | |
| 253 | |
| 254 // Only dynamic should be left. Should this be allowed? | |
| 255 // It's not particularly useful. | |
| 256 assert(mirror.reflectedType == dynamic); | |
| 257 return true; | |
| 258 } | |
| 259 | |
| 260 bool _isRawFunction(FunctionTypeMirror mirror) { | |
| 261 var returnType = mirror.returnType; | |
| 262 if (!_isTop(returnType)) return false; | |
| 263 for (var parameter in mirror.parameters) { | |
| 264 var paramType = parameter.type; | |
| 265 if (!_isBottom(paramType, dynamicIsBottom: true)) return false; | |
| 266 } | |
| 267 return true; | |
| 268 } | |
| 269 | |
| 231 bool _isRawClass(ClassMirror mirror) { | 270 bool _isRawClass(ClassMirror mirror) { |
| 232 // Allow only raw types. | 271 // Allow only raw types. |
| 233 if (mirror == mirror.originalDeclaration) return true; | 272 if (mirror == mirror.originalDeclaration) return true; |
| 234 final dynamicMirror = reflectType(dynamic); | |
| 235 for (var typeArgument in mirror.typeArguments) { | 273 for (var typeArgument in mirror.typeArguments) { |
| 236 if (typeArgument != dynamicMirror) return false; | 274 if (!_isTop(typeArgument)) return false; |
| 237 } | 275 } |
| 238 return true; | 276 return true; |
| 239 } | 277 } |
| 240 | 278 |
| 241 TypeMirror _canonicalizeTypeMirror(TypeMirror t) { | 279 TypeMirror _canonicalizeTypeMirror(TypeMirror t) { |
| 242 if (t is TypedefMirror) { | 280 if (t is TypedefMirror) { |
| 243 // We canonicalize Typedefs to their underlying function types. | 281 // We canonicalize Typedefs to their underlying function types. |
| 244 t = (t as TypedefMirror).referent; | 282 t = (t as TypedefMirror).referent; |
| 245 } | 283 } |
| 246 if (t is ClassMirror && _isRawClass(t)) { | 284 if (t is ClassMirror && _isRawClass(t)) { |
| 247 // We canonicalize T<dynamic> to T. | 285 // We canonicalize T<dynamic> to T. |
| 248 t = t.originalDeclaration; | 286 t = t.originalDeclaration; |
| 249 } | 287 } |
| 250 return t; | 288 return t; |
| 251 } | 289 } |
| 252 | 290 |
| 253 bool _reflects(TypeMirror mirror, Type t) { | 291 bool _reflects(TypeMirror mirror, Type t) { |
| 254 return mirror.hasReflectedType && mirror.reflectedType == t; | 292 return mirror.hasReflectedType && mirror.reflectedType == t; |
| 255 } | 293 } |
| 256 | 294 |
| 257 bool _isSubType(TypeMirror t1, TypeMirror t2) { | 295 bool _isSubType(TypeMirror t1, TypeMirror t2, {bool dynamicIsBottom: false}) { |
| 258 t1 = _canonicalizeTypeMirror(t1); | 296 t1 = _canonicalizeTypeMirror(t1); |
| 259 t2 = _canonicalizeTypeMirror(t2); | 297 t2 = _canonicalizeTypeMirror(t2); |
| 260 | 298 |
| 299 if (t1 is TypeVariableMirror) { | |
|
Jennifer Messerly
2015/04/01 19:12:46
similar question about TypeVariableMirror, do we a
vsm
2015/04/01 21:04:04
I actually did hit this, in part because of how we
| |
| 300 t1 = t1.upperBound; | |
| 301 } | |
| 302 | |
| 303 if (t2 is TypeVariableMirror) { | |
| 304 // TODO(vsm): Bottom? | |
| 305 t2 = _nullMirror; | |
| 306 } | |
| 307 | |
| 261 if (t1 == t2) return true; | 308 if (t1 == t2) return true; |
| 262 | 309 |
| 263 // In Dart, dynamic is effectively both top and bottom. | 310 // Trivially true. |
| 264 // Here, we treat dynamic as top - the base type of everything. | 311 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
| 265 if (_reflects(t1, dynamic)) return false; | 312 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
| 266 if (_reflects(t2, dynamic)) return true; | 313 return true; |
| 314 } | |
| 267 | 315 |
| 268 // Object only subtypes dynamic and Object. | 316 // Trivially false. |
| 269 if (_reflects(t2, Object)) return true; | 317 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
| 270 if (_reflects(t1, Object)) return false; | 318 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
| 319 return false; | |
| 320 } | |
| 321 | |
| 322 // The null type is a subtype of any nonnullable type. | |
| 323 if (t1 == _nullMirror) { | |
| 324 // Return false iff t2 *may* be a primitive type. | |
| 325 return !isPrimitiveType(t2); | |
| 326 } | |
| 271 | 327 |
| 272 // "Traditional" name-based subtype check. | 328 // "Traditional" name-based subtype check. |
| 273 final c1 = t1 as ClassMirror; | 329 final c1 = t1 as ClassMirror; |
| 274 final c2 = t2 as ClassMirror; | 330 final c2 = t2 as ClassMirror; |
| 275 if (_isClassSubType(c1, c2)) { | 331 if (_isClassSubType(c1, c2)) { |
| 276 return true; | 332 return true; |
| 277 } | 333 } |
| 278 | 334 |
| 279 // Function subtyping. | 335 // Function subtyping. |
| 280 // Note: it appears under the hood all Dart functions map to a class / hidden type | 336 // Note: it appears under the hood all Dart functions map to a class / hidden type |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 ret1 = call1.returnType; | 371 ret1 = call1.returnType; |
| 316 params1 = call1.parameters; | 372 params1 = call1.parameters; |
| 317 } | 373 } |
| 318 | 374 |
| 319 // Any type that implements a call method implicitly subtypes Function. | 375 // Any type that implements a call method implicitly subtypes Function. |
| 320 if (_reflects(c2, Function)) return true; | 376 if (_reflects(c2, Function)) return true; |
| 321 | 377 |
| 322 // Check structural function subtyping | 378 // Check structural function subtyping |
| 323 return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); | 379 return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); |
| 324 } | 380 } |
| OLD | NEW |