Reapply "reflectType() dynamic type arguments support (#26012)"
This was a pull request: 8a8033a417
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 .
This commit is contained in:
@@ -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 ||
|
||||
|
||||
@@ -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<LibraryElement, List<MirrorUsage>> usageMap) {
|
||||
Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>();
|
||||
usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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<ClassMirror> _declarationCache = new Expando("ClassMirror");
|
||||
static Expando<TypeMirror> _instantiationCache = new Expando("TypeMirror");
|
||||
@@ -1661,7 +1663,10 @@ class _Mirrors {
|
||||
return classMirror;
|
||||
}
|
||||
|
||||
static TypeMirror reflectType(Type key) {
|
||||
static TypeMirror reflectType(Type key, [List<Type> 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<Type> typeArguments) {
|
||||
if (typeArguments.isEmpty) {
|
||||
throw new ArgumentError.value(
|
||||
typeArguments, 'typeArguments', 'Type arguments list cannot be empty.');
|
||||
}
|
||||
return instantiateGenericType(key, typeArguments.toList(growable: false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Type> typeArguments]) {
|
||||
return _Mirrors.reflectType(key, typeArguments);
|
||||
}
|
||||
|
||||
@patch class MirrorSystem {
|
||||
|
||||
@@ -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) \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,9 +43,9 @@ ClassMirror reflectClass(Type key) {
|
||||
}
|
||||
|
||||
@patch
|
||||
TypeMirror reflectType(Type key) {
|
||||
TypeMirror reflectType(Type key, [List<Type> typeArguments]) {
|
||||
if (key == dynamic) {
|
||||
return currentMirrorSystem().dynamicType;
|
||||
}
|
||||
return js.reflectType(key);
|
||||
return js.reflectType(key, typeArguments);
|
||||
}
|
||||
|
||||
@@ -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<Type> 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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<int> foo(Future<int> 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);
|
||||
}
|
||||
@@ -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<T> {}
|
||||
|
||||
class P {}
|
||||
|
||||
class B extends A<P> {}
|
||||
|
||||
class C<K, V> {}
|
||||
|
||||
class D<T> extends A<T> {}
|
||||
|
||||
class E<K> extends C<K, int> {}
|
||||
|
||||
class F<G> {}
|
||||
|
||||
typedef bool Predicate<T>(T arg);
|
||||
|
||||
class FBounded<S extends FBounded> {}
|
||||
|
||||
class Helper<T> {
|
||||
Type get param => T;
|
||||
}
|
||||
|
||||
class Mixin<T extends P> {}
|
||||
|
||||
class Composite<K extends P, V> extends Object with Mixin<K> {}
|
||||
|
||||
main() {
|
||||
// "Happy" paths:
|
||||
expectReflectedType(reflectType(A, [P]), new A<P>().runtimeType);
|
||||
expectReflectedType(reflectType(C, [B, P]), new C<B, P>().runtimeType);
|
||||
expectReflectedType(reflectType(D, [P]), new D<P>().runtimeType);
|
||||
expectReflectedType(reflectType(E, [P]), new E<P>().runtimeType);
|
||||
expectReflectedType(
|
||||
reflectType(FBounded, [FBounded]), new FBounded<FBounded>().runtimeType);
|
||||
|
||||
var predicateHelper = new Helper<Predicate<P>>();
|
||||
expectReflectedType(reflectType(Predicate, [P]), predicateHelper.param); /// 01: ok
|
||||
var composite = new Composite<P, int>();
|
||||
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<P>().runtimeType, instance.runtimeType);
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
library test.reflected_type_helper;
|
||||
|
||||
@MirrorsUsed(targets: "test.reflected_type_helper")
|
||||
import 'dart:mirrors';
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user