| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dev_compiler.runtime.dart_runtime; | |
| 6 | |
| 7 import 'dart:mirrors'; | |
| 8 | |
| 9 import 'package:dev_compiler/config.dart'; | |
| 10 | |
| 11 dynamic dload(dynamic obj, String field) { | |
| 12 var symbol = new Symbol(field); | |
| 13 var mirror = reflect(obj); | |
| 14 // TODO(vsm): Does this create an NSM? | |
| 15 var fieldMirror = mirror.getField(symbol); | |
| 16 return fieldMirror.reflectee; | |
| 17 } | |
| 18 | |
| 19 dynamic dinvokef(dynamic f, List args) { | |
| 20 // TODO(vsm): Support named arguments. | |
| 21 assert(f is Function); | |
| 22 return Function.apply(f, args); | |
| 23 } | |
| 24 | |
| 25 // A workaround to manufacture a generic Type object inline. | |
| 26 // We use mirrors to extract type T given a TypeFunction<T>. | |
| 27 // E.g., Map<String, String> is not a valid literal in Dart. | |
| 28 // Instead, use: type((Map<String, String> _) {}); | |
| 29 // See bug: https://code.google.com/p/dart/issues/detail?id=11923 | |
| 30 typedef TypeFunction<T>(T x); | |
| 31 | |
| 32 Type type(TypeFunction f) { | |
| 33 ClosureMirror cm = reflect(f); | |
| 34 MethodMirror mm = cm.function; | |
| 35 ParameterMirror pm = mm.parameters[0]; | |
| 36 TypeMirror tm = pm.type; | |
| 37 return tm.reflectedType; | |
| 38 } | |
| 39 | |
| 40 dynamic cast(dynamic obj, Type staticType) { | |
| 41 // This is our 'as' equivalent. | |
| 42 if (obj == null) { | |
| 43 // A null can be cast only to non-primitive types. | |
| 44 if (!isPrimitiveType(staticType)) return null; | |
| 45 } else { | |
| 46 // For non-null values, val is T => val as T succeeds. | |
| 47 if (instanceOf(obj, staticType)) return obj; | |
| 48 } | |
| 49 // TODO(vsm): Add message. | |
| 50 throw new CastError(); | |
| 51 } | |
| 52 | |
| 53 bool instanceOf(dynamic obj, Type staticType) { | |
| 54 // This is our 'is' equivalent. | |
| 55 Type runtimeType = obj.runtimeType; | |
| 56 return _isSubType(reflectType(runtimeType), reflectType(staticType)); | |
| 57 } | |
| 58 | |
| 59 bool isGroundType(Type type) { | |
| 60 // These are types allowed in is / as expressions. | |
| 61 final mirror = reflectType(type); | |
| 62 return _isGroundTypeMirror(mirror); | |
| 63 } | |
| 64 | |
| 65 final _primitiveMap = { | |
| 66 'int': int, | |
| 67 'double': double, | |
| 68 'num': num, | |
| 69 'bool': bool, | |
| 70 'String': String, | |
| 71 }; | |
| 72 | |
| 73 // TODO(vsm): Make this configurable? Using default settings for now. | |
| 74 final _typeOptions = new TypeOptions(); | |
| 75 | |
| 76 Set<Type> _primitives = () { | |
| 77 var types = _typeOptions.nonnullableTypes; | |
| 78 var set = new Set<Type>.from(types.map((t) => _primitiveMap[t])); | |
| 79 return set; | |
| 80 }(); | |
| 81 | |
| 82 bool isPrimitiveType(Type t) { | |
| 83 return _primitives.contains(t); | |
| 84 } | |
| 85 | |
| 86 class Arity { | |
| 87 final int normal; | |
| 88 final int optionalPositional; | |
| 89 | |
| 90 Arity._internal(this.normal, this.optionalPositional); | |
| 91 | |
| 92 int get min => normal; | |
| 93 int get max => normal + optionalPositional; | |
| 94 } | |
| 95 | |
| 96 Arity getArity(Function f) { | |
| 97 final FunctionTypeMirror mirror = reflectType(f.runtimeType); | |
| 98 final parameters = mirror.parameters; | |
| 99 int normal = 0; | |
| 100 int optionalPositional = 0; | |
| 101 for (var parameter in parameters) { | |
| 102 if (parameter.isNamed) { | |
| 103 // Ignore named parameters - these cannot be passed positionally. | |
| 104 } else if (parameter.isOptional) { | |
| 105 optionalPositional++; | |
| 106 } else { | |
| 107 normal++; | |
| 108 } | |
| 109 } | |
| 110 return new Arity._internal(normal, optionalPositional); | |
| 111 } | |
| 112 | |
| 113 bool _isFunctionSubType(TypeMirror ret1, List<ParameterMirror> params1, | |
| 114 TypeMirror ret2, List<ParameterMirror> params2) { | |
| 115 if (!_isSubType(ret1, ret2)) { | |
| 116 // Covariant return types | |
| 117 // Note, void (which can only appear as a return type) is effectively | |
| 118 // treated as dynamic. If the base return type is void, we allow any | |
| 119 // subtype return type. | |
| 120 // E.g., we allow: | |
| 121 // () -> int <: () -> void | |
| 122 if (ret2.simpleName != const Symbol('void')) { | |
| 123 return false; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 if (params1.length < params2.length) { | |
| 128 return false; | |
| 129 } | |
| 130 | |
| 131 for (int i = 0; i < params2.length; ++i) { | |
| 132 ParameterMirror p1 = params1[i]; | |
| 133 ParameterMirror p2 = params2[i]; | |
| 134 | |
| 135 // Contravariant parameter types. | |
| 136 if (!_isSubType(p2.type, p1.type, dynamicIsBottom: true)) { | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 // Optional parameters. | |
| 141 if (p2.isOptional) { | |
| 142 // If the base param is optional, the sub param must be optional: | |
| 143 if (!p1.isOptional) return false; | |
| 144 if (!p2.isNamed) { | |
| 145 // either neither are named or | |
| 146 if (p1.isNamed) return false; | |
| 147 } else { | |
| 148 // both are named with the same name | |
| 149 if (!p1.isNamed || p1.simpleName != p2.simpleName) return false; | |
| 150 } | |
| 151 } else { | |
| 152 // If the base param is required, the sub may be optional, but not named. | |
| 153 if (p1.isNamed) return false; | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 for (int i = params2.length; i < params1.length; ++i) { | |
| 158 ParameterMirror p1 = params1[i]; | |
| 159 // Any additional sub params must be optional. | |
| 160 if (!p1.isOptional) return false; | |
| 161 } | |
| 162 | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 bool _isClassSubType(ClassMirror m1, ClassMirror m2) { | |
| 167 // TODO(vsm): Consider some caching for efficiency here. | |
| 168 | |
| 169 // We support Dart's covariant generics with the caveat that we do not | |
| 170 // substitute bottom for dynamic in subtyping rules. | |
| 171 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: | |
| 172 // - S !<: S<T1, ..., Tn> | |
| 173 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> | |
| 174 if (m1 == m2) return true; | |
| 175 | |
| 176 if (_isTop(m1)) return false; | |
| 177 | |
| 178 // Check if m1 and m2 have the same raw type. If so, check covariance on | |
| 179 // type parameters. | |
| 180 if (m1.originalDeclaration == m2.originalDeclaration) { | |
| 181 if (_isRawClass(m2)) return true; | |
| 182 if (_isRawClass(m1)) return false; | |
| 183 | |
| 184 final typeArguments1 = m1.typeArguments; | |
| 185 final typeArguments2 = m2.typeArguments; | |
| 186 final length = typeArguments1.length; | |
| 187 assert(typeArguments1.isNotEmpty && typeArguments2.isNotEmpty); | |
| 188 assert(typeArguments2.length == length); | |
| 189 for (var i = 0; i < length; ++i) { | |
| 190 var typeArgument1 = typeArguments1[i]; | |
| 191 var typeArgument2 = typeArguments2[i]; | |
| 192 if (!_isSubType(typeArgument1, typeArgument2)) { | |
| 193 return false; | |
| 194 } | |
| 195 } | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 // Check superclass. | |
| 200 if (_isClassSubType(m1.superclass, m2)) return true; | |
| 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 | |
| 206 // Check interfaces. | |
| 207 for (final parent in m1.superinterfaces) { | |
| 208 if (_isClassSubType(parent, m2)) return true; | |
| 209 } | |
| 210 | |
| 211 return false; | |
| 212 } | |
| 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 | |
| 262 bool _isRawClass(ClassMirror mirror) { | |
| 263 // Allow only raw types. | |
| 264 if (mirror == mirror.originalDeclaration) return true; | |
| 265 for (var typeArgument in mirror.typeArguments) { | |
| 266 if (!_isTop(typeArgument)) return false; | |
| 267 } | |
| 268 return true; | |
| 269 } | |
| 270 | |
| 271 TypeMirror _canonicalizeTypeMirror(TypeMirror t) { | |
| 272 if (t is TypedefMirror) { | |
| 273 // We canonicalize Typedefs to their underlying function types. | |
| 274 t = (t as TypedefMirror).referent; | |
| 275 } | |
| 276 if (t is ClassMirror && _isRawClass(t)) { | |
| 277 // We canonicalize T<dynamic> to T. | |
| 278 t = t.originalDeclaration; | |
| 279 } | |
| 280 return t; | |
| 281 } | |
| 282 | |
| 283 bool _reflects(TypeMirror mirror, Type t) { | |
| 284 return mirror.hasReflectedType && mirror.reflectedType == t; | |
| 285 } | |
| 286 | |
| 287 bool _isSubType(TypeMirror t1, TypeMirror t2, {bool dynamicIsBottom: false}) { | |
| 288 t1 = _canonicalizeTypeMirror(t1); | |
| 289 t2 = _canonicalizeTypeMirror(t2); | |
| 290 | |
| 291 if (t1 is TypeVariableMirror) { | |
| 292 t1 = t1.upperBound; | |
| 293 } | |
| 294 | |
| 295 if (t1 == t2) return true; | |
| 296 | |
| 297 // Trivially true. | |
| 298 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | |
| 299 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | |
| 300 return true; | |
| 301 } | |
| 302 | |
| 303 // Trivially false. | |
| 304 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | |
| 305 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | |
| 306 return false; | |
| 307 } | |
| 308 | |
| 309 // "Traditional" name-based subtype check. | |
| 310 final c1 = t1 as ClassMirror; | |
| 311 final c2 = t2 as ClassMirror; | |
| 312 if (_isClassSubType(c1, c2)) { | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 // Function subtyping. | |
| 317 // Note: it appears under the hood all Dart functions map to a class / hidden
type | |
| 318 // that: | |
| 319 // (a) subtypes Object (an internal _FunctionImpl in the VM) | |
| 320 // (b) implements Function | |
| 321 // (c) provides standard Object members (hashCode, toString) | |
| 322 // (d) contains private members (corresponding to _FunctionImpl?) | |
| 323 // (e) provides a call method to handle the actual function invocation | |
| 324 // | |
| 325 // The standard Dart subtyping rules are structural in nature. I.e., | |
| 326 // bivariant on arguments and return type. | |
| 327 // | |
| 328 // The below tries for a more traditional subtyping rule: | |
| 329 // - covariant on return type | |
| 330 // - contravariant on parameters | |
| 331 // - 'sensible' (?) rules on optional and/or named params | |
| 332 // but doesn't properly mix with class subtyping yet. | |
| 333 // | |
| 334 // Note, a class type that implements a call method implicitly subtypes | |
| 335 // the function type of the call method. However, the converse is not true: | |
| 336 // a function type does not subtype a class type with a call method. | |
| 337 | |
| 338 // If c1 is not a proper function or a class type with call method, | |
| 339 // return false. | |
| 340 TypeMirror ret1; | |
| 341 List<ParameterMirror> params1; | |
| 342 // Note, a proper function has a call method, but it's not a regular method, | |
| 343 // so we break out the two cases. | |
| 344 if (c1 is FunctionTypeMirror) { | |
| 345 // Regular function | |
| 346 ret1 = c1.returnType; | |
| 347 params1 = c1.parameters; | |
| 348 } else { | |
| 349 var call1 = c1.instanceMembers[#call]; | |
| 350 if (call1 == null || !call1.isRegularMethod) return false; | |
| 351 // Class that emulate a function | |
| 352 ret1 = call1.returnType; | |
| 353 params1 = call1.parameters; | |
| 354 } | |
| 355 | |
| 356 // Any type that implements a call method implicitly subtypes Function. | |
| 357 if (_reflects(c2, Function)) return true; | |
| 358 | |
| 359 // Check structural function subtyping | |
| 360 return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); | |
| 361 } | |
| OLD | NEW |