Index: pkg/compiler/lib/src/resolution/type_resolver.dart |
diff --git a/pkg/compiler/lib/src/resolution/type_resolver.dart b/pkg/compiler/lib/src/resolution/type_resolver.dart |
index 3acc024e5fe5b0445a112cae6d98c6e5d5bb4c13..002afe0ad1c7eb54ff05cf8c823dd597e35bc4ef 100644 |
--- a/pkg/compiler/lib/src/resolution/type_resolver.dart |
+++ b/pkg/compiler/lib/src/resolution/type_resolver.dart |
@@ -27,6 +27,16 @@ import 'registry.dart' show ResolutionRegistry; |
import 'resolution_common.dart' show MappingVisitor; |
import 'scope.dart' show Scope; |
+class _FormalsTypeResolutionResult { |
+ final List<DartType> requiredTypes; |
+ final List<DartType> orderedTypes; |
+ final List<String> names; |
+ final List<DartType> nameTypes; |
+ |
+ _FormalsTypeResolutionResult( |
+ this.requiredTypes, this.orderedTypes, this.names, this.nameTypes); |
+} |
+ |
class TypeResolver { |
final Resolution resolution; |
@@ -65,6 +75,153 @@ class TypeResolver { |
DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node, |
{bool malformedIsError: false, bool deferredIsMalformed: true}) { |
+ return _resolveTypeAnnotation( |
+ visitor, node, const [], malformedIsError: malformedIsError, |
+ deferredIsMalformed: deferredIsMalformed); |
+ } |
+ |
+ // TODO(floitsch): the [visibleTypeParameterNames] is a hack to put |
+ // type parameters in scope for the nested types. |
+ // |
+ // For example, in the following example, the generic type "A" would be stored |
+ // in `visibleTypeParameterNames`. |
+ // `typedef F = Function(List<A> Function<A>(A x))`. |
+ // |
+ // They are resolved to `dynamic` until dart2js supports generic methods. |
+ DartType _resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node, |
+ List<List<String>> visibleTypeParameterNames, |
+ {bool malformedIsError: false, bool deferredIsMalformed: true}) { |
+ |
+ if (node.asNominalTypeAnnotation() != null) { |
+ return resolveNominalTypeAnnotation( |
+ visitor, node, |
+ visibleTypeParameterNames, |
+ malformedIsError: malformedIsError, |
+ deferredIsMalformed: deferredIsMalformed); |
+ } |
+ assert(node.asFunctionTypeAnnotation() != null); |
+ return _resolveFunctionTypeAnnotation( |
+ visitor, node, visibleTypeParameterNames, |
+ malformedIsError: malformedIsError, |
+ deferredIsMalformed: deferredIsMalformed); |
+ } |
+ |
+ /// Resolves the types of a parameter list. |
+ /// |
+ /// This function does not accept "inline" function types. For example |
+ /// `foo(int bar(String x))` is not accepted. |
+ /// |
+ /// However, it does work with nested generalized function types: |
+ /// `foo(int Function(String) x)`. |
+ _FormalsTypeResolutionResult _resolveFormalTypes( |
+ MappingVisitor visitor, NodeList formals, |
+ List<List<String>> visibleTypeParameterNames) { |
+ |
+ DartType resolvePositionalType(VariableDefinitions node) { |
+ return _resolveTypeAnnotation( |
+ visitor, node.type, visibleTypeParameterNames); |
+ } |
+ |
+ void fillNamedTypes( |
+ NodeList namedFormals, List<String> names, List<DartType> types) { |
+ List<Node> nodes = namedFormals.nodes.toList(growable: false); |
+ |
+ // Sort the named arguments first. |
+ nodes.sort((node1, node2) { |
+ VariableDefinitions a = node1; |
+ VariableDefinitions b = node2; |
+ assert(a.definitions.nodes.tail.isEmpty); |
+ assert(b.definitions.nodes.tail.isEmpty); |
+ return a.definitions.nodes.head.asIdentifier().source.compareTo( |
+ b.definitions.nodes.head.asIdentifier().source); |
+ }); |
+ |
+ for (VariableDefinitions node in nodes) { |
+ String name = node.definitions.nodes.head.asIdentifier().source; |
+ DartType type = node.type == null |
+ ? const DynamicType() |
+ : _resolveTypeAnnotation( |
+ visitor, node.type, visibleTypeParameterNames); |
+ names.add(name); |
+ types.add(type); |
+ } |
+ } |
+ |
+ List<DartType> requiredTypes = <DartType>[]; |
+ NodeList optionalFormals = null; |
+ for (Link<Node> link = formals.nodes; !link.isEmpty; link = link.tail) { |
+ if (link.tail.isEmpty && link.head is NodeList) { |
+ optionalFormals = link.head; |
+ break; |
+ } |
+ requiredTypes.add(resolvePositionalType(link.head)); |
+ } |
+ |
+ |
+ List<DartType> orderedTypes = const <DartType>[]; |
+ List<String> names = const <String>[]; |
+ List<DartType> nameTypes = const <DartType>[]; |
Johnni Winther
2017/01/02 12:46:53
[nameTypes] -> [namedTypes]
floitsch
2017/01/02 13:48:48
Done.
|
+ |
+ if (optionalFormals != null) { |
+ // This must be a list of optional arguments. |
+ String value = optionalFormals.beginToken.stringValue; |
+ if ((!identical(value, '[')) && (!identical(value, '{'))) { |
+ reporter.internalError(optionalFormals, "expected optional parameters"); |
+ } |
+ bool optionalParametersAreNamed = (identical(value, '{')); |
+ |
+ if (optionalParametersAreNamed) { |
+ names = <String>[]; |
+ nameTypes = <DartType>[]; |
+ fillNamedTypes(optionalFormals, names, nameTypes); |
+ } else { |
+ orderedTypes = <DartType>[]; |
+ for (Link<Node> link = optionalFormals.nodes; |
+ !link.isEmpty; |
+ link = link.tail) { |
+ orderedTypes.add(resolvePositionalType(link.head)); |
+ } |
+ } |
+ } |
+ return new _FormalsTypeResolutionResult( |
+ requiredTypes, orderedTypes, names, nameTypes); |
+ } |
+ |
+ FunctionType _resolveFunctionTypeAnnotation(MappingVisitor visitor, |
+ FunctionTypeAnnotation node, |
+ List<List<String>> visibleTypeParameterNames, |
+ {malformedIsError: false, bool deferredIsMalformed: true}) { |
Johnni Winther
2017/01/02 12:46:53
`malformedIsError` -> `bool malformedIsError`.
floitsch
2017/01/02 13:48:48
Done.
|
+ |
+ assert(visibleTypeParameterNames != null); |
+ |
+ if (node.typeParameters != null) { |
+ List<String> newTypeNames = node.typeParameters.map((TypeVariable node) { |
+ return node.name.asIdentifier().source; |
+ }).toList(); |
+ visibleTypeParameterNames = |
+ visibleTypeParameterNames.toList()..add(newTypeNames); |
+ } |
+ |
+ DartType returnType = node.returnType == null |
+ ? const DynamicType() |
+ : _resolveTypeAnnotation(visitor, node.returnType, |
+ visibleTypeParameterNames); |
+ var formalTypes = |
+ _resolveFormalTypes(visitor, node.formals, visibleTypeParameterNames); |
+ var result = new FunctionType.generalized( |
+ returnType, |
+ formalTypes.requiredTypes, |
+ formalTypes.orderedTypes, |
+ formalTypes.names, |
+ formalTypes.nameTypes); |
+ visitor.registry.useType(node, result); |
+ return result; |
+ } |
+ |
+ DartType resolveNominalTypeAnnotation(MappingVisitor visitor, |
+ NominalTypeAnnotation node, |
+ List<List<String>> visibleTypeParameterNames, |
+ {malformedIsError: false, bool deferredIsMalformed: true}) { |
Johnni Winther
2017/01/02 12:46:53
Ditto.
floitsch
2017/01/02 13:48:48
Done.
|
ResolutionRegistry registry = visitor.registry; |
Identifier typeName; |
@@ -72,8 +229,9 @@ class TypeResolver { |
DartType checkNoTypeArguments(DartType type) { |
List<DartType> arguments = new List<DartType>(); |
- bool hasTypeArgumentMismatch = |
- resolveTypeArguments(visitor, node, const <DartType>[], arguments); |
+ bool hasTypeArgumentMismatch = resolveTypeArguments( |
+ visitor, node, const <DartType>[], arguments, |
+ visibleTypeParameterNames); |
if (hasTypeArgumentMismatch) { |
return new MalformedType( |
new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |
@@ -105,9 +263,6 @@ class TypeResolver { |
} |
} |
- Element element = resolveTypeName(prefixName, typeName, visitor.scope, |
- deferredIsMalformed: deferredIsMalformed); |
- |
DartType reportFailureAndCreateType( |
MessageKind messageKind, Map messageArguments, |
{DartType userProvidedBadType, |
@@ -127,13 +282,33 @@ class TypeResolver { |
typeName.source, visitor.enclosingElement); |
} |
List<DartType> arguments = <DartType>[]; |
- resolveTypeArguments(visitor, node, const <DartType>[], arguments); |
+ resolveTypeArguments(visitor, node, const <DartType>[], arguments, |
+ visibleTypeParameterNames); |
return new MalformedType( |
erroneousElement, userProvidedBadType, arguments); |
} |
+ Element element; |
+ // Resolve references to type names as dynamic. |
+ // TODO(floitsch): this hackishly resolves generic function type arguments |
+ // to dynamic. |
+ if (prefixName == null && |
+ visibleTypeParameterNames.any((n) => n.contains(typeName.source))) { |
+ type = const DynamicType(); |
+ } else { |
+ element = resolveTypeName(prefixName, typeName, visitor.scope, |
+ deferredIsMalformed: deferredIsMalformed); |
+ } |
+ |
// Try to construct the type from the element. |
- if (element == null) { |
+ if (type != null) { |
+ // Already assigned to through the visibleTypeParameterNames. |
+ // Just make sure that it doesn't have type arguments. |
+ if (node.typeArguments != null) { |
+ reporter.reportWarningMessage(node.typeArguments.nodes.head, |
+ MessageKind.ADDITIONAL_TYPE_ARGUMENT); |
+ } |
+ } else if (element == null) { |
type = reportFailureAndCreateType( |
MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName}); |
} else if (element.isAmbiguous) { |
@@ -168,8 +343,9 @@ class TypeResolver { |
resolver.ensureClassWillBeResolvedInternal(cls); |
cls.computeType(resolution); |
List<DartType> arguments = <DartType>[]; |
- bool hasTypeArgumentMismatch = |
- resolveTypeArguments(visitor, node, cls.typeVariables, arguments); |
+ bool hasTypeArgumentMismatch = resolveTypeArguments( |
+ visitor, node, cls.typeVariables, arguments, |
+ visibleTypeParameterNames); |
if (hasTypeArgumentMismatch) { |
type = new BadInterfaceType( |
cls.declaration, |
@@ -192,7 +368,8 @@ class TypeResolver { |
typdef.computeType(resolution); |
List<DartType> arguments = <DartType>[]; |
bool hasTypeArgumentMismatch = resolveTypeArguments( |
- visitor, node, typdef.typeVariables, arguments); |
+ visitor, node, typdef.typeVariables, arguments, |
+ visibleTypeParameterNames); |
if (hasTypeArgumentMismatch) { |
type = new BadTypedefType(typdef, |
new TypedefType.forUserProvidedBadType(typdef, arguments)); |
@@ -236,7 +413,7 @@ class TypeResolver { |
} |
/// Checks the type arguments of [type] against the type variable bounds. |
- void checkTypeVariableBounds(TypeAnnotation node, GenericType type) { |
+ void checkTypeVariableBounds(NominalTypeAnnotation node, GenericType type) { |
void checkTypeVariableBound(_, DartType typeArgument, |
TypeVariableType typeVariable, DartType bound) { |
if (!types.isSubtype(typeArgument, bound)) { |
@@ -259,8 +436,9 @@ class TypeResolver { |
* Returns [: true :] if the number of type arguments did not match the |
* number of type variables. |
*/ |
- bool resolveTypeArguments(MappingVisitor visitor, TypeAnnotation node, |
- List<DartType> typeVariables, List<DartType> arguments) { |
+ bool resolveTypeArguments(MappingVisitor visitor, NominalTypeAnnotation node, |
+ List<DartType> typeVariables, List<DartType> arguments, |
+ List<List<String>> visibleTypeParameterNames) { |
if (node.typeArguments == null) { |
return false; |
} |
@@ -275,7 +453,8 @@ class TypeResolver { |
typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |
typeArgumentCountMismatch = true; |
} |
- DartType argType = resolveTypeAnnotation(visitor, typeArguments.head); |
+ DartType argType = _resolveTypeAnnotation( |
+ visitor, typeArguments.head, visibleTypeParameterNames); |
// TODO(karlklose): rewrite to not modify [arguments]. |
arguments.add(argType); |
} |