From 2547caab258bec7b8d9742df2cce3fdfc2680786 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Tue, 10 Jan 2017 15:53:21 +0100 Subject: [PATCH] Reapply "reflectType() dynamic type arguments support (#26012)" This was a pull request: 8a8033a4176a2f26e8ed035497631d539dc1ede5 MirrorsUsed doesn't transitively include reflective information. However, it must still be able to create TypeMirrors for types that are used as return- or parameter types. Initially, the patch checked that TypeMirrors had the correct number of arguments for generic types. This is now disabled. A better approach would be to know if a class has full reflective information, or not. But this would require much bigger changes to the system. R=sigmund@google.com Review-Url: https://codereview.chromium.org/2615943004 . --- pkg/compiler/lib/src/js_backend/backend.dart | 2 +- pkg/compiler/lib/src/mirrors_used.dart | 4 +- runtime/lib/mirrors.cc | 64 ++ runtime/lib/mirrors_impl.dart | 15 +- runtime/lib/mirrors_patch.dart | 4 +- runtime/vm/bootstrap_natives.h | 1 + .../_internal/js_runtime/lib/js_mirrors.dart | 835 +++++++++--------- .../js_runtime/lib/mirrors_patch.dart | 4 +- sdk/lib/mirrors/mirrors.dart | 61 +- tests/lib/lib.status | 12 + .../mirrors_used_generic_types_test.dart | 28 + .../mirrors/reflected_type_generics_test.dart | 99 +++ tests/lib/mirrors/reflected_type_helper.dart | 1 + 13 files changed, 669 insertions(+), 461 deletions(-) create mode 100644 tests/lib/mirrors/mirrors_used_generic_types_test.dart create mode 100644 tests/lib/mirrors/reflected_type_generics_test.dart diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart index 95cd78e7fb3..87ce42f9c71 100644 --- a/pkg/compiler/lib/src/js_backend/backend.dart +++ b/pkg/compiler/lib/src/js_backend/backend.dart @@ -1984,7 +1984,7 @@ class JavaScriptBackend extends Backend { /** * Returns true if the element has to be resolved due to a mirrorsUsed * annotation. If we have insufficient mirrors used annotations, we only - * keep additonal elements if treeshaking has been disabled. + * keep additional elements if treeshaking has been disabled. */ bool requiredByMirrorSystem(Element element) { return hasInsufficientMirrorsUsed && isTreeShakingDisabled || diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart index dde7af17c86..34a81a56391 100644 --- a/pkg/compiler/lib/src/mirrors_used.dart +++ b/pkg/compiler/lib/src/mirrors_used.dart @@ -116,7 +116,7 @@ class MirrorUsageAnalyzerTask extends CompilerTask { (librariesWithUsage != null && librariesWithUsage.contains(library)); } - /// Call-back from the resolver to analyze MirorsUsed annotations. The result + /// Call-back from the resolver to analyze MirrorsUsed annotations. The result /// is stored in [analyzer] and later used to compute /// [:analyzer.mergedMirrorUsage:]. void validate(NewExpression node, TreeElements mapping) { @@ -260,7 +260,7 @@ class MirrorUsageAnalyzer { return result; } - /// Merge all [MirrorUsage] instances accross all libraries. + /// Merge all [MirrorUsage] instances across all libraries. MirrorUsage mergeUsages(Map> usageMap) { Set usagesToMerge = new Set(); usageMap.forEach((LibraryElement library, List usages) { diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index f99b1113658..a64dbed58cb 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -819,6 +819,70 @@ DEFINE_NATIVE_ENTRY(Mirrors_makeLocalTypeMirror, 1) { } +DEFINE_NATIVE_ENTRY(Mirrors_instantiateGenericType, 2) { + GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0)); + GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(1)); + + ASSERT(type.HasResolvedTypeClass()); + const Class& clz = Class::Handle(type.type_class()); + if (!clz.IsGeneric()) { + const Array& error_args = Array::Handle(Array::New(3)); + error_args.SetAt(0, type); + error_args.SetAt(1, String::Handle(String::New("key"))); + error_args.SetAt(2, String::Handle(String::New( + "Type must be a generic class or function."))); + Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args); + UNREACHABLE(); + } + if (clz.NumTypeParameters() != args.Length()) { + const Array& error_args = Array::Handle(Array::New(3)); + error_args.SetAt(0, args); + error_args.SetAt(1, String::Handle(String::New("typeArguments"))); + error_args.SetAt(2, String::Handle(String::New( + "Number of type arguments does not match."))); + Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args); + UNREACHABLE(); + } + + intptr_t num_expected_type_arguments = args.Length(); + TypeArguments& type_args_obj = TypeArguments::Handle(); + type_args_obj ^= TypeArguments::New(num_expected_type_arguments); + AbstractType& type_arg = AbstractType::Handle(); + Instance& instance = Instance::Handle(); + for (intptr_t i = 0; i < args.Length(); i++) { + instance ^= args.At(i); + if (!instance.IsType()) { + const Array& error_args = Array::Handle(Array::New(3)); + error_args.SetAt(0, args); + error_args.SetAt(1, String::Handle(String::New("typeArguments"))); + error_args.SetAt(2, String::Handle(String::New( + "Type arguments must be instances of Type."))); + Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args); + UNREACHABLE(); + } + type_arg ^= args.At(i); + type_args_obj.SetTypeAt(i, type_arg); + } + + Type& instantiated_type = + Type::Handle(Type::New(clz, type_args_obj, TokenPosition::kNoSource)); + instantiated_type ^= ClassFinalizer::FinalizeType( + clz, instantiated_type, ClassFinalizer::kCanonicalize); + if (instantiated_type.IsMalbounded()) { + const LanguageError& type_error = + LanguageError::Handle(instantiated_type.error()); + const Array& error_args = Array::Handle(Array::New(3)); + error_args.SetAt(0, args); + error_args.SetAt(1, String::Handle(String::New("typeArguments"))); + error_args.SetAt(2, String::Handle(type_error.FormatMessage())); + Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args); + UNREACHABLE(); + } + + return instantiated_type.raw(); +} + + DEFINE_NATIVE_ENTRY(Mirrors_mangleName, 2) { GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1)); diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart index fe1c56ecdeb..f152adbc733 100644 --- a/runtime/lib/mirrors_impl.dart +++ b/runtime/lib/mirrors_impl.dart @@ -1645,6 +1645,8 @@ class _Mirrors { native "Mirrors_makeLocalClassMirror"; static TypeMirror makeLocalTypeMirror(Type key) native "Mirrors_makeLocalTypeMirror"; + static Type instantiateGenericType(Type key, typeArguments) + native "Mirrors_instantiateGenericType"; static Expando _declarationCache = new Expando("ClassMirror"); static Expando _instantiationCache = new Expando("TypeMirror"); @@ -1661,7 +1663,10 @@ class _Mirrors { return classMirror; } - static TypeMirror reflectType(Type key) { + static TypeMirror reflectType(Type key, [List typeArguments]) { + if (typeArguments != null) { + key = _instantiateType(key, typeArguments); + } var typeMirror = _instantiationCache[key]; if (typeMirror == null) { typeMirror = makeLocalTypeMirror(key); @@ -1672,4 +1677,12 @@ class _Mirrors { } return typeMirror; } + + static Type _instantiateType(Type key, List typeArguments) { + if (typeArguments.isEmpty) { + throw new ArgumentError.value( + typeArguments, 'typeArguments', 'Type arguments list cannot be empty.'); + } + return instantiateGenericType(key, typeArguments.toList(growable: false)); + } } diff --git a/runtime/lib/mirrors_patch.dart b/runtime/lib/mirrors_patch.dart index 03bd1b6eca5..c1680268104 100644 --- a/runtime/lib/mirrors_patch.dart +++ b/runtime/lib/mirrors_patch.dart @@ -33,8 +33,8 @@ import "dart:_internal" as internal; return _Mirrors.reflectClass(key); } -@patch TypeMirror reflectType(Type key) { - return _Mirrors.reflectType(key); +@patch TypeMirror reflectType(Type key, [List typeArguments]) { + return _Mirrors.reflectType(key, typeArguments); } @patch class MirrorSystem { diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index 1260f7cd426..725af062cb6 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -366,6 +366,7 @@ namespace dart { V(Mirrors_evalInLibraryWithPrivateKey, 2) \ V(Mirrors_makeLocalClassMirror, 1) \ V(Mirrors_makeLocalTypeMirror, 1) \ + V(Mirrors_instantiateGenericType, 2) \ V(Mirrors_mangleName, 2) \ V(MirrorReference_equals, 2) \ V(MirrorSystem_libraries, 0) \ diff --git a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart index b554437dcb6..7489b217aa5 100644 --- a/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart +++ b/sdk/lib/_internal/js_runtime/lib/js_mirrors.dart @@ -4,63 +4,60 @@ library dart._js_mirrors; -import 'dart:_js_embedded_names' show - JsGetName, - ALL_CLASSES, - LAZIES, - LIBRARIES, - STATICS, - TYPE_INFORMATION, - TYPEDEF_PREDICATE_PROPERTY_NAME, - TYPEDEF_TYPE_PROPERTY_NAME; +import 'dart:_js_embedded_names' + show + JsGetName, + ALL_CLASSES, + LAZIES, + LIBRARIES, + STATICS, + TYPE_INFORMATION, + TYPEDEF_PREDICATE_PROPERTY_NAME, + TYPEDEF_TYPE_PROPERTY_NAME; -import 'dart:collection' show - UnmodifiableListView, - UnmodifiableMapView; +import 'dart:collection' show UnmodifiableListView, UnmodifiableMapView; import 'dart:mirrors'; -import 'dart:_foreign_helper' show - JS, - JS_GET_FLAG, - JS_GET_STATIC_STATE, - JS_CURRENT_ISOLATE_CONTEXT, - JS_EMBEDDED_GLOBAL, - JS_GET_NAME; - +import 'dart:_foreign_helper' + show + JS, + JS_GET_FLAG, + JS_GET_STATIC_STATE, + JS_CURRENT_ISOLATE_CONTEXT, + JS_EMBEDDED_GLOBAL, + JS_GET_NAME; import 'dart:_internal' as _symbol_dev; -import 'dart:_js_helper' show - BoundClosure, - CachedInvocation, - Closure, - JSInvocationMirror, - JsCache, - Primitives, - ReflectionInfo, - RuntimeError, - TearOffClosure, - TypeVariable, - UnimplementedNoSuchMethodError, - createRuntimeType, - createUnmangledInvocationMirror, - getMangledTypeName, - getMetadata, - getType, - getRuntimeType, - isDartFunctionType, - runtimeTypeToString, - setRuntimeTypeInfo, - throwInvalidReflectionError, - TypeImpl, - deferredLoadHook; +import 'dart:_js_helper' + show + BoundClosure, + CachedInvocation, + Closure, + JSInvocationMirror, + JsCache, + Primitives, + ReflectionInfo, + RuntimeError, + TearOffClosure, + TypeVariable, + UnimplementedNoSuchMethodError, + createRuntimeType, + createUnmangledInvocationMirror, + getMangledTypeName, + getMetadata, + getType, + getRuntimeType, + isDartFunctionType, + runtimeTypeToString, + setRuntimeTypeInfo, + throwInvalidReflectionError, + TypeImpl, + deferredLoadHook; -import 'dart:_interceptors' show - Interceptor, - JSArray, - JSExtendableArray, - getInterceptor; +import 'dart:_interceptors' + show Interceptor, JSArray, JSExtendableArray, getInterceptor; import 'dart:_js_names'; @@ -152,10 +149,11 @@ class JsMirrorSystem implements MirrorSystem { if (uriString != "") { uri = Uri.parse(uriString); } else { - uri = new Uri(scheme: 'https', - host: 'dartlang.org', - path: 'dart2js-stripped-uri', - queryParameters: { 'lib': name }); + uri = new Uri( + scheme: 'https', + host: 'dartlang.org', + path: 'dart2js-stripped-uri', + queryParameters: {'lib': name}); } List classes = data[2]; List functions = data[3]; @@ -164,12 +162,11 @@ class JsMirrorSystem implements MirrorSystem { bool isRoot = data[6]; var globalObject = data[7]; List metadata = (metadataFunction == null) - ? const [] : JS('List', '#()', metadataFunction); + ? const [] + : JS('List', '#()', metadataFunction); var libraries = result.putIfAbsent(name, () => []); - libraries.add( - new JsLibraryMirror( - s(name), uri, classes, functions, metadata, fields, isRoot, - globalObject)); + libraries.add(new JsLibraryMirror(s(name), uri, classes, functions, + metadata, fields, isRoot, globalObject)); } return result; } @@ -217,8 +214,8 @@ class JsIsolateMirror extends JsMirror implements IsolateMirror { bool get isCurrent => JS_CURRENT_ISOLATE_CONTEXT() == _isolateContext; LibraryMirror get rootLibrary { - return currentJsMirrorSystem.libraries.values.firstWhere( - (JsLibraryMirror library) => library._isRoot); + return currentJsMirrorSystem.libraries.values + .firstWhere((JsLibraryMirror library) => library._isRoot); } } @@ -255,8 +252,8 @@ class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror { final int _metadataIndex; TypeMirror _cachedUpperBound; - JsTypeVariableMirror(TypeVariable typeVariable, this.owner, - this._metadataIndex) + JsTypeVariableMirror( + TypeVariable typeVariable, this.owner, this._metadataIndex) : this._typeVariable = typeVariable, super(s(typeVariable.name)); @@ -291,8 +288,7 @@ class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror { } class JsTypeMirror extends JsDeclarationMirror implements TypeMirror { - JsTypeMirror(Symbol simpleName) - : super(simpleName); + JsTypeMirror(Symbol simpleName) : super(simpleName); String get _prettyName => 'TypeMirror'; @@ -325,7 +321,8 @@ class JsTypeMirror extends JsDeclarationMirror implements TypeMirror { } } -class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror +class JsLibraryMirror extends JsDeclarationMirror + with JsObjectMirror implements LibraryMirror { final Uri _uri; final List _classes; @@ -345,14 +342,15 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror UnmodifiableMapView _cachedDeclarations; UnmodifiableListView _cachedMetadata; - JsLibraryMirror(Symbol simpleName, - this._uri, - this._classes, - this._functions, - this._metadata, - this._compactFieldSpecification, - this._isRoot, - this._globalObject) + JsLibraryMirror( + Symbol simpleName, + this._uri, + this._classes, + this._functions, + this._metadata, + this._compactFieldSpecification, + this._isRoot, + this._globalObject) : super(simpleName) { preserveLibraryNames(); } @@ -379,7 +377,7 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror if (cls is JsClassMirror) { result[cls.simpleName] = cls; cls._owner = this; - } else if (cls is JsTypedefMirror) { + } else if (cls is JsTypedefMirror) { result[cls.simpleName] = cls; } } @@ -414,9 +412,8 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror return reflect(JS("", "#()", getter)); } - InstanceMirror invoke(Symbol memberName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) { if (namedArguments != null && !namedArguments.isEmpty) { throw new UnsupportedError('Named arguments are not implemented.'); } @@ -474,14 +471,13 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror continue; } bool isConstructor = unmangledName.startsWith('new '); - bool isStatic = !isConstructor; // Top-level functions are static, but - // constructors are not. + // Top-level functions are static, but constructors are not. + bool isStatic = !isConstructor; if (isConstructor) { unmangledName = unmangledName.substring(4).replaceAll(r'$', '.'); } - JsMethodMirror mirror = - new JsMethodMirror.fromUnmangledName( - unmangledName, jsFunction, isStatic, isConstructor); + JsMethodMirror mirror = new JsMethodMirror.fromUnmangledName( + unmangledName, jsFunction, isStatic, isConstructor); result.add(mirror); mirror._owner = this; } @@ -533,11 +529,12 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror } Map get __members { - if (_cachedMembers != null) return _cachedMembers; + if (_cachedMembers != null) return _cachedMembers; Map result = new Map.from(__classes); addToResult(Symbol key, Mirror value) { result[key] = value; } + __functions.forEach(addToResult); __getters.forEach(addToResult); __setters.forEach(addToResult); @@ -551,6 +548,7 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror addToResult(Symbol key, Mirror value) { result[key] = value; } + __members.forEach(addToResult); return _cachedDeclarations = new UnmodifiableMapView(result); @@ -566,8 +564,8 @@ class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror // TODO(ahe): Test this getter. DeclarationMirror get owner => null; - List get libraryDependencies - => throw new UnimplementedError(); + List get libraryDependencies => + throw new UnimplementedError(); } String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol); @@ -589,8 +587,19 @@ InstanceMirror reflect(Object reflectee) { } } -TypeMirror reflectType(Type key) { - return reflectClassByMangledName(getMangledTypeName(key)); +TypeMirror reflectType(Type key, [List typeArguments]) { + String mangledName = getMangledTypeName(key); + if (typeArguments != null) { + if (typeArguments.isEmpty || !typeArguments.every((_) => _ is TypeImpl)) { + var message = typeArguments.isEmpty + ? 'Type arguments list can not be empty.' + : 'Type arguments list must contain only instances of Type.'; + throw new ArgumentError.value(typeArguments, 'typeArguments', message); + } + var mangledTypeArguments = typeArguments.map(getMangledTypeName); + mangledName = "${mangledName}<${mangledTypeArguments.join(', ')}>"; + } + return reflectClassByMangledName(mangledName); } TypeMirror reflectClassByMangledName(String mangledName) { @@ -612,11 +621,12 @@ TypeMirror reflectClassByName(Symbol symbol, String mangledName) { if (typeArgIndex != -1) { TypeMirror originalDeclaration = reflectClassByMangledName(mangledName.substring(0, typeArgIndex)) - .originalDeclaration; + .originalDeclaration; if (originalDeclaration is JsTypedefMirror) { throw new UnimplementedError(); } - mirror = new JsTypeBoundClassMirror(originalDeclaration, + mirror = new JsTypeBoundClassMirror( + originalDeclaration, // Remove the angle brackets enclosing the type arguments. mangledName.substring(typeArgIndex + 1, mangledName.length - 1)); JsCache.update(classMirrors, mangledName, mirror); @@ -635,8 +645,8 @@ TypeMirror reflectClassByName(Symbol symbol, String mangledName) { if (descriptor == null) { // This is a native class, or an intercepted class. // TODO(ahe): Preserve descriptor for such classes. - } else if (JS('bool', '# in #', - TYPEDEF_PREDICATE_PROPERTY_NAME, descriptor)) { + } else if (JS( + 'bool', '# in #', TYPEDEF_PREDICATE_PROPERTY_NAME, descriptor)) { // Typedefs are represented as normal classes with two special properties: // TYPEDEF_PREDICATE_PROPERTY_NAME and TYPEDEF_TYPE_PROPERTY_NAME. // For example: @@ -688,6 +698,43 @@ TypeMirror reflectClassByName(Symbol symbol, String mangledName) { return mirror; } +/// Splits input `typeArguments` string into a list of strings for each argument. +/// Takes into account nested generic types. +/// For example, `Map, String` will become a list of two items: +/// `Map` and `String`. +List splitTypeArguments(String typeArguments) { + if (typeArguments.indexOf('<') == -1) { + return typeArguments.split(','); + } + var argumentList = new List(); + int level = 0; + String currentTypeArgument = ''; + + for (int i = 0; i < typeArguments.length; i++) { + var character = typeArguments[i]; + if (character == ' ') { + continue; + } else if (character == '<') { + currentTypeArgument += character; + level++; + } else if (character == '>') { + currentTypeArgument += character; + level--; + } else if (character == ',') { + if (level > 0) { + currentTypeArgument += character; + } else { + argumentList.add(currentTypeArgument); + currentTypeArgument = ''; + } + } else { + currentTypeArgument += character; + } + } + argumentList.add(currentTypeArgument); + return argumentList; +} + Map filterMethods(List methods) { var result = new Map(); for (JsMethodMirror method in methods) { @@ -708,12 +755,11 @@ Map filterConstructors(methods) { return result; } -Map filterGetters(List methods, - Map fields) { +Map filterGetters( + List methods, Map fields) { var result = new Map(); for (JsMethodMirror method in methods) { if (method.isGetter) { - // TODO(ahe): This is a hack to remove getters corresponding to a field. if (fields[method.simpleName] != null) continue; @@ -723,12 +769,11 @@ Map filterGetters(List methods, return result; } -Map filterSetters(List methods, - Map fields) { +Map filterSetters( + List methods, Map fields) { var result = new Map(); for (JsMethodMirror method in methods) { if (method.isSetter) { - // TODO(ahe): This is a hack to remove setters corresponding to a field. String name = n(method.simpleName); name = name.substring(0, name.length - 1); // Remove '='. @@ -740,8 +785,8 @@ Map filterSetters(List methods, return result; } -Map filterMembers(List methods, - Map variables) { +Map filterMembers( + List methods, Map variables) { Map result = new Map.from(variables); for (JsMethodMirror method in methods) { if (method.isSetter) { @@ -777,15 +822,16 @@ ClassMirror reflectMixinApplication(mixinNames, String mangledName) { return superclass; } -class JsMixinApplication extends JsTypeMirror with JsObjectMirror +class JsMixinApplication extends JsTypeMirror + with JsObjectMirror implements ClassMirror { final ClassMirror superclass; final ClassMirror mixin; Symbol _cachedSimpleName; Map _cachedInstanceMembers; - JsMixinApplication(ClassMirror superclass, ClassMirror mixin, - String mangledName) + JsMixinApplication( + ClassMirror superclass, ClassMirror mixin, String mangledName) : this.superclass = superclass, this.mixin = mixin, super(s(mangledName)); @@ -833,10 +879,8 @@ class JsMixinApplication extends JsTypeMirror with JsObjectMirror _asRuntimeType() => null; - InstanceMirror invoke( - Symbol memberName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) { throw new NoSuchStaticMethodError.method( null, memberName, positionalArguments, namedArguments); } @@ -858,10 +902,8 @@ class JsMixinApplication extends JsTypeMirror with JsObjectMirror Map get __constructors => _mixin.__constructors; - InstanceMirror newInstance( - Symbol constructorName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror newInstance(Symbol constructorName, List positionalArguments, + [Map namedArguments]) { throw new UnsupportedError( "Can't instantiate mixin application '${n(qualifiedName)}'"); } @@ -890,8 +932,7 @@ class JsMixinApplication extends JsTypeMirror with JsObjectMirror bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); } -abstract class JsObjectMirror implements ObjectMirror { -} +abstract class JsObjectMirror implements ObjectMirror {} class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { final reflectee; @@ -907,19 +948,17 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { return reflectType(getRuntimeType(reflectee)); } - InstanceMirror invoke(Symbol memberName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) { if (namedArguments == null) namedArguments = const {}; // We can safely pass positionalArguments to _invoke as it will wrap it in // a JSArray if needed. - return _invoke(memberName, JSInvocationMirror.METHOD, - positionalArguments, namedArguments); + return _invoke(memberName, JSInvocationMirror.METHOD, positionalArguments, + namedArguments); } - InstanceMirror _invokeMethodWithNamedArguments( - String reflectiveName, - List positionalArguments, Map namedArguments) { + InstanceMirror _invokeMethodWithNamedArguments(String reflectiveName, + List positionalArguments, Map namedArguments) { assert(namedArguments.isNotEmpty); var interceptor = getInterceptor(reflectee); @@ -983,12 +1022,13 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { } String _computeReflectiveName(Symbol symbolName, int type, - List positionalArguments, - Map namedArguments) { + List positionalArguments, Map namedArguments) { String name = n(symbolName); switch (type) { - case JSInvocationMirror.GETTER: return name; - case JSInvocationMirror.SETTER: return '$name='; + case JSInvocationMirror.GETTER: + return name; + case JSInvocationMirror.SETTER: + return '$name='; case JSInvocationMirror.METHOD: if (namedArguments.isNotEmpty) return '$name*'; int nbArgs = positionalArguments.length as int; @@ -1004,8 +1044,7 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { * Caches the result. */ _getCachedInvocation(Symbol name, int type, String reflectiveName, - List positionalArguments, Map namedArguments) { - + List positionalArguments, Map namedArguments) { var cache = _classInvocationCache; var cacheEntry = JsCache.fetch(cache, reflectiveName); var result; @@ -1037,10 +1076,8 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { /// Invoke the member specified through name and type on the reflectee. /// As a side-effect, this populates the class-specific invocation cache /// for the reflectee. - InstanceMirror _invoke(Symbol name, - int type, - List positionalArguments, - Map namedArguments) { + InstanceMirror _invoke(Symbol name, int type, List positionalArguments, + Map namedArguments) { String reflectiveName = _computeReflectiveName(name, type, positionalArguments, namedArguments); @@ -1055,8 +1092,8 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { if (cacheEntry.isNoSuchMethod || !_isReflectable(cacheEntry)) { // Could be that we want to invoke a getter, or get a method. if (type == JSInvocationMirror.METHOD && _instanceFieldExists(name)) { - return getField(name).invoke( - #call, positionalArguments, namedArguments); + return getField(name) + .invoke(#call, positionalArguments, namedArguments); } if (type == JSInvocationMirror.SETTER) { @@ -1086,15 +1123,11 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { } // JS helpers for getField optimizations. - static bool isUndefined(x) - => JS('bool', 'typeof # == "undefined"', x); - static bool isMissingCache(x) - => JS('bool', 'typeof # == "number"', x); - static bool isMissingProbe(Symbol symbol) - => JS('bool', 'typeof #.\$p == "undefined"', symbol); - static bool isEvalAllowed() - => !JS_GET_FLAG("USE_CONTENT_SECURITY_POLICY"); - + static bool isUndefined(x) => JS('bool', 'typeof # == "undefined"', x); + static bool isMissingCache(x) => JS('bool', 'typeof # == "number"', x); + static bool isMissingProbe(Symbol symbol) => + JS('bool', 'typeof #.\$p == "undefined"', symbol); + static bool isEvalAllowed() => !JS_GET_FLAG("USE_CONTENT_SECURITY_POLICY"); /// The getter cache is lazily allocated after a couple /// of invocations of [InstanceMirror.getField]. The delay is @@ -1113,13 +1146,14 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { int getterType = JSInvocationMirror.GETTER; String getterName = _computeReflectiveName(name, getterType, const [], const {}); - var getterCacheEntry = _getCachedInvocation( - name, getterType, getterName, const [], const {}); + var getterCacheEntry = + _getCachedInvocation(name, getterType, getterName, const [], const {}); return !getterCacheEntry.isNoSuchMethod && !getterCacheEntry.isGetterStub; } InstanceMirror getField(Symbol fieldName) { - FASTPATH: { + FASTPATH: + { var cache = _getterCache; if (isMissingCache(cache) || isMissingProbe(fieldName)) break FASTPATH; // If the [fieldName] has an associated probe function, we can use @@ -1207,8 +1241,8 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { return JS('', 'new Function("o", #)', body); } - _newGetterNoEvalFn(n) => JS('', - '(function(n){return(function(o){return o[n]()})})(#)', n); + _newGetterNoEvalFn(n) => + JS('', '(function(n){return(function(o){return o[n]()})})(#)', n); _newInterceptedGetterFn(String name, bool useEval) { var object = reflectee; @@ -1219,22 +1253,20 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor); String className = JS('String', '#.constructor.name', interceptor); String functionName = '$className\$$name'; - String body = - ' function $functionName(o){return i.$name(o)}' + String body = ' function $functionName(o){return i.$name(o)}' ' return $functionName;'; return JS('', '(new Function("i", #))(#)', body, interceptor); } - _newInterceptGetterNoEvalFn(n, i) => JS('', - '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i); + _newInterceptGetterNoEvalFn(n, i) => + JS('', '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i); delegate(Invocation invocation) { return JSInvocationMirror.invokeFromMirror(invocation, reflectee); } operator ==(other) { - return other is JsInstanceMirror && - identical(reflectee, other.reflectee); + return other is JsInstanceMirror && identical(reflectee, other.reflectee); } int get hashCode { @@ -1332,54 +1364,25 @@ class JsTypeBoundClassMirror extends JsDeclarationMirror } } - if (_typeArguments.indexOf('<') == -1) { - _typeArguments.split(',').forEach((t) => addTypeArgument(t)); - } else { - int level = 0; - String currentTypeArgument = ''; - - for (int i = 0; i < _typeArguments.length; i++) { - var character = _typeArguments[i]; - if (character == ' ') { - continue; - } else if (character == '<') { - currentTypeArgument += character; - level++; - } else if (character == '>') { - currentTypeArgument += character; - level--; - } else if (character == ',') { - if (level > 0) { - currentTypeArgument += character; - } else { - addTypeArgument(currentTypeArgument); - currentTypeArgument = ''; - } - } else { - currentTypeArgument += character; - } - } - addTypeArgument(currentTypeArgument); - } + splitTypeArguments(_typeArguments).forEach(addTypeArgument); return _cachedTypeArguments = new UnmodifiableListView(result); } List get _methods { if (_cachedMethods != null) return _cachedMethods; - return _cachedMethods =_class._getMethodsWithOwner(this); + return _cachedMethods = _class._getMethodsWithOwner(this); } Map get __methods { if (_cachedMethodsMap != null) return _cachedMethodsMap; - return _cachedMethodsMap = new UnmodifiableMapView( - filterMethods(_methods)); + return _cachedMethodsMap = + new UnmodifiableMapView(filterMethods(_methods)); } Map get __constructors { if (_cachedConstructors != null) return _cachedConstructors; - return _cachedConstructors = - new UnmodifiableMapView( - filterConstructors(_methods)); + return _cachedConstructors = new UnmodifiableMapView( + filterConstructors(_methods)); } Map get __getters { @@ -1397,7 +1400,7 @@ class JsTypeBoundClassMirror extends JsDeclarationMirror Map get __variables { if (_cachedVariables != null) return _cachedVariables; var result = new Map(); - for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) { + for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) { result[mirror.simpleName] = mirror; } return _cachedVariables = @@ -1451,8 +1454,10 @@ class JsTypeBoundClassMirror extends JsDeclarationMirror result.addAll(superclass.instanceMembers); } declarations.values.forEach((decl) { - if (decl is MethodMirror && !decl.isStatic && - !decl.isConstructor && !decl.isAbstract) { + if (decl is MethodMirror && + !decl.isStatic && + !decl.isConstructor && + !decl.isAbstract) { result[decl.simpleName] = decl; } if (decl is VariableMirror && !decl.isStatic) { @@ -1477,19 +1482,17 @@ class JsTypeBoundClassMirror extends JsDeclarationMirror InstanceMirror getField(Symbol fieldName) => _class.getField(fieldName); - InstanceMirror newInstance(Symbol constructorName, - List positionalArguments, - [Map namedArguments]) { - var instance = _class._getInvokedInstance(constructorName, - positionalArguments, - namedArguments); + InstanceMirror newInstance(Symbol constructorName, List positionalArguments, + [Map namedArguments]) { + var instance = _class._getInvokedInstance( + constructorName, positionalArguments, namedArguments); return reflect(setRuntimeTypeInfo( instance, typeArguments.map((t) => t._asRuntimeType()).toList())); } _asRuntimeType() { - return [_class._jsConstructor].addAll( - typeArguments.map((t) => t._asRuntimeType())); + return [_class._jsConstructor] + .addAll(typeArguments.map((t) => t._asRuntimeType())); } JsLibraryMirror get owner => _class.owner; @@ -1507,9 +1510,8 @@ class JsTypeBoundClassMirror extends JsDeclarationMirror return _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type); } - InstanceMirror invoke(Symbol memberName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) { return _class.invoke(memberName, positionalArguments, namedArguments); } @@ -1562,14 +1564,12 @@ class JsSyntheticAccessor implements MethodMirror { final bool isGetter; final bool isStatic; final bool isTopLevel; - final _target; /// The field or type that introduces the synthetic accessor. - JsSyntheticAccessor(this.owner, - this.simpleName, - this.isGetter, - this.isStatic, - this.isTopLevel, - this._target); + /// The field or type that introduces the synthetic accessor. + final _target; + + JsSyntheticAccessor(this.owner, this.simpleName, this.isGetter, this.isStatic, + this.isTopLevel, this._target); bool get isSynthetic => true; bool get isRegularMethod => false; @@ -1622,7 +1622,8 @@ class JsSyntheticSetterParameter implements ParameterMirror { SourceLocation get location => throw new UnimplementedError(); } -class JsClassMirror extends JsTypeMirror with JsObjectMirror +class JsClassMirror extends JsTypeMirror + with JsObjectMirror implements ClassMirror { final String _mangledName; final _jsConstructor; @@ -1649,26 +1650,22 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror // Set as side-effect of accessing JsLibraryMirror.classes. JsLibraryMirror _owner; - JsClassMirror(Symbol simpleName, - this._mangledName, - this._jsConstructor, - this._fieldsDescriptor, - this._fieldsMetadata) + JsClassMirror(Symbol simpleName, this._mangledName, this._jsConstructor, + this._fieldsDescriptor, this._fieldsMetadata) : super(simpleName); String get _prettyName => 'ClassMirror'; Map get __constructors { if (_cachedConstructors != null) return _cachedConstructors; - return _cachedConstructors = - new UnmodifiableMapView( - filterConstructors(_methods)); + return _cachedConstructors = new UnmodifiableMapView( + filterConstructors(_methods)); } _asRuntimeType() { - if (typeVariables.isEmpty) return _jsConstructor; + if (typeVariables.isEmpty) return _jsConstructor; var type = [_jsConstructor]; - for (int i = 0; i < typeVariables.length; i ++) { + for (int i = 0; i < typeVariables.length; i++) { type.add(JsMirrorSystem._dynamicType._asRuntimeType); } return type; @@ -1678,7 +1675,7 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror var prototype = JS('', '#.prototype', _jsConstructor); // The prototype might not have been processed yet, so do that now. JS('', '#[#]()', prototype, - JS_GET_NAME(JsGetName.DEFERRED_ACTION_PROPERTY)); + JS_GET_NAME(JsGetName.DEFERRED_ACTION_PROPERTY)); List keys = extractKeys(prototype); var result = []; for (String key in keys) { @@ -1692,9 +1689,8 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror var function = JS('', '#[#]', prototype, key); if (!isOrdinaryReflectableMethod(function)) continue; if (isAliasedSuperMethod(function, key)) continue; - var mirror = - new JsMethodMirror.fromUnmangledName( - simpleName, function, false, false); + var mirror = new JsMethodMirror.fromUnmangledName( + simpleName, function, false, false); result.add(mirror); mirror._owner = methodOwner; } @@ -1720,9 +1716,8 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror continue; } bool isStatic = !isConstructor; // Constructors are not static. - JsMethodMirror mirror = - new JsMethodMirror.fromUnmangledName( - unmangledName, jsFunction, isStatic, isConstructor); + JsMethodMirror mirror = new JsMethodMirror.fromUnmangledName( + unmangledName, jsFunction, isStatic, isConstructor); result.add(mirror); mirror._owner = methodOwner; } @@ -1740,8 +1735,8 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror var instanceFieldSpecfication = _fieldsDescriptor.split(';')[1]; if (_fieldsMetadata != null) { - instanceFieldSpecfication = - [instanceFieldSpecfication]..addAll(_fieldsMetadata); + instanceFieldSpecfication = [instanceFieldSpecfication] + ..addAll(_fieldsMetadata); } parseCompactFieldSpecification( fieldOwner, instanceFieldSpecfication, false, result); @@ -1751,10 +1746,10 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror if (staticDescriptor != null) { parseCompactFieldSpecification( fieldOwner, - JS('', '#[#]', - staticDescriptor, + JS('', '#[#]', staticDescriptor, JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY)), - true, result); + true, + result); } return result; } @@ -1804,6 +1799,7 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror addToResult(Symbol key, Mirror value) { result[key] = value; } + __members.forEach(addToResult); __constructors.forEach(addToResult); typeVariables.forEach((tv) => result[tv.simpleName] = tv); @@ -1841,8 +1837,10 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror result.addAll(superclass.instanceMembers); } declarations.values.forEach((decl) { - if (decl is MethodMirror && !decl.isStatic && - !decl.isConstructor && !decl.isAbstract) { + if (decl is MethodMirror && + !decl.isStatic && + !decl.isConstructor && + !decl.isAbstract) { result[decl.simpleName] = decl; } if (decl is VariableMirror && !decl.isStatic) { @@ -1926,32 +1924,28 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror throw new NoSuchStaticMethodError.method(null, fieldName, null, null); } - _getInvokedInstance(Symbol constructorName, - List positionalArguments, - [Map namedArguments]) { - if (namedArguments != null && !namedArguments.isEmpty) { - throw new UnsupportedError('Named arguments are not implemented.'); - } - JsMethodMirror mirror = - JsCache.fetch(_jsConstructorCache, n(constructorName)); - if (mirror == null) { - mirror = __constructors.values.firstWhere( - (m) => m.constructorName == constructorName, - orElse: () { - throw new NoSuchStaticMethodError.method( - null, constructorName, positionalArguments, namedArguments); - }); - JsCache.update(_jsConstructorCache, n(constructorName), mirror); - } - return mirror._invoke(positionalArguments, namedArguments); - } + _getInvokedInstance(Symbol constructorName, List positionalArguments, + [Map namedArguments]) { + if (namedArguments != null && !namedArguments.isEmpty) { + throw new UnsupportedError('Named arguments are not implemented.'); + } + JsMethodMirror mirror = + JsCache.fetch(_jsConstructorCache, n(constructorName)); + if (mirror == null) { + mirror = __constructors.values + .firstWhere((m) => m.constructorName == constructorName, orElse: () { + throw new NoSuchStaticMethodError.method( + null, constructorName, positionalArguments, namedArguments); + }); + JsCache.update(_jsConstructorCache, n(constructorName), mirror); + } + return mirror._invoke(positionalArguments, namedArguments); + } - InstanceMirror newInstance(Symbol constructorName, - List positionalArguments, - [Map namedArguments]) { - return reflect(_getInvokedInstance(constructorName, - positionalArguments, - namedArguments)); + InstanceMirror newInstance(Symbol constructorName, List positionalArguments, + [Map namedArguments]) { + return reflect(_getInvokedInstance( + constructorName, positionalArguments, namedArguments)); } JsLibraryMirror get owner { @@ -2001,16 +1995,16 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror // Use _superclass == this to represent class with no superclass // (Object). _superclass = (superclassName == '') - ? this : reflectClassByMangledName(superclassName); - } + ? this + : reflectClassByMangledName(superclassName); } } + } return _superclass == this ? null : _superclass; } - InstanceMirror invoke(Symbol memberName, - List positionalArguments, - [Map namedArguments]) { + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) { // Mirror API gotcha: Calling [invoke] on a ClassMirror means invoke a // static method. @@ -2065,15 +2059,15 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror } List get typeVariables { - if (_cachedTypeVariables != null) return _cachedTypeVariables; - List result = new List(); - List typeVariables = + if (_cachedTypeVariables != null) return _cachedTypeVariables; + List result = new List(); + List typeVariables = JS('JSExtendableArray|Null', '#.prototype["<>"]', _jsConstructor); if (typeVariables == null) return result; for (int i = 0; i < typeVariables.length; i++) { TypeVariable typeVariable = getMetadata(typeVariables[i]); - result.add(new JsTypeVariableMirror(typeVariable, this, - typeVariables[i])); + result + .add(new JsTypeVariableMirror(typeVariable, this, typeVariables[i])); } return _cachedTypeVariables = new UnmodifiableListView(result); } @@ -2103,8 +2097,9 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror } if (other is JsFunctionTypeMirror) { return false; - } if (other is JsClassMirror && - JS('bool', '# == #', other._jsConstructor, _jsConstructor)) { + } + if (other is JsClassMirror && + JS('bool', '# == #', other._jsConstructor, _jsConstructor)) { return true; } else if (superclass == null) { return false; @@ -2115,7 +2110,6 @@ class JsClassMirror extends JsTypeMirror with JsObjectMirror } class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { - // TODO(ahe): The values in these fields are virtually untested. final String _jsName; final bool isFinal; @@ -2125,19 +2119,12 @@ class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { final int _type; List _metadata; - JsVariableMirror(Symbol simpleName, - this._jsName, - this._type, - this.isFinal, - this.isStatic, - this._metadataFunction, - this._owner) + JsVariableMirror(Symbol simpleName, this._jsName, this._type, this.isFinal, + this.isStatic, this._metadataFunction, this._owner) : super(simpleName); - factory JsVariableMirror.from(String descriptor, - metadataFunction, - JsDeclarationMirror owner, - bool isStatic) { + factory JsVariableMirror.from(String descriptor, metadataFunction, + JsDeclarationMirror owner, bool isStatic) { List fieldInformation = descriptor.split('-'); if (fieldInformation.length == 1) { // The field is not available for reflection. @@ -2180,13 +2167,8 @@ class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { } } int type = int.parse(fieldInformation[1], onError: (_) => null); - return new JsVariableMirror(s(unmangledName), - jsName, - type, - isFinal, - isStatic, - metadataFunction, - owner); + return new JsVariableMirror(s(unmangledName), jsName, type, isFinal, + isStatic, metadataFunction, owner); } String get _prettyName => 'VariableMirror'; @@ -2201,7 +2183,8 @@ class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { preserveMetadata(); if (_metadata == null) { _metadata = (_metadataFunction == null) - ? const [] : JS('', '#()', _metadataFunction); + ? const [] + : JS('', '#()', _metadataFunction); } return _metadata.map(reflect).toList(); } @@ -2233,8 +2216,7 @@ class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { } class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { - JsClosureMirror(reflectee) - : super(reflectee); + JsClosureMirror(reflectee) : super(reflectee); MethodMirror get function { String cacheName = Primitives.mirrorFunctionCacheName; @@ -2262,7 +2244,8 @@ class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { } return null; })(#, #)''', - reflectee, callPrefix); + reflectee, + callPrefix); if (callName == null) { throw new RuntimeError('Cannot find callName on "$reflectee"'); @@ -2276,22 +2259,29 @@ class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { if (name == null) { throwInvalidReflectionError(name); } - cachedFunction = new JsMethodMirror.fromUnmangledName( - name, target, false, false); + cachedFunction = + new JsMethodMirror.fromUnmangledName(name, target, false, false); } else { bool isStatic = true; // TODO(ahe): Compute isStatic correctly. var jsFunction = JS('', '#[#]', reflectee, callName); var dummyOptionalParameterCount = 0; cachedFunction = new JsMethodMirror( - s(callName), jsFunction, parameterCount, dummyOptionalParameterCount, - false, false, isStatic, false, false); + s(callName), + jsFunction, + parameterCount, + dummyOptionalParameterCount, + false, + false, + isStatic, + false, + false); } JS('void', r'#.constructor[#] = #', reflectee, cacheName, cachedFunction); return cachedFunction; } InstanceMirror apply(List positionalArguments, - [Map namedArguments]) { + [Map namedArguments]) { return reflect( Function.apply(reflectee, positionalArguments, namedArguments)); } @@ -2316,21 +2306,20 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { TypeMirror _returnType; UnmodifiableListView _parameters; - JsMethodMirror(Symbol simpleName, - this._jsFunction, - this._requiredParameterCount, - this._optionalParameterCount, - this.isGetter, - this.isSetter, - this.isStatic, - this.isConstructor, - this.isOperator) + JsMethodMirror( + Symbol simpleName, + this._jsFunction, + this._requiredParameterCount, + this._optionalParameterCount, + this.isGetter, + this.isSetter, + this.isStatic, + this.isConstructor, + this.isOperator) : super(simpleName); - factory JsMethodMirror.fromUnmangledName(String name, - jsFunction, - bool isStatic, - bool isConstructor) { + factory JsMethodMirror.fromUnmangledName( + String name, jsFunction, bool isStatic, bool isConstructor) { List info = name.split(':'); name = info[0]; bool isOperator = isOperatorName(name); @@ -2349,12 +2338,19 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { ReflectionInfo reflectionInfo = new ReflectionInfo(jsFunction); requiredParameterCount = reflectionInfo.requiredParameterCount; optionalParameterCount = reflectionInfo.optionalParameterCount; - assert(int.parse(info[1]) == requiredParameterCount - + optionalParameterCount); + assert(int.parse(info[1]) == + requiredParameterCount + optionalParameterCount); } return new JsMethodMirror( - s(name), jsFunction, requiredParameterCount, optionalParameterCount, - isGetter, isSetter, isStatic, isConstructor, isOperator); + s(name), + jsFunction, + requiredParameterCount, + optionalParameterCount, + isGetter, + isSetter, + isStatic, + isConstructor, + isOperator); } String get _prettyName => 'MethodMirror'; @@ -2384,8 +2380,8 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { var formals = new List(_parameterCount); ReflectionInfo info = new ReflectionInfo(_jsFunction); if (info != null) { - assert(_parameterCount - == info.requiredParameterCount + info.optionalParameterCount); + assert(_parameterCount == + info.requiredParameterCount + info.optionalParameterCount); var functionType = info.functionType; var type; if (functionType is int) { @@ -2397,8 +2393,7 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { TypeMirror ownerType = owner; JsClassMirror ownerClass = ownerType.originalDeclaration; type = new JsFunctionTypeMirror( - info.computeFunctionRti(ownerClass._jsConstructor), - owner); + info.computeFunctionRti(ownerClass._jsConstructor), owner); } // Constructors aren't reified with their return type. if (isConstructor) { @@ -2417,9 +2412,11 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { metadataList: annotations); } else { var defaultValue = info.defaultValue(i); - p = new JsParameterMirror( - name, this, parameter._type, metadataList: annotations, - isOptional: true, isNamed: isNamed, defaultValue: defaultValue); + p = new JsParameterMirror(name, this, parameter._type, + metadataList: annotations, + isOptional: true, + isNamed: isNamed, + defaultValue: defaultValue); } formals[i++] = p; } @@ -2449,7 +2446,7 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { } int positionalLength = positionalArguments.length; if (positionalLength < _requiredParameterCount || - positionalLength > _parameterCount || + positionalLength > _parameterCount || _jsFunction == null) { // TODO(ahe): What receiver to use? throw new NoSuchMethodError( @@ -2469,7 +2466,7 @@ class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { // care who their receiver is. But to lazy getters, it is important that // 'this' is '$'. return JS('', r'#.apply(#, #)', _jsFunction, JS_GET_STATIC_STATE(), - new List.from(positionalArguments)); + new List.from(positionalArguments)); } _getField(JsMirror receiver) { @@ -2527,13 +2524,11 @@ class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror { final List metadataList; - JsParameterMirror(String unmangledName, - this.owner, - this._type, - {this.metadataList: const [], - this.isOptional: false, - this.isNamed: false, - defaultValue}) + JsParameterMirror(String unmangledName, this.owner, this._type, + {this.metadataList: const [], + this.isOptional: false, + this.isNamed: false, + defaultValue}) : _defaultValue = defaultValue, super(s(unmangledName)); @@ -2568,7 +2563,7 @@ class JsTypedefMirror extends JsDeclarationMirror implements TypedefMirror { final String _mangledName; JsFunctionTypeMirror referent; - JsTypedefMirror(Symbol simpleName, this._mangledName, _typeData) + JsTypedefMirror(Symbol simpleName, this._mangledName, _typeData) : super(simpleName) { referent = new JsFunctionTypeMirror(_typeData, this); } @@ -2607,23 +2602,21 @@ class BrokenClassMirror { Type get reflectedType => throw new UnimplementedError(); ClassMirror get superclass => throw new UnimplementedError(); List get superinterfaces => throw new UnimplementedError(); - Map get declarations - => throw new UnimplementedError(); - Map get instanceMembers - => throw new UnimplementedError(); + Map get declarations => + throw new UnimplementedError(); + Map get instanceMembers => + throw new UnimplementedError(); Map get staticMembers => throw new UnimplementedError(); ClassMirror get mixin => throw new UnimplementedError(); - InstanceMirror newInstance( - Symbol constructorName, - List positionalArguments, - [Map namedArguments]) => throw new UnimplementedError(); - InstanceMirror invoke(Symbol memberName, - List positionalArguments, - [Map namedArguments]) - => throw new UnimplementedError(); + InstanceMirror newInstance(Symbol constructorName, List positionalArguments, + [Map namedArguments]) => + throw new UnimplementedError(); + InstanceMirror invoke(Symbol memberName, List positionalArguments, + [Map namedArguments]) => + throw new UnimplementedError(); InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError(); - InstanceMirror setField(Symbol fieldName, Object value) - => throw new UnimplementedError(); + InstanceMirror setField(Symbol fieldName, Object value) => + throw new UnimplementedError(); delegate(Invocation invocation) => throw new UnimplementedError(); List get typeVariables => throw new UnimplementedError(); List get typeArguments => throw new UnimplementedError(); @@ -2662,36 +2655,39 @@ class JsFunctionTypeMirror extends BrokenClassMirror } bool get _hasArguments { - return JS('bool', '# in #', - JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG), - _typeData); + return JS( + 'bool', + '# in #', + JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG), + _typeData); } + List get _arguments { - return JS('JSExtendableArray', '#[#]', - _typeData, - JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG)); + return JS('JSExtendableArray', '#[#]', _typeData, + JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG)); } bool get _hasOptionalArguments { - return JS('bool', '# in #', - JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG), - _typeData); + return JS( + 'bool', + '# in #', + JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG), + _typeData); } + List get _optionalArguments { - return JS('JSExtendableArray', '#[#]', - _typeData, - JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG)); + return JS('JSExtendableArray', '#[#]', _typeData, + JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG)); } bool get _hasNamedArguments { return JS('bool', '# in #', - JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG), - _typeData); + JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG), _typeData); } + get _namedArguments { - return JS('=Object', '#[#]', - _typeData, - JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG)); + return JS('=Object', '#[#]', _typeData, + JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG)); } bool get isOriginalDeclaration => true; @@ -2730,8 +2726,8 @@ class JsFunctionTypeMirror extends BrokenClassMirror result.add(new JsParameterMirror(name, this, type)); } } - return _cachedParameters = new UnmodifiableListView( - result); + return _cachedParameters = + new UnmodifiableListView(result); } String _unmangleIfPreserved(String mangled) { @@ -2804,8 +2800,7 @@ int findTypeVariableIndex(List typeVariables, String name) { } TypeMirror typeMirrorFromRuntimeTypeRepresentation( - DeclarationMirror owner, - var /*int|List|JsFunction|TypeImpl*/ type) { + DeclarationMirror owner, var /*int|List|JsFunction|TypeImpl*/ type) { // TODO(ahe): This method might benefit from using convertRtiToRuntimeType // instead of working on strings. ClassMirror ownerClass; @@ -2852,8 +2847,7 @@ TypeMirror typeMirrorFromRuntimeTypeRepresentation( // [type] represents a type variable used as type argument for example // the type argument of Bar: class Foo extends Bar {} TypeMirror typeArgument = getTypeArgument(type); - if (typeArgument is JsTypeVariableMirror) - return typeArgument; + if (typeArgument is JsTypeVariableMirror) return typeArgument; } String substituteTypeVariable(int index) { var typeArgument = getTypeArgument(index); @@ -2873,6 +2867,7 @@ TypeMirror typeMirrorFromRuntimeTypeRepresentation( } return typeArgument._mangledName; } + representation = runtimeTypeToString(type, onTypeVariable: substituteTypeVariable); } @@ -2905,19 +2900,17 @@ List extractMetadata(victim) { if (metadataFunction != null) return JS('', '#()', metadataFunction); if (JS('bool', 'typeof # != "function"', victim)) return const []; if (JS('bool', '# in #', r'$metadataIndex', victim)) { - return JSArray.markFixedList( - JS('JSExtendableArray', - r'#.$reflectionInfo.splice(#.$metadataIndex)', victim, victim)) - .map((int i) => getMetadata(i)).toList(); + return JSArray + .markFixedList(JS('JSExtendableArray', + r'#.$reflectionInfo.splice(#.$metadataIndex)', victim, victim)) + .map((int i) => getMetadata(i)) + .toList(); } return const []; } -void parseCompactFieldSpecification( - JsDeclarationMirror owner, - fieldSpecification, - bool isStatic, - List result) { +void parseCompactFieldSpecification(JsDeclarationMirror owner, + fieldSpecification, bool isStatic, List result) { List fieldsMetadata = null; List fields; if (fieldSpecification is List) { @@ -2930,7 +2923,7 @@ void parseCompactFieldSpecification( } int fieldNumber = 0; for (String field in fields) { - if (r'$ti' == field) continue; // Strip type info pseudofield. + if (r'$ti' == field) continue; // Strip type info pseudofield. var metadata; if (fieldsMetadata != null) { metadata = fieldsMetadata[fieldNumber++]; @@ -2950,29 +2943,29 @@ List splitFields(String string, Pattern pattern) { bool isOperatorName(String name) { switch (name) { - case '==': - case '[]': - case '*': - case '/': - case '%': - case '~/': - case '+': - case '<<': - case '>>': - case '>=': - case '>': - case '<=': - case '<': - case '&': - case '^': - case '|': - case '-': - case 'unary-': - case '[]=': - case '~': - return true; - default: - return false; + case '==': + case '[]': + case '*': + case '/': + case '%': + case '~/': + case '+': + case '<<': + case '>>': + case '>=': + case '>': + case '<=': + case '<': + case '&': + case '^': + case '|': + case '-': + case 'unary-': + case '[]=': + case '~': + return true; + default: + return false; } } @@ -3010,35 +3003,28 @@ class NoSuchStaticMethodError extends Error implements NoSuchMethodError { final int _kind; NoSuchStaticMethodError.missingConstructor( - this._cls, - this._name, - this._positionalArguments, - this._namedArguments) + this._cls, this._name, this._positionalArguments, this._namedArguments) : _kind = MISSING_CONSTRUCTOR; /// If the given class is `null` the static method/getter/setter is top-level. NoSuchStaticMethodError.method( - this._cls, - this._name, - this._positionalArguments, - this._namedArguments) + this._cls, this._name, this._positionalArguments, this._namedArguments) : _kind = MISSING_METHOD; String toString() { // TODO(floitsch): show arguments. - switch(_kind) { - case MISSING_CONSTRUCTOR: - return - "NoSuchMethodError: No constructor named '${n(_name)}' in class" - " '${n(_cls.qualifiedName)}'."; - case MISSING_METHOD: - if (_cls == null) { - return "NoSuchMethodError: No top-level method named '${n(_name)}'."; - } - return "NoSuchMethodError: No static method named '${n(_name)}' in" - " class '${n(_cls.qualifiedName)}'"; - default: - return 'NoSuchMethodError'; + switch (_kind) { + case MISSING_CONSTRUCTOR: + return "NoSuchMethodError: No constructor named '${n(_name)}' in class" + " '${n(_cls.qualifiedName)}'."; + case MISSING_METHOD: + if (_cls == null) { + return "NoSuchMethodError: No top-level method named '${n(_name)}'."; + } + return "NoSuchMethodError: No static method named '${n(_name)}' in" + " class '${n(_cls.qualifiedName)}'"; + default: + return 'NoSuchMethodError'; } } } @@ -3048,8 +3034,7 @@ Symbol getSymbol(String name, LibraryMirror library) { return new _symbol_dev.Symbol.validated(name); } if (library == null) { - throw new ArgumentError( - "Library required for private symbol name: $name"); + throw new ArgumentError("Library required for private symbol name: $name"); } if (!_symbol_dev.Symbol.isValidSymbol(name)) { throw new ArgumentError("Not a valid symbol name: $name"); diff --git a/sdk/lib/_internal/js_runtime/lib/mirrors_patch.dart b/sdk/lib/_internal/js_runtime/lib/mirrors_patch.dart index eb6319c591d..c3700430775 100644 --- a/sdk/lib/_internal/js_runtime/lib/mirrors_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/mirrors_patch.dart @@ -43,9 +43,9 @@ ClassMirror reflectClass(Type key) { } @patch -TypeMirror reflectType(Type key) { +TypeMirror reflectType(Type key, [List typeArguments]) { if (key == dynamic) { return currentMirrorSystem().dynamicType; } - return js.reflectType(key); + return js.reflectType(key, typeArguments); } diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart index 3aa88f4c24b..4cfbf190fa2 100644 --- a/sdk/lib/mirrors/mirrors.dart +++ b/sdk/lib/mirrors/mirrors.dart @@ -171,11 +171,16 @@ external ClassMirror reflectClass(Type key); * If [key] is not an instance of [Type], then this function throws an * [ArgumentError]. * + * Optionally takes a list of [typeArguments] for generic classes. If the list + * is provided, then the [key] must be a generic class type, and the number of + * the provided type arguments must be equal to the number of type variables + * declared by the class. + * * Note that since one cannot obtain a [Type] object from another isolate, this * function can only be used to obtain type mirrors on types of the current * isolate. */ -external TypeMirror reflectType(Type key); +external TypeMirror reflectType(Type key, [List typeArguments]); /** * A [Mirror] reflects some Dart language entity. @@ -1229,7 +1234,7 @@ class Comment { * see the comments for [symbols], [targets], [metaTargets] and [override]. * * An import of `dart:mirrors` may have multiple [MirrorsUsed] annotations. This - * is particularly helpful to specify overrides for specific libraries. For + * is particularly helpful to specify overrides for specific libraries. For * example: * * @MirrorsUsed(targets: 'foo.Bar', override: 'foo') @@ -1241,7 +1246,7 @@ class Comment { */ class MirrorsUsed { // Note: the fields of this class are untyped. This is because the most - // convenient way to specify symbols today is using a single string. In + // convenient way to specify symbols today is using a single string. In // some cases, a const list of classes might be convenient. Some // might prefer to use a const list of symbols. @@ -1258,7 +1263,7 @@ class MirrorsUsed { * * Dart2js currently supports the following formats to specify symbols: * - * * A constant [List] of [String] constants representing symbol names, + * * A constant [List] of [String] constants representing symbol names, * e.g., `const ['foo', 'bar']`. * * A single [String] constant whose value is a comma-separated list of * symbol names, e.g., `"foo, bar"`. @@ -1306,14 +1311,14 @@ class MirrorsUsed { * 1. If the qualified name matches a library name, the matching library is * the target. * 2. Else, find the longest prefix of the name such that the prefix ends - * just before a `.` and is a library name. + * just before a `.` and is a library name. * 3. Use that library as current scope. If no matching prefix was found, use - * the current library, i.e., the library where the [MirrorsUsed] + * the current library, i.e., the library where the [MirrorsUsed] * annotation was placed. * 4. Split the remaining suffix (the entire name if no library name was - * found in step 3) into a list of [String] using `.` as a + * found in step 3) into a list of [String] using `.` as a * separator. - * 5. Select all targets in the current scope whose name matches a [String] + * 5. Select all targets in the current scope whose name matches a [String] * from the list. * * For example: @@ -1329,11 +1334,11 @@ class MirrorsUsed { * @MirrorsUsed(targets: "my.library.one.A.aField") * import "dart:mirrors"; * - * The [MirrorsUsed] annotation specifies `A` and `aField` from library + * The [MirrorsUsed] annotation specifies `A` and `aField` from library * `my.library.one` as targets. This will mark the class `A` as a reflective * target. The target specification for `aField` has no effect, as there is - * no target in `my.library.one` with that name. - * + * no target in `my.library.one` with that name. + * * Note that everything within a target also is available for reflection. * So, if a library is specified as target, all classes in that library * become targets for reflection. Likewise, if a class is a target, all @@ -1355,9 +1360,9 @@ class MirrorsUsed { * effect. In particular, adding a library to [metaTargets] does not make * the library's classes valid metadata annotations to enable reflection. * - * If an instance of a class specified in [metaTargets] is used as + * If an instance of a class specified in [metaTargets] is used as * metadata annotation on a library, class, field or method, that library, - * class, field or method is added to the set of targets for reflection. + * class, field or method is added to the set of targets for reflection. * * Example usage: * @@ -1377,10 +1382,10 @@ class MirrorsUsed { * } * * In the above example. `reflectableMethod` is marked as reflectable by - * using the `Reflectable` class, which in turn is specified in the + * using the `Reflectable` class, which in turn is specified in the * [metaTargets] annotation. * - * The method `nonReflectableMethod` lacks a metadata annotation and thus + * The method `nonReflectableMethod` lacks a metadata annotation and thus * will not be reflectable at runtime. */ final metaTargets; @@ -1390,7 +1395,7 @@ class MirrorsUsed { * * When used as metadata on an import of "dart:mirrors", this metadata does * not apply to the library in which the annotation is used, but instead - * applies to the other libraries (all libraries if "*" is used). + * applies to the other libraries (all libraries if "*" is used). * * The following text is non-normative: * @@ -1400,31 +1405,31 @@ class MirrorsUsed { * libraries. * * A single [String] constant whose value is a comma-separated list of * library names. - * - * Conceptually, a [MirrorsUsed] annotation with [override] has the same + * + * Conceptually, a [MirrorsUsed] annotation with [override] has the same * effect as placing the annotation directly on the import of `dart:mirrors` - * in each of the referenced libraries. Thus, if the library had no - * [MirrorsUsed] annotation before, its unconditional import of + * in each of the referenced libraries. Thus, if the library had no + * [MirrorsUsed] annotation before, its unconditional import of * `dart:mirrors` is overridden by an annotated import. - * + * * Note that, like multiple explicit [MirrorsUsed] annotations, using * override on a library with an existing [MirrorsUsed] annotation is * additive. That is, the overall set of reflective targets is the union * of the reflective targets that arise from the original and the - * overriding [MirrorsUsed] annotations. + * overriding [MirrorsUsed] annotations. * - * The use of [override] is only meaningful for libraries that have an + * The use of [override] is only meaningful for libraries that have an * import of `dart:mirrors` without annotation because otherwise it would * work exactly the same way without the [override] parameter. * * While the annotation will apply to the given target libraries, the - * [symbols], [targets] and [metaTargets] are still evaluated in the + * [symbols], [targets] and [metaTargets] are still evaluated in the * scope of the annotation. Thus, to select a target from library `foo`, * a qualified name has to be used or, if the target is visible in the * current scope, its type may be referenced. - * + * * For example, the following code marks all targets in the library `foo` - * as reflectable that have a metadata annotation using the `Reflectable` + * as reflectable that have a metadata annotation using the `Reflectable` * class from the same library. * * @MirrorsUsed(metaTargets: "foo.Reflectable", override: "foo") @@ -1438,8 +1443,8 @@ class MirrorsUsed { final override; /** - * See the documentation for [MirrorsUsed.symbols], [MirrorsUsed.targets], - * [MirrorsUsed.metaTargets] and [MirrorsUsed.override] for documentation + * See the documentation for [MirrorsUsed.symbols], [MirrorsUsed.targets], + * [MirrorsUsed.metaTargets] and [MirrorsUsed.override] for documentation * of the parameters. */ const MirrorsUsed( diff --git a/tests/lib/lib.status b/tests/lib/lib.status index e7b13042192..95989835543 100644 --- a/tests/lib/lib.status +++ b/tests/lib/lib.status @@ -105,6 +105,18 @@ mirrors/variable_is_const_test/none: RuntimeError # Issue 14671 mirrors/raw_type_test/01: RuntimeError # Issue 6490 mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589 mirrors/regress_26187_test: RuntimeError # Issue 6490 +mirrors/reflected_type_generics_test/01: Fail # Issues in reflecting generic typedefs. +mirrors/reflected_type_generics_test/02: Fail # Issues in reflecting bounded type variables. +# The following tests fail because we have disabled a test in +# `reflectClassByName`. `MirrorsUsed` leads to classes not having the +# information necessary to correctly handle these checks. +mirrors/reflected_type_generics_test/03: Fail # Issues in reflecting generic typedefs. +mirrors/reflected_type_generics_test/04: Fail # Issues in reflecting bounded type variables. +mirrors/reflected_type_generics_test/05: Fail # Issues in reflecting generic typedefs. +mirrors/reflected_type_generics_test/06: Fail # Issues in reflecting bounded type variables. + +[ $compiler == none && $unchecked ] +mirrors/reflected_type_generics_test/02: Fail, Ok # Type check for a bounded type argument. [ $compiler == dart2js && $fast_startup ] mirrors/*: Fail # mirrors not supported diff --git a/tests/lib/mirrors/mirrors_used_generic_types_test.dart b/tests/lib/mirrors/mirrors_used_generic_types_test.dart new file mode 100644 index 00000000000..59622149ac2 --- /dev/null +++ b/tests/lib/mirrors/mirrors_used_generic_types_test.dart @@ -0,0 +1,28 @@ +// Copyright (c) 2017, 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 Test; + +@MirrorsUsed(targets: const ["Test"]) +import 'dart:mirrors'; +import 'dart:async'; + +import 'package:expect/expect.dart'; + +class A { + // Because of the `mirrors-used` annotation, the types `List` and `Future` + // are not reflectable. + // However, we still need to be able to create a Mirror for them, when we + // create a mirror for `foo`. In particular, it must be able to create a + // mirror, even though there are generic types. + List foo(Future x) { + return null; + } +} + +void main() { + var m = reflect(new A()).type.instanceMembers[#foo]; + Expect.equals(#List, m.returnType.simpleName); + Expect.equals(#Future, m.parameters[0].type.simpleName); +} diff --git a/tests/lib/mirrors/reflected_type_generics_test.dart b/tests/lib/mirrors/reflected_type_generics_test.dart new file mode 100644 index 00000000000..f10425c4337 --- /dev/null +++ b/tests/lib/mirrors/reflected_type_generics_test.dart @@ -0,0 +1,99 @@ +// Copyright (c) 2016, 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 test.reflected_type_generics_test; + +@MirrorsUsed(targets: "test.reflected_type_generics_test") +import 'dart:mirrors'; + +import 'package:expect/expect.dart'; + +import 'reflected_type_helper.dart'; + +class A {} + +class P {} + +class B extends A

{} + +class C {} + +class D extends A {} + +class E extends C {} + +class F {} + +typedef bool Predicate(T arg); + +class FBounded {} + +class Helper { + Type get param => T; +} + +class Mixin {} + +class Composite extends Object with Mixin {} + +main() { + // "Happy" paths: + expectReflectedType(reflectType(A, [P]), new A

().runtimeType); + expectReflectedType(reflectType(C, [B, P]), new C().runtimeType); + expectReflectedType(reflectType(D, [P]), new D

().runtimeType); + expectReflectedType(reflectType(E, [P]), new E

().runtimeType); + expectReflectedType( + reflectType(FBounded, [FBounded]), new FBounded().runtimeType); + + var predicateHelper = new Helper>(); + expectReflectedType(reflectType(Predicate, [P]), predicateHelper.param); /// 01: ok + var composite = new Composite(); + expectReflectedType(reflectType(Composite, [P, int]), composite.runtimeType); + + // Edge cases: + Expect.throws( + () => reflectType(P, []), + (e) => e is ArgumentError && e.invalidValue is List, + "Should throw an ArgumentError if reflecting not a generic class with " + "empty list of type arguments"); + Expect.throws( /// 03: ok + () => reflectType(P, [B]), /// 03: continued + (e) => e is Error, /// 03: continued + "Should throw an ArgumentError if reflecting not a generic class with " /// 03: continued + "some type arguments"); /// 03: continued + Expect.throws( + () => reflectType(A, []), + (e) => e is ArgumentError && e.invalidValue is List, + "Should throw an ArgumentError if type argument list is empty for a " + "generic class"); + Expect.throws( /// 04: ok + () => reflectType(A, [P, B]), /// 04: continued + (e) => e is ArgumentError && e.invalidValue is List, /// 04: continued + "Should throw an ArgumentError if number of type arguments is not " /// 04: continued + "correct"); /// 04: continued + Expect.throws(() => reflectType(B, [P]), (e) => e is Error, /// 05: ok + "Should throw an ArgumentError for non-generic class extending " /// 05: continued + "generic one"); /// 05: continued + Expect.throws( + () => reflectType(A, ["non-type"]), + (e) => e is ArgumentError && e.invalidValue is List, + "Should throw an ArgumentError when any of type arguments is not a Type"); + Expect.throws( /// 06: ok + () => reflectType(A, [P, B]), /// 06: continued + (e) => e is ArgumentError && e.invalidValue is List, /// 06: continued + "Should throw an ArgumentError if number of type arguments is not correct " /// 06: continued + "for generic extending another generic"); /// 06: continued + Expect.throws( + () => reflectType(reflectType(F).typeVariables[0].reflectedType, [int])); + Expect.throws(() => reflectType(FBounded, [int])); /// 02: ok + var boundedType = + reflectType(FBounded).typeVariables[0].upperBound.reflectedType; + Expect.throws(() => reflectType(boundedType, [int])); /// 02: ok + Expect.throws(() => reflectType(Composite, [int, int])); /// 02: ok + + // Instantiation of a generic class preserves type information: + ClassMirror m = reflectType(A, [P]) as ClassMirror; + var instance = m.newInstance(const Symbol(""), []).reflectee; + Expect.equals(new A

().runtimeType, instance.runtimeType); +} diff --git a/tests/lib/mirrors/reflected_type_helper.dart b/tests/lib/mirrors/reflected_type_helper.dart index e973854b905..bc47152df19 100644 --- a/tests/lib/mirrors/reflected_type_helper.dart +++ b/tests/lib/mirrors/reflected_type_helper.dart @@ -4,6 +4,7 @@ library test.reflected_type_helper; +@MirrorsUsed(targets: "test.reflected_type_helper") import 'dart:mirrors'; import 'package:expect/expect.dart';