Chromium Code Reviews| 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); |
| } |