Index: lib/runtime/dart_runtime.dart |
diff --git a/lib/runtime/dart_runtime.dart b/lib/runtime/dart_runtime.dart |
deleted file mode 100644 |
index 799aad22640142ec4844141a0549b5837df01304..0000000000000000000000000000000000000000 |
--- a/lib/runtime/dart_runtime.dart |
+++ /dev/null |
@@ -1,361 +0,0 @@ |
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library dev_compiler.runtime.dart_runtime; |
- |
-import 'dart:mirrors'; |
- |
-import 'package:dev_compiler/config.dart'; |
- |
-dynamic dload(dynamic obj, String field) { |
- var symbol = new Symbol(field); |
- var mirror = reflect(obj); |
- // TODO(vsm): Does this create an NSM? |
- var fieldMirror = mirror.getField(symbol); |
- return fieldMirror.reflectee; |
-} |
- |
-dynamic dinvokef(dynamic f, List args) { |
- // TODO(vsm): Support named arguments. |
- assert(f is Function); |
- return Function.apply(f, args); |
-} |
- |
-// A workaround to manufacture a generic Type object inline. |
-// We use mirrors to extract type T given a TypeFunction<T>. |
-// E.g., Map<String, String> is not a valid literal in Dart. |
-// Instead, use: type((Map<String, String> _) {}); |
-// See bug: https://code.google.com/p/dart/issues/detail?id=11923 |
-typedef TypeFunction<T>(T x); |
- |
-Type type(TypeFunction f) { |
- ClosureMirror cm = reflect(f); |
- MethodMirror mm = cm.function; |
- ParameterMirror pm = mm.parameters[0]; |
- TypeMirror tm = pm.type; |
- return tm.reflectedType; |
-} |
- |
-dynamic cast(dynamic obj, Type staticType) { |
- // This is our 'as' equivalent. |
- if (obj == null) { |
- // A null can be cast only to non-primitive types. |
- if (!isPrimitiveType(staticType)) return null; |
- } else { |
- // For non-null values, val is T => val as T succeeds. |
- if (instanceOf(obj, staticType)) return obj; |
- } |
- // TODO(vsm): Add message. |
- throw new CastError(); |
-} |
- |
-bool instanceOf(dynamic obj, Type staticType) { |
- // This is our 'is' equivalent. |
- Type runtimeType = obj.runtimeType; |
- return _isSubType(reflectType(runtimeType), reflectType(staticType)); |
-} |
- |
-bool isGroundType(Type type) { |
- // These are types allowed in is / as expressions. |
- final mirror = reflectType(type); |
- return _isGroundTypeMirror(mirror); |
-} |
- |
-final _primitiveMap = { |
- 'int': int, |
- 'double': double, |
- 'num': num, |
- 'bool': bool, |
- 'String': String, |
-}; |
- |
-// TODO(vsm): Make this configurable? Using default settings for now. |
-final _typeOptions = new TypeOptions(); |
- |
-Set<Type> _primitives = () { |
- var types = _typeOptions.nonnullableTypes; |
- var set = new Set<Type>.from(types.map((t) => _primitiveMap[t])); |
- return set; |
-}(); |
- |
-bool isPrimitiveType(Type t) { |
- return _primitives.contains(t); |
-} |
- |
-class Arity { |
- final int normal; |
- final int optionalPositional; |
- |
- Arity._internal(this.normal, this.optionalPositional); |
- |
- int get min => normal; |
- int get max => normal + optionalPositional; |
-} |
- |
-Arity getArity(Function f) { |
- final FunctionTypeMirror mirror = reflectType(f.runtimeType); |
- final parameters = mirror.parameters; |
- int normal = 0; |
- int optionalPositional = 0; |
- for (var parameter in parameters) { |
- if (parameter.isNamed) { |
- // Ignore named parameters - these cannot be passed positionally. |
- } else if (parameter.isOptional) { |
- optionalPositional++; |
- } else { |
- normal++; |
- } |
- } |
- return new Arity._internal(normal, optionalPositional); |
-} |
- |
-bool _isFunctionSubType(TypeMirror ret1, List<ParameterMirror> params1, |
- TypeMirror ret2, List<ParameterMirror> params2) { |
- if (!_isSubType(ret1, ret2)) { |
- // Covariant return types |
- // Note, void (which can only appear as a return type) is effectively |
- // treated as dynamic. If the base return type is void, we allow any |
- // subtype return type. |
- // E.g., we allow: |
- // () -> int <: () -> void |
- if (ret2.simpleName != const Symbol('void')) { |
- return false; |
- } |
- } |
- |
- if (params1.length < params2.length) { |
- return false; |
- } |
- |
- for (int i = 0; i < params2.length; ++i) { |
- ParameterMirror p1 = params1[i]; |
- ParameterMirror p2 = params2[i]; |
- |
- // Contravariant parameter types. |
- if (!_isSubType(p2.type, p1.type, dynamicIsBottom: true)) { |
- return false; |
- } |
- |
- // Optional parameters. |
- if (p2.isOptional) { |
- // If the base param is optional, the sub param must be optional: |
- if (!p1.isOptional) return false; |
- if (!p2.isNamed) { |
- // either neither are named or |
- if (p1.isNamed) return false; |
- } else { |
- // both are named with the same name |
- if (!p1.isNamed || p1.simpleName != p2.simpleName) return false; |
- } |
- } else { |
- // If the base param is required, the sub may be optional, but not named. |
- if (p1.isNamed) return false; |
- } |
- } |
- |
- for (int i = params2.length; i < params1.length; ++i) { |
- ParameterMirror p1 = params1[i]; |
- // Any additional sub params must be optional. |
- if (!p1.isOptional) return false; |
- } |
- |
- return true; |
-} |
- |
-bool _isClassSubType(ClassMirror m1, ClassMirror m2) { |
- // TODO(vsm): Consider some caching for efficiency here. |
- |
- // We support Dart's covariant generics with the caveat that we do not |
- // substitute bottom for dynamic in subtyping rules. |
- // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: |
- // - S !<: S<T1, ..., Tn> |
- // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> |
- if (m1 == m2) return true; |
- |
- if (_isTop(m1)) return false; |
- |
- // Check if m1 and m2 have the same raw type. If so, check covariance on |
- // type parameters. |
- if (m1.originalDeclaration == m2.originalDeclaration) { |
- if (_isRawClass(m2)) return true; |
- if (_isRawClass(m1)) return false; |
- |
- final typeArguments1 = m1.typeArguments; |
- final typeArguments2 = m2.typeArguments; |
- final length = typeArguments1.length; |
- assert(typeArguments1.isNotEmpty && typeArguments2.isNotEmpty); |
- assert(typeArguments2.length == length); |
- for (var i = 0; i < length; ++i) { |
- var typeArgument1 = typeArguments1[i]; |
- var typeArgument2 = typeArguments2[i]; |
- if (!_isSubType(typeArgument1, typeArgument2)) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- // Check superclass. |
- if (_isClassSubType(m1.superclass, m2)) return true; |
- |
- // Check for mixins. The mixin getter returns the original class if there is |
- // no mixin. |
- if (m1 != m1.mixin && _isClassSubType(m1.mixin, m2)) return true; |
- |
- // Check interfaces. |
- for (final parent in m1.superinterfaces) { |
- if (_isClassSubType(parent, m2)) return true; |
- } |
- |
- return false; |
-} |
- |
-final _dynamicMirror = reflectType(dynamic); |
-final _objectMirror = reflectType(Object); |
- |
-bool _isBottom(TypeMirror t, {bool dynamicIsBottom: false}) { |
- if (t == _dynamicMirror && dynamicIsBottom) return true; |
- // TODO(vsm): Do we need an explicit representation of Bottom? |
- return false; |
-} |
- |
-bool _isTop(TypeMirror t, {bool dynamicIsBottom: false}) { |
- if (t == _dynamicMirror && !dynamicIsBottom) return true; |
- if (t == _objectMirror) return true; |
- return false; |
-} |
- |
-bool _isGroundTypeMirror(TypeMirror mirror) { |
- // This is a runtime type - we should not see type parameters here. |
- assert(mirror is! TypeVariableMirror); |
- |
- // Allow only 'raw' functions. |
- if (mirror is TypedefMirror) { |
- return _isRawFunction(mirror.referent); |
- } |
- if (mirror is FunctionTypeMirror) { |
- return _isRawFunction(mirror); |
- } |
- |
- // Allow only 'raw' classes. |
- if (mirror is ClassMirror) { |
- return _isRawClass(mirror); |
- } |
- |
- // Only dynamic should be left. Should this be allowed? |
- // It's not particularly useful. |
- assert(mirror.reflectedType == dynamic); |
- return true; |
-} |
- |
-bool _isRawFunction(FunctionTypeMirror mirror) { |
- var returnType = mirror.returnType; |
- if (!_isTop(returnType)) return false; |
- for (var parameter in mirror.parameters) { |
- var paramType = parameter.type; |
- if (!_isBottom(paramType, dynamicIsBottom: true)) return false; |
- } |
- return true; |
-} |
- |
-bool _isRawClass(ClassMirror mirror) { |
- // Allow only raw types. |
- if (mirror == mirror.originalDeclaration) return true; |
- for (var typeArgument in mirror.typeArguments) { |
- if (!_isTop(typeArgument)) return false; |
- } |
- return true; |
-} |
- |
-TypeMirror _canonicalizeTypeMirror(TypeMirror t) { |
- if (t is TypedefMirror) { |
- // We canonicalize Typedefs to their underlying function types. |
- t = (t as TypedefMirror).referent; |
- } |
- if (t is ClassMirror && _isRawClass(t)) { |
- // We canonicalize T<dynamic> to T. |
- t = t.originalDeclaration; |
- } |
- return t; |
-} |
- |
-bool _reflects(TypeMirror mirror, Type t) { |
- return mirror.hasReflectedType && mirror.reflectedType == t; |
-} |
- |
-bool _isSubType(TypeMirror t1, TypeMirror t2, {bool dynamicIsBottom: false}) { |
- t1 = _canonicalizeTypeMirror(t1); |
- t2 = _canonicalizeTypeMirror(t2); |
- |
- if (t1 is TypeVariableMirror) { |
- t1 = t1.upperBound; |
- } |
- |
- if (t1 == t2) return true; |
- |
- // Trivially true. |
- if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
- _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
- return true; |
- } |
- |
- // Trivially false. |
- if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
- _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
- return false; |
- } |
- |
- // "Traditional" name-based subtype check. |
- final c1 = t1 as ClassMirror; |
- final c2 = t2 as ClassMirror; |
- if (_isClassSubType(c1, c2)) { |
- return true; |
- } |
- |
- // Function subtyping. |
- // Note: it appears under the hood all Dart functions map to a class / hidden type |
- // that: |
- // (a) subtypes Object (an internal _FunctionImpl in the VM) |
- // (b) implements Function |
- // (c) provides standard Object members (hashCode, toString) |
- // (d) contains private members (corresponding to _FunctionImpl?) |
- // (e) provides a call method to handle the actual function invocation |
- // |
- // The standard Dart subtyping rules are structural in nature. I.e., |
- // bivariant on arguments and return type. |
- // |
- // The below tries for a more traditional subtyping rule: |
- // - covariant on return type |
- // - contravariant on parameters |
- // - 'sensible' (?) rules on optional and/or named params |
- // but doesn't properly mix with class subtyping yet. |
- // |
- // Note, a class type that implements a call method implicitly subtypes |
- // the function type of the call method. However, the converse is not true: |
- // a function type does not subtype a class type with a call method. |
- |
- // If c1 is not a proper function or a class type with call method, |
- // return false. |
- TypeMirror ret1; |
- List<ParameterMirror> params1; |
- // Note, a proper function has a call method, but it's not a regular method, |
- // so we break out the two cases. |
- if (c1 is FunctionTypeMirror) { |
- // Regular function |
- ret1 = c1.returnType; |
- params1 = c1.parameters; |
- } else { |
- var call1 = c1.instanceMembers[#call]; |
- if (call1 == null || !call1.isRegularMethod) return false; |
- // Class that emulate a function |
- ret1 = call1.returnType; |
- params1 = call1.parameters; |
- } |
- |
- // Any type that implements a call method implicitly subtypes Function. |
- if (_reflects(c2, Function)) return true; |
- |
- // Check structural function subtyping |
- return _isFunctionSubType(ret1, params1, c2.returnType, c2.parameters); |
-} |