| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 } else { | 45 } else { |
| 46 // For non-null values, val is T => val as T succeeds. | 46 // For non-null values, val is T => val as T succeeds. |
| 47 if (instanceOf(obj, staticType)) return obj; | 47 if (instanceOf(obj, staticType)) return obj; |
| 48 } | 48 } |
| 49 // TODO(vsm): Add message. | 49 // TODO(vsm): Add message. |
| 50 throw new CastError(); | 50 throw new CastError(); |
| 51 } | 51 } |
| 52 | 52 |
| 53 bool instanceOf(dynamic obj, Type staticType) { | 53 bool instanceOf(dynamic obj, Type staticType) { |
| 54 // This is our 'is' equivalent. | 54 // This is our 'is' equivalent. |
| 55 if (obj == null) { | |
| 56 // Only true for the Object type. | |
| 57 return staticType == Object || staticType == dynamic || staticType == Null; | |
| 58 } | |
| 59 | |
| 60 Type runtimeType = obj.runtimeType; | 55 Type runtimeType = obj.runtimeType; |
| 61 return _isSubType(reflectType(runtimeType), reflectType(staticType)); | 56 return _isSubType(reflectType(runtimeType), reflectType(staticType)); |
| 62 } | 57 } |
| 63 | 58 |
| 64 bool isGroundType(Type type) { | 59 bool isGroundType(Type type) { |
| 65 // These are types allow in is / as expressions. | 60 // These are types allowed in is / as expressions. |
| 66 final mirror = reflectType(type); | 61 final mirror = reflectType(type); |
| 67 // Disallow functions. | 62 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 } | 63 } |
| 82 | 64 |
| 83 final _primitiveMap = { | 65 final _primitiveMap = { |
| 84 'int': int, | 66 'int': int, |
| 85 'double': double, | 67 'double': double, |
| 86 'num': num, | 68 'num': num, |
| 87 'bool': bool, | 69 'bool': bool, |
| 88 'String': String, | 70 'String': String, |
| 89 }; | 71 }; |
| 90 | 72 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 | 126 |
| 145 if (params1.length < params2.length) { | 127 if (params1.length < params2.length) { |
| 146 return false; | 128 return false; |
| 147 } | 129 } |
| 148 | 130 |
| 149 for (int i = 0; i < params2.length; ++i) { | 131 for (int i = 0; i < params2.length; ++i) { |
| 150 ParameterMirror p1 = params1[i]; | 132 ParameterMirror p1 = params1[i]; |
| 151 ParameterMirror p2 = params2[i]; | 133 ParameterMirror p2 = params2[i]; |
| 152 | 134 |
| 153 // Contravariant parameter types. | 135 // Contravariant parameter types. |
| 154 if (!_isSubType(p2.type, p1.type)) { | 136 if (!_isSubType(p2.type, p1.type, dynamicIsBottom: true)) { |
| 155 return false; | 137 return false; |
| 156 } | 138 } |
| 157 | 139 |
| 158 // Optional parameters. | 140 // Optional parameters. |
| 159 if (p2.isOptional) { | 141 if (p2.isOptional) { |
| 160 // If the base param is optional, the sub param must be optional: | 142 // If the base param is optional, the sub param must be optional: |
| 161 if (!p1.isOptional) return false; | 143 if (!p1.isOptional) return false; |
| 162 if (!p2.isNamed) { | 144 if (!p2.isNamed) { |
| 163 // either neither are named or | 145 // either neither are named or |
| 164 if (p1.isNamed) return false; | 146 if (p1.isNamed) return false; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 184 bool _isClassSubType(ClassMirror m1, ClassMirror m2) { | 166 bool _isClassSubType(ClassMirror m1, ClassMirror m2) { |
| 185 // TODO(vsm): Consider some caching for efficiency here. | 167 // TODO(vsm): Consider some caching for efficiency here. |
| 186 | 168 |
| 187 // We support Dart's covariant generics with the caveat that we do not | 169 // We support Dart's covariant generics with the caveat that we do not |
| 188 // substitute bottom for dynamic in subtyping rules. | 170 // substitute bottom for dynamic in subtyping rules. |
| 189 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: | 171 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: |
| 190 // - S !<: S<T1, ..., Tn> | 172 // - S !<: S<T1, ..., Tn> |
| 191 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> | 173 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> |
| 192 if (m1 == m2) return true; | 174 if (m1 == m2) return true; |
| 193 | 175 |
| 194 if (m1.hasReflectedType && m1.reflectedType == Object) return false; | 176 if (_isTop(m1)) return false; |
| 195 | 177 |
| 196 // Check if m1 and m2 have the same raw type. If so, check covariance on | 178 // Check if m1 and m2 have the same raw type. If so, check covariance on |
| 197 // type parameters. | 179 // type parameters. |
| 198 if (m1.originalDeclaration == m2.originalDeclaration) { | 180 if (m1.originalDeclaration == m2.originalDeclaration) { |
| 181 if (_isRawClass(m2)) return true; |
| 182 if (_isRawClass(m1)) return false; |
| 183 |
| 199 final typeArguments1 = m1.typeArguments; | 184 final typeArguments1 = m1.typeArguments; |
| 200 final typeArguments2 = m2.typeArguments; | 185 final typeArguments2 = m2.typeArguments; |
| 201 final length = typeArguments1.length; | 186 final length = typeArguments1.length; |
| 202 if (typeArguments2.length == 0) { | 187 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); | 188 assert(typeArguments2.length == length); |
| 210 for (var i = 0; i < length; ++i) { | 189 for (var i = 0; i < length; ++i) { |
| 211 var typeArgument1 = typeArguments1[i]; | 190 var typeArgument1 = typeArguments1[i]; |
| 212 var typeArgument2 = typeArguments2[i]; | 191 var typeArgument2 = typeArguments2[i]; |
| 213 if (!_isSubType(typeArgument1, typeArgument2)) { | 192 if (!_isSubType(typeArgument1, typeArgument2)) { |
| 214 return false; | 193 return false; |
| 215 } | 194 } |
| 216 } | 195 } |
| 217 return true; | 196 return true; |
| 218 } | 197 } |
| 219 | 198 |
| 220 // Check superclass. | 199 // Check superclass. |
| 221 if (_isClassSubType(m1.superclass, m2)) return true; | 200 if (_isClassSubType(m1.superclass, m2)) return true; |
| 222 | 201 |
| 202 // Check for mixins. The mixin getter returns the original class if there is |
| 203 // no mixin. |
| 204 if (m1 != m1.mixin && _isClassSubType(m1.mixin, m2)) return true; |
| 205 |
| 223 // Check interfaces. | 206 // Check interfaces. |
| 224 for (final parent in m1.superinterfaces) { | 207 for (final parent in m1.superinterfaces) { |
| 225 if (_isClassSubType(parent, m2)) return true; | 208 if (_isClassSubType(parent, m2)) return true; |
| 226 } | 209 } |
| 227 | 210 |
| 228 return false; | 211 return false; |
| 229 } | 212 } |
| 230 | 213 |
| 214 final _dynamicMirror = reflectType(dynamic); |
| 215 final _objectMirror = reflectType(Object); |
| 216 |
| 217 bool _isBottom(TypeMirror t, {bool dynamicIsBottom: false}) { |
| 218 if (t == _dynamicMirror && dynamicIsBottom) return true; |
| 219 // TODO(vsm): Do we need an explicit representation of Bottom? |
| 220 return false; |
| 221 } |
| 222 |
| 223 bool _isTop(TypeMirror t, {bool dynamicIsBottom: false}) { |
| 224 if (t == _dynamicMirror && !dynamicIsBottom) return true; |
| 225 if (t == _objectMirror) return true; |
| 226 return false; |
| 227 } |
| 228 |
| 229 bool _isGroundTypeMirror(TypeMirror mirror) { |
| 230 // This is a runtime type - we should not see type parameters here. |
| 231 assert(mirror is! TypeVariableMirror); |
| 232 |
| 233 // Allow only 'raw' functions. |
| 234 if (mirror is TypedefMirror) { |
| 235 return _isRawFunction(mirror.referent); |
| 236 } |
| 237 if (mirror is FunctionTypeMirror) { |
| 238 return _isRawFunction(mirror); |
| 239 } |
| 240 |
| 241 // Allow only 'raw' classes. |
| 242 if (mirror is ClassMirror) { |
| 243 return _isRawClass(mirror); |
| 244 } |
| 245 |
| 246 // Only dynamic should be left. Should this be allowed? |
| 247 // It's not particularly useful. |
| 248 assert(mirror.reflectedType == dynamic); |
| 249 return true; |
| 250 } |
| 251 |
| 252 bool _isRawFunction(FunctionTypeMirror mirror) { |
| 253 var returnType = mirror.returnType; |
| 254 if (!_isTop(returnType)) return false; |
| 255 for (var parameter in mirror.parameters) { |
| 256 var paramType = parameter.type; |
| 257 if (!_isBottom(paramType, dynamicIsBottom: true)) return false; |
| 258 } |
| 259 return true; |
| 260 } |
| 261 |
| 231 bool _isRawClass(ClassMirror mirror) { | 262 bool _isRawClass(ClassMirror mirror) { |
| 232 // Allow only raw types. | 263 // Allow only raw types. |
| 233 if (mirror == mirror.originalDeclaration) return true; | 264 if (mirror == mirror.originalDeclaration) return true; |
| 234 final dynamicMirror = reflectType(dynamic); | |
| 235 for (var typeArgument in mirror.typeArguments) { | 265 for (var typeArgument in mirror.typeArguments) { |
| 236 if (typeArgument != dynamicMirror) return false; | 266 if (!_isTop(typeArgument)) return false; |
| 237 } | 267 } |
| 238 return true; | 268 return true; |
| 239 } | 269 } |
| 240 | 270 |
| 241 TypeMirror _canonicalizeTypeMirror(TypeMirror t) { | 271 TypeMirror _canonicalizeTypeMirror(TypeMirror t) { |
| 242 if (t is TypedefMirror) { | 272 if (t is TypedefMirror) { |
| 243 // We canonicalize Typedefs to their underlying function types. | 273 // We canonicalize Typedefs to their underlying function types. |
| 244 t = (t as TypedefMirror).referent; | 274 t = (t as TypedefMirror).referent; |
| 245 } | 275 } |
| 246 if (t is ClassMirror && _isRawClass(t)) { | 276 if (t is ClassMirror && _isRawClass(t)) { |
| 247 // We canonicalize T<dynamic> to T. | 277 // We canonicalize T<dynamic> to T. |
| 248 t = t.originalDeclaration; | 278 t = t.originalDeclaration; |
| 249 } | 279 } |
| 250 return t; | 280 return t; |
| 251 } | 281 } |
| 252 | 282 |
| 253 bool _reflects(TypeMirror mirror, Type t) { | 283 bool _reflects(TypeMirror mirror, Type t) { |
| 254 return mirror.hasReflectedType && mirror.reflectedType == t; | 284 return mirror.hasReflectedType && mirror.reflectedType == t; |
| 255 } | 285 } |
| 256 | 286 |
| 257 bool _isSubType(TypeMirror t1, TypeMirror t2) { | 287 bool _isSubType(TypeMirror t1, TypeMirror t2, {bool dynamicIsBottom: false}) { |
| 258 t1 = _canonicalizeTypeMirror(t1); | 288 t1 = _canonicalizeTypeMirror(t1); |
| 259 t2 = _canonicalizeTypeMirror(t2); | 289 t2 = _canonicalizeTypeMirror(t2); |
| 260 | 290 |
| 291 if (t1 is TypeVariableMirror) { |
| 292 t1 = t1.upperBound; |
| 293 } |
| 294 |
| 261 if (t1 == t2) return true; | 295 if (t1 == t2) return true; |
| 262 | 296 |
| 263 // In Dart, dynamic is effectively both top and bottom. | 297 // Trivially true. |
| 264 // Here, we treat dynamic as top - the base type of everything. | 298 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
| 265 if (_reflects(t1, dynamic)) return false; | 299 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
| 266 if (_reflects(t2, dynamic)) return true; | 300 return true; |
| 301 } |
| 267 | 302 |
| 268 // Object only subtypes dynamic and Object. | 303 // Trivially false. |
| 269 if (_reflects(t2, Object)) return true; | 304 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
| 270 if (_reflects(t1, Object)) return false; | 305 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
| 306 return false; |
| 307 } |
| 271 | 308 |
| 272 // "Traditional" name-based subtype check. | 309 // "Traditional" name-based subtype check. |
| 273 final c1 = t1 as ClassMirror; | 310 final c1 = t1 as ClassMirror; |
| 274 final c2 = t2 as ClassMirror; | 311 final c2 = t2 as ClassMirror; |
| 275 if (_isClassSubType(c1, c2)) { | 312 if (_isClassSubType(c1, c2)) { |
| 276 return true; | 313 return true; |
| 277 } | 314 } |
| 278 | 315 |
| 279 // Function subtyping. | 316 // Function subtyping. |
| 280 // Note: it appears under the hood all Dart functions map to a class / hidden
type | 317 // 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; | 352 ret1 = call1.returnType; |
| 316 params1 = call1.parameters; | 353 params1 = call1.parameters; |
| 317 } | 354 } |
| 318 | 355 |
| 319 // Any type that implements a call method implicitly subtypes Function. | 356 // Any type that implements a call method implicitly subtypes Function. |
| 320 if (_reflects(c2, Function)) return true; | 357 if (_reflects(c2, Function)) return true; |
| 321 | 358 |
| 322 // Check structural function subtyping | 359 // Check structural function subtyping |
| 323 return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); | 360 return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); |
| 324 } | 361 } |
| OLD | NEW |