Skip to content

Instantly share code, notes, and snippets.

@eernstg
Last active November 7, 2017 08:29
Show Gist options
  • Save eernstg/15b6b8590691f66877e7cfe25efb97d1 to your computer and use it in GitHub Desktop.
Save eernstg/15b6b8590691f66877e7cfe25efb97d1 to your computer and use it in GitHub Desktop.
A patch for reflectable (branch use_build) adding a naive and probably still buggy ability to handle some actual type arguments
diff --git a/reflectable/lib/mirrors.dart b/reflectable/lib/mirrors.dart
index 8d3cd64..09ece0e 100644
--- a/reflectable/lib/mirrors.dart
+++ b/reflectable/lib/mirrors.dart
@@ -719,6 +719,17 @@ abstract class TypeMirror implements DeclarationMirror {
/// [TypeRelationsCapability].
List<TypeMirror> get typeArguments;
+ /// An immutable list with [Type] values for the actual type arguments
+ /// of this type.
+ ///
+ /// If the reflectee is an invocation of a generic class,
+ /// the type arguments are the bindings of its type parameters.
+ /// If the reflectee is the original declaration of a generic class,
+ /// it has no type arguments and this method returns an empty list.
+ /// If the reflectee is not generic, then
+ /// it has no type arguments and this method returns an empty list.
+ List<Type> get reflectedTypeArguments;
+
/// Is this the original declaration of this type?
///
/// For most classes, they are their own original declaration. For
diff --git a/reflectable/lib/src/reflectable_transformer_based.dart b/reflectable/lib/src/reflectable_transformer_based.dart
index 82d20ef..eeb9fec 100644
--- a/reflectable/lib/src/reflectable_transformer_based.dart
+++ b/reflectable/lib/src/reflectable_transformer_based.dart
@@ -142,6 +142,7 @@ class ReflectorData {
yield typeMirror;
}
}
+
_typeToClassMirrorCache = new Map<Type, ClassMirror>.fromIterables(
types.sublist(0, supportedClassCount), classMirrors());
}
@@ -157,7 +158,7 @@ class ReflectorData {
if (classMirror is GenericClassMirrorImpl) {
if (classMirror._isGenericRuntimeTypeOf(instance)) {
return _createInstantiatedGenericClass(
- classMirror, instance.runtimeType);
+ classMirror, instance.runtimeType, null);
}
}
}
@@ -644,6 +645,7 @@ abstract class ClassMirrorBase extends _DataCaching implements ClassMirror {
throw reflectableNoSuchMethodError(
reflectedType, memberName, positionalArguments, namedArguments);
}
+
_StaticGetter getter = _getters[memberName];
if (getter == null) fail();
if (!_checkStaticParameterListShape(
@@ -888,7 +890,18 @@ class NonGenericClassMirrorImpl extends ClassMirrorBase {
"Attempt to get `typeArguments` for `$qualifiedName` "
"without `typeRelationsCapability`");
}
- return <TypeMirror>[];
+ return const <TypeMirror>[];
+ }
+
+ @override
+ List<Type> get reflectedTypeArguments {
+ if (!_supportsTypeRelations(_reflector) ||
+ !_supportsReflectedType(_reflector)) {
+ throw new NoSuchCapabilityError(
+ "Attempt to get `typeArguments` for `$qualifiedName` "
+ "without `typeRelationsCapability` or `reflectedTypeCapability`");
+ }
+ return const <Type>[];
}
@override
@@ -898,7 +911,7 @@ class NonGenericClassMirrorImpl extends ClassMirrorBase {
"Attempt to evaluate `typeVariables` for `$qualifiedName` "
"without `typeRelationsCapability`");
}
- return <TypeVariableMirror>[];
+ return const <TypeVariableMirror>[];
}
@override
@@ -999,7 +1012,24 @@ class GenericClassMirrorImpl extends ClassMirrorBase {
"Attempt to get `typeArguments` for `$qualifiedName` "
"without `typeRelationsCapability`");
}
- return <TypeMirror>[];
+ // This mirror represents the original declaration, so no actual type
+ // arguments have been passed. By convention we represent this situation
+ // by returning the empty list, as documented in mirrors.dart.
+ return const <TypeMirror>[];
+ }
+
+ @override
+ List<Type> get reflectedTypeArguments {
+ if (!_supportsTypeRelations(_reflector) ||
+ !_supportsReflectedType(_reflector)) {
+ throw new NoSuchCapabilityError(
+ "Attempt to get `reflectedTypeArguments` for `$qualifiedName` "
+ "without `typeRelationsCapability` or `reflectedTypeCapability`");
+ }
+ // This mirror represents the original declaration, so no actual type
+ // arguments have been passed. By convention we represent this situation
+ // by returning the empty list, as documented in mirrors.dart.
+ return const <Type>[];
}
// The type variables declared by this generic class, in declaration order.
@@ -1078,6 +1108,10 @@ class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
final GenericClassMirrorImpl _originalDeclaration;
final Type _reflectedType;
+ // `_reflectedTypeArguments == null` means that the given situation is
+ // not yet supported for method `reflectedTypeArguments`.
+ final List<Type> _reflectedTypeArguments;
+
InstantiatedGenericClassMirrorImpl(
String simpleName,
String qualifiedName,
@@ -1097,7 +1131,8 @@ class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
List<Object> metadata,
Map<String, int> parameterListShapes,
this._originalDeclaration,
- this._reflectedType)
+ this._reflectedType,
+ this._reflectedTypeArguments)
: super(
simpleName,
qualifiedName,
@@ -1128,6 +1163,20 @@ class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
throw unimplementedError("typeArguments");
}
+ @override
+ List<Type> get reflectedTypeArguments {
+ if (!_supportsTypeRelations(_reflector) ||
+ !_supportsReflectedType(_reflector)) {
+ throw new NoSuchCapabilityError(
+ "Attempt to get `reflectedTypeArguments` for `$qualifiedName` "
+ "without `typeRelationsCapability` or `reflectedTypeCapability`");
+ }
+ if (_reflectedTypeArguments == null) {
+ throw unimplementedError("reflectedTypeArguments");
+ }
+ return _reflectedTypeArguments;
+ }
+
@override
List<TypeVariableMirror> get typeVariables =>
originalDeclaration.typeVariables;
@@ -1208,7 +1257,9 @@ class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
}
InstantiatedGenericClassMirrorImpl _createInstantiatedGenericClass(
- GenericClassMirrorImpl genericClassMirror, Type reflectedType) {
+ GenericClassMirrorImpl genericClassMirror,
+ Type reflectedType,
+ List<Type> reflectedTypeArguments) {
// TODO(eernst) implement: Pass a representation of type arguments to this
// method, and create an instantiated generic class which includes that
// information.
@@ -1231,7 +1282,8 @@ InstantiatedGenericClassMirrorImpl _createInstantiatedGenericClass(
genericClassMirror._metadata,
genericClassMirror._parameterListShapes,
genericClassMirror,
- reflectedType);
+ reflectedType,
+ reflectedTypeArguments);
}
class TypeVariableMirrorImpl extends _DataCaching
@@ -1315,7 +1367,18 @@ class TypeVariableMirrorImpl extends _DataCaching
"Attempt to get `typeArguments` for `$qualifiedName` "
"without `typeRelationsCapability`");
}
- return <TypeMirror>[];
+ return const <TypeMirror>[];
+ }
+
+ @override
+ List<Type> get reflectedTypeArguments {
+ if (!_supportsTypeRelations(_reflector) ||
+ !_supportsReflectedType(_reflector)) {
+ throw new NoSuchCapabilityError(
+ "Attempt to get `reflectedTypeArguments` for `$qualifiedName` "
+ "without `typeRelationsCapability` or `reflectedTypeCapability`");
+ }
+ return const <Type>[];
}
@override
@@ -1598,6 +1661,13 @@ class MethodMirrorImpl extends _DataCaching implements MethodMirror {
/// `dynamicReflectedReturnType`.
final int _dynamicReflectedReturnTypeIndex;
+ /// The [Type] values of the actual type arguments of the return type of this
+ /// method, if supported. If the actual type arguments are not supported,
+ /// [_reflectedTypeArgumentsOfReturnType] is null. The actual type arguments
+ /// are not supported if they are not compile-time constant, e.g., if such an
+ /// actual type argument is a type variable declared by the enclosing class.
+ final List<Type> _reflectedTypeArgumentsOfReturnType;
+
/// The indices of the [ParameterMirror]s describing the formal parameters
/// of this method.
final List<int> _parameterIndices;
@@ -1617,6 +1687,7 @@ class MethodMirrorImpl extends _DataCaching implements MethodMirror {
this._returnTypeIndex,
this._reflectedReturnTypeIndex,
this._dynamicReflectedReturnTypeIndex,
+ this._reflectedTypeArgumentsOfReturnType,
this._parameterIndices,
this._reflector,
this._metadata);
@@ -1730,8 +1801,8 @@ class MethodMirrorImpl extends _DataCaching implements MethodMirror {
if (_hasVoidReturnType) return new VoidMirrorImpl();
if (_hasClassReturnType) {
return _hasGenericReturnType
- ? _createInstantiatedGenericClass(
- _data.typeMirrors[_returnTypeIndex], null)
+ ? _createInstantiatedGenericClass(_data.typeMirrors[_returnTypeIndex],
+ null, _reflectedTypeArgumentsOfReturnType)
: _data.typeMirrors[_returnTypeIndex];
}
throw unreachableError("Unexpected kind of returnType");
@@ -1997,7 +2068,8 @@ class ImplicitSetterMirrorImpl extends ImplicitAccessorMirrorImpl {
_variableMirror._classMirrorIndex,
_variableMirror._reflectedTypeIndex,
_variableMirror._dynamicReflectedTypeIndex,
- <Object>[],
+ _variableMirror._reflectedTypeArguments,
+ const <Object>[],
null,
null)
];
@@ -2022,6 +2094,7 @@ abstract class VariableMirrorBase extends _DataCaching
final int _classMirrorIndex;
final int _reflectedTypeIndex;
final int _dynamicReflectedTypeIndex;
+ final List<Type> _reflectedTypeArguments;
final List<Object> _metadata;
VariableMirrorBase(
@@ -2032,6 +2105,7 @@ abstract class VariableMirrorBase extends _DataCaching
this._classMirrorIndex,
this._reflectedTypeIndex,
this._dynamicReflectedTypeIndex,
+ this._reflectedTypeArguments,
this._metadata);
int get kind => constants.kindFromEncoding(_descriptor);
@@ -2085,7 +2159,8 @@ abstract class VariableMirrorBase extends _DataCaching
return _isGenericType
? _createInstantiatedGenericClass(
_data.typeMirrors[_classMirrorIndex],
- hasReflectedType ? reflectedType : null)
+ hasReflectedType ? reflectedType : null,
+ _reflectedTypeArguments)
: _data.typeMirrors[_classMirrorIndex];
}
throw unreachableError("Unexpected kind of type");
@@ -2152,9 +2227,18 @@ class VariableMirrorImpl extends VariableMirrorBase {
int classMirrorIndex,
int reflectedTypeIndex,
int dynamicReflectedTypeIndex,
+ List<Type> reflectedTypeArguments,
List<Object> metadata)
- : super(name, descriptor, ownerIndex, reflectable, classMirrorIndex,
- reflectedTypeIndex, dynamicReflectedTypeIndex, metadata);
+ : super(
+ name,
+ descriptor,
+ ownerIndex,
+ reflectable,
+ classMirrorIndex,
+ reflectedTypeIndex,
+ dynamicReflectedTypeIndex,
+ reflectedTypeArguments,
+ metadata);
// Note that the corresponding implementation of [hashCode] is inherited from
// [VariableMirrorBase].
@@ -2213,11 +2297,12 @@ class ParameterMirrorImpl extends VariableMirrorBase
int classMirrorIndex,
int reflectedTypeIndex,
int dynamicReflectedTypeIndex,
+ List<Type> reflectedTypeArguments,
List<Object> metadata,
this._defaultValue,
this._nameSymbol)
: super(name, descriptor, ownerIndex, reflectable, classMirrorIndex,
- reflectedTypeIndex, dynamicReflectedTypeIndex, metadata);
+ reflectedTypeIndex, dynamicReflectedTypeIndex, reflectedTypeArguments, metadata);
// Note that the corresponding implementation of [hashCode] is inherited from
// [VariableMirrorBase].
@@ -2250,10 +2335,13 @@ class DynamicMirrorImpl implements TypeMirror {
// TODO(eernst) implement: do as in 'dart:mirrors'.
@override
- List<TypeVariableMirror> get typeVariables => <TypeVariableMirror>[];
+ List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
@override
- List<TypeMirror> get typeArguments => <TypeMirror>[];
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+ @override
+ List<Type> get reflectedTypeArguments => const <Type>[];
// TODO(eernst) implement: do as in 'dart:mirrors'.
@override
@@ -2312,10 +2400,13 @@ class VoidMirrorImpl implements TypeMirror {
// TODO(eernst) implement: do as in 'dart:mirrors'.
@override
- List<TypeVariableMirror> get typeVariables => <TypeVariableMirror>[];
+ List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
+
+ @override
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
@override
- List<TypeMirror> get typeArguments => <TypeMirror>[];
+ List<Type> get reflectedTypeArguments => const <Type>[];
// TODO(eernst) implement: do as in 'dart:mirrors'.
@override
@@ -2467,8 +2558,8 @@ bool _isSetterName(String name) => name.endsWith("=");
String _getterNameToSetterName(String name) => name + "=";
bool _supportsType(ReflectableImpl reflector) {
- return reflector.capabilities.any(
- (ReflectCapability capability) => capability is TypeCapability);
+ return reflector.capabilities
+ .any((ReflectCapability capability) => capability is TypeCapability);
}
bool _supportsTypeRelations(ReflectableImpl reflector) {
diff --git a/reflectable/lib/src/transformer_implementation.dart b/reflectable/lib/src/transformer_implementation.dart
index 568d65f..4b7f01b 100644
--- a/reflectable/lib/src/transformer_implementation.dart
+++ b/reflectable/lib/src/transformer_implementation.dart
@@ -1110,6 +1110,74 @@ class _ReflectorDomain {
descriptor & constants.classTypeAttribute != 0);
}
+ bool _hasSupportedReflectedTypeArguments(DartType dartType) {
+ if (dartType is ParameterizedType) {
+ for (DartType typeArgument in dartType.typeArguments) {
+ if (!_hasSupportedReflectedTypeArguments(typeArgument)) return false;
+ }
+ return true;
+ } else if (dartType is TypeParameterType) {
+ return false;
+ } else {
+ throw unimplementedError(
+ '`reflectedTypeArguments` where an actual type argument '
+ '(possibly nested) is $dartType');
+ }
+ }
+
+ String _computeReflectedTypeArguments(
+ DartType dartType, _ImportCollector importCollector) {
+ if (dartType is ParameterizedType) {
+ List<TypeParameterElement> typeParameters = dartType.typeParameters;
+ if (typeParameters.length == 0) {
+ // We have no formal type parameters, so there cannot be any actual
+ // type arguments.
+ return 'const <Type>[]';
+ } else {
+ // We have some formal type parameters: `dartType` is a generic class.
+ List<DartType> typeArguments = dartType.typeArguments;
+ // This method is called with variable/parameter type annotations and
+ // function return types, and they denote instantiated generic classes
+ // rather than "original" generic classes; so they do have actual type
+ // arguments when there are formal type parameters.
+ assert(typeArguments.length == typeParameters.length);
+
+ bool isSupported = true;
+ // Use `toList` in order to force execution of the following, such that
+ // the side effect on `isSupported` occurs before `if (isSupported)`.
+ List<String> typesCodeList =
+ typeArguments.map((DartType actualTypeArgument) {
+ if (actualTypeArgument is InterfaceType) {
+ if (_hasSupportedReflectedTypeArguments(actualTypeArgument)) {
+ return _dynamicTypeCodeOfClass(
+ actualTypeArgument.element, importCollector);
+ } else {
+ isSupported = false;
+ return null;
+ }
+ } else if (actualTypeArgument is TypeParameterType) {
+ isSupported = false;
+ return null;
+ } else {
+ // TODO(eernst) clarify: Are `dynamic` et al `InterfaceType`s?
+ // Otherwise this means "a case that we have not it considered".
+ throw unimplementedError(
+ '`reflectedTypeArguments` where one actual type argument'
+ ' is $actualTypeArgument');
+ }
+ }).toList();
+ if (isSupported) {
+ return _formatAsList("Type", typesCodeList);
+ } else {
+ return 'null';
+ }
+ }
+ } else {
+ // If the type is not a ParameterizedType then it has no type arguments.
+ return 'const <Type>[]';
+ }
+ }
+
int _computeReturnTypeIndex(ExecutableElement element, int descriptor) {
if (!_capabilities._impliesTypes) return constants.NO_CAPABILITY_INDEX;
int result = _computeTypeIndexBase(
@@ -1217,12 +1285,10 @@ class _ReflectorDomain {
});
String declarationsCode = _capabilities._impliesDeclarations
- ? _formatAsConstList(
- "int",
- () sync* {
- yield* fieldsIndices;
- yield* methodsIndices;
- }())
+ ? _formatAsConstList("int", () sync* {
+ yield* fieldsIndices;
+ yield* methodsIndices;
+ }())
: "const <int>[${constants.NO_CAPABILITY_INDEX}]";
// All instance members belong to the behavioral interface, so they
@@ -1500,6 +1566,11 @@ class _ReflectorDomain {
int descriptor = _declarationDescriptor(element);
int returnTypeIndex = _computeReturnTypeIndex(element, descriptor);
int ownerIndex = _computeOwnerIndex(element, descriptor);
+ String reflectedTypeArgumentsOfReturnType = 'null';
+ if (reflectedTypeRequested && _capabilities._impliesTypeRelations) {
+ reflectedTypeArgumentsOfReturnType =
+ _computeReflectedTypeArguments(element.returnType, importCollector);
+ }
String parameterIndicesCode = _formatAsConstList("int",
element.parameters.map((ParameterElement parameterElement) {
return parameters.indexOf(parameterElement);
@@ -1520,7 +1591,8 @@ class _ReflectorDomain {
: null;
return 'new r.MethodMirrorImpl(r"${element.name}", $descriptor, '
'$ownerIndex, $returnTypeIndex, $reflectedReturnTypeIndex, '
- '$dynamicReflectedReturnTypeIndex, $parameterIndicesCode, '
+ '$dynamicReflectedReturnTypeIndex, '
+ '$reflectedTypeArgumentsOfReturnType, $parameterIndicesCode, '
'${_constConstructionCode(importCollector, logger)}, $metadataCode)';
}
}
@@ -1544,6 +1616,11 @@ class _ReflectorDomain {
? _dynamicTypeCodeIndex(
element.type, classes, reflectedTypes, reflectedTypesOffset)
: constants.NO_CAPABILITY_INDEX;
+ String reflectedTypeArguments = 'null';
+ if (reflectedTypeRequested && _capabilities._impliesTypeRelations) {
+ reflectedTypeArguments =
+ _computeReflectedTypeArguments(element.type, importCollector);
+ }
String metadataCode;
if (_capabilities._supportsMetadata) {
metadataCode = _extractMetadataCode(
@@ -1556,7 +1633,8 @@ class _ReflectorDomain {
return 'new r.VariableMirrorImpl(r"${element.name}", $descriptor, '
'$ownerIndex, ${_constConstructionCode(importCollector, logger)}, '
'$classMirrorIndex, $reflectedTypeIndex, '
- '$dynamicReflectedTypeIndex, $metadataCode)';
+ '$dynamicReflectedTypeIndex, $reflectedTypeArguments, '
+ '$metadataCode)';
}
String _fieldMirrorCode(
@@ -1577,6 +1655,11 @@ class _ReflectorDomain {
? _dynamicTypeCodeIndex(
element.type, classes, reflectedTypes, reflectedTypesOffset)
: constants.NO_CAPABILITY_INDEX;
+ String reflectedTypeArguments = 'null';
+ if (reflectedTypeRequested && _capabilities._impliesTypeRelations) {
+ reflectedTypeArguments =
+ _computeReflectedTypeArguments(element.type, importCollector);
+ }
String metadataCode;
if (_capabilities._supportsMetadata) {
metadataCode = _extractMetadataCode(
@@ -1589,7 +1672,7 @@ class _ReflectorDomain {
return 'new r.VariableMirrorImpl(r"${element.name}", $descriptor, '
'$ownerIndex, ${_constConstructionCode(importCollector, logger)}, '
'$classMirrorIndex, $reflectedTypeIndex, '
- '$dynamicReflectedTypeIndex, $metadataCode)';
+ '$dynamicReflectedTypeIndex, $reflectedTypeArguments, $metadataCode)';
}
/// Returns the index into `ReflectorData.types` of the [Type] object
@@ -1932,6 +2015,11 @@ class _ReflectorDomain {
? _dynamicTypeCodeIndex(
element.type, classes, reflectedTypes, reflectedTypesOffset)
: constants.NO_CAPABILITY_INDEX;
+ String reflectedTypeArguments = 'null';
+ if (reflectedTypeRequested && _capabilities._impliesTypeRelations) {
+ reflectedTypeArguments =
+ _computeReflectedTypeArguments(element.type, importCollector);
+ }
String metadataCode = "null";
if (_capabilities._supportsMetadata) {
FormalParameter node = element.computeNode();
@@ -1956,7 +2044,8 @@ class _ReflectorDomain {
return 'new r.ParameterMirrorImpl(r"${element.name}", $descriptor, '
'$ownerIndex, ${_constConstructionCode(importCollector, logger)}, '
'$classMirrorIndex, $reflectedTypeIndex, $dynamicReflectedTypeIndex, '
- '$metadataCode, $defaultValueCode, $parameterSymbolCode)';
+ '$reflectedTypeArguments, $metadataCode, $defaultValueCode, '
+ '$parameterSymbolCode)';
}
}
@@ -2052,8 +2141,10 @@ class _SuperclassFixedPoint extends FixedPoint<ClassElement> {
if (classElement.supertype == null) return false;
return helper(classElement.supertype.element, false);
}
+
return upwardsClosureBounds.keys.any(isSuperclassOfClassElement);
}
+
return upwardsClosureBounds.isEmpty || helper(classElement, true);
}
}
@@ -2390,8 +2481,10 @@ class _ClassDomain {
if (member.isPrivate) return;
// If [member] is a synthetic accessor created from a field, search for
// the metadata on the original field.
- List<ElementAnnotation> metadata = (member is PropertyAccessorElement &&
- member.isSynthetic) ? member.variable.metadata : member.metadata;
+ List<ElementAnnotation> metadata =
+ (member is PropertyAccessorElement && member.isSynthetic)
+ ? member.variable.metadata
+ : member.metadata;
List<ElementAnnotation> getterMetadata = null;
if (_reflectorDomain._capabilities._impliesCorrespondingSetters &&
member is PropertyAccessorElement &&
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment