| 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 318e7488f429e86e8c8693d209a82407658f3935..34e5cab4dc2d1a45624868171b19b9f6f5bf6edb 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<ResolutionDartType> requiredTypes;
|
| + final List<ResolutionDartType> orderedTypes;
|
| + final List<String> names;
|
| + final List<ResolutionDartType> nameTypes;
|
| +
|
| + _FormalsTypeResolutionResult(
|
| + this.requiredTypes, this.orderedTypes, this.names, this.nameTypes);
|
| +}
|
| +
|
| class TypeResolver {
|
| final Resolution resolution;
|
|
|
| @@ -66,6 +76,154 @@ class TypeResolver {
|
| ResolutionDartType 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.
|
| + ResolutionDartType _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) {
|
| +
|
| + ResolutionDartType resolvePositionalType(VariableDefinitions node) {
|
| + return _resolveTypeAnnotation(
|
| + visitor, node.type, visibleTypeParameterNames);
|
| + }
|
| +
|
| + void fillNamedTypes(NodeList namedFormals,
|
| + List<String> names, List<ResolutionDartType> 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;
|
| + ResolutionDartType type = node.type == null
|
| + ? const ResolutionDynamicType()
|
| + : _resolveTypeAnnotation(
|
| + visitor, node.type, visibleTypeParameterNames);
|
| + names.add(name);
|
| + types.add(type);
|
| + }
|
| + }
|
| +
|
| + List<ResolutionDartType> requiredTypes = <ResolutionDartType>[];
|
| + 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<ResolutionDartType> orderedTypes = const <ResolutionDartType>[];
|
| + List<String> names = const <String>[];
|
| + List<ResolutionDartType> namedTypes = const <ResolutionDartType>[];
|
| +
|
| + 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>[];
|
| + namedTypes = <ResolutionDartType>[];
|
| + fillNamedTypes(optionalFormals, names, namedTypes);
|
| + } else {
|
| + orderedTypes = <ResolutionDartType>[];
|
| + for (Link<Node> link = optionalFormals.nodes;
|
| + !link.isEmpty;
|
| + link = link.tail) {
|
| + orderedTypes.add(resolvePositionalType(link.head));
|
| + }
|
| + }
|
| + }
|
| + return new _FormalsTypeResolutionResult(
|
| + requiredTypes, orderedTypes, names, namedTypes);
|
| + }
|
| +
|
| + ResolutionFunctionType _resolveFunctionTypeAnnotation(MappingVisitor visitor,
|
| + FunctionTypeAnnotation node,
|
| + List<List<String>> visibleTypeParameterNames,
|
| + {bool malformedIsError: false, bool deferredIsMalformed: true}) {
|
| +
|
| + 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);
|
| + }
|
| +
|
| + ResolutionDartType returnType = node.returnType == null
|
| + ? const ResolutionDynamicType()
|
| + : _resolveTypeAnnotation(visitor, node.returnType,
|
| + visibleTypeParameterNames);
|
| + var formalTypes =
|
| + _resolveFormalTypes(visitor, node.formals, visibleTypeParameterNames);
|
| + var result = new ResolutionFunctionType.generalized(
|
| + returnType,
|
| + formalTypes.requiredTypes,
|
| + formalTypes.orderedTypes,
|
| + formalTypes.names,
|
| + formalTypes.nameTypes);
|
| + visitor.registry.useType(node, result);
|
| + return result;
|
| + }
|
| +
|
| + ResolutionDartType resolveNominalTypeAnnotation(MappingVisitor visitor,
|
| + NominalTypeAnnotation node,
|
| + List<List<String>> visibleTypeParameterNames,
|
| + {bool malformedIsError: false, bool deferredIsMalformed: true}) {
|
| ResolutionRegistry registry = visitor.registry;
|
|
|
| Identifier typeName;
|
| @@ -74,7 +232,8 @@ class TypeResolver {
|
| ResolutionDartType checkNoTypeArguments(ResolutionDartType type) {
|
| List<ResolutionDartType> arguments = new List<ResolutionDartType>();
|
| bool hasTypeArgumentMismatch = resolveTypeArguments(
|
| - visitor, node, const <ResolutionDartType>[], arguments);
|
| + visitor, node, const <ResolutionDartType>[], arguments,
|
| + visibleTypeParameterNames);
|
| if (hasTypeArgumentMismatch) {
|
| return new MalformedType(
|
| new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
|
| @@ -106,9 +265,6 @@ class TypeResolver {
|
| }
|
| }
|
|
|
| - Element element = resolveTypeName(prefixName, typeName, visitor.scope,
|
| - deferredIsMalformed: deferredIsMalformed);
|
| -
|
| ResolutionDartType reportFailureAndCreateType(
|
| MessageKind messageKind, Map messageArguments,
|
| {ResolutionDartType userProvidedBadType,
|
| @@ -128,14 +284,33 @@ class TypeResolver {
|
| typeName.source, visitor.enclosingElement);
|
| }
|
| List<ResolutionDartType> arguments = <ResolutionDartType>[];
|
| - resolveTypeArguments(
|
| - visitor, node, const <ResolutionDartType>[], arguments);
|
| + resolveTypeArguments(visitor, node, const <ResolutionDartType>[],
|
| + 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 ResolutionDynamicType();
|
| + } 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) {
|
| @@ -170,8 +345,9 @@ class TypeResolver {
|
| resolver.ensureClassWillBeResolvedInternal(cls);
|
| cls.computeType(resolution);
|
| List<ResolutionDartType> arguments = <ResolutionDartType>[];
|
| - bool hasTypeArgumentMismatch =
|
| - resolveTypeArguments(visitor, node, cls.typeVariables, arguments);
|
| + bool hasTypeArgumentMismatch = resolveTypeArguments(
|
| + visitor, node, cls.typeVariables, arguments,
|
| + visibleTypeParameterNames);
|
| if (hasTypeArgumentMismatch) {
|
| type = new BadInterfaceType(
|
| cls.declaration,
|
| @@ -194,7 +370,8 @@ class TypeResolver {
|
| typdef.computeType(resolution);
|
| List<ResolutionDartType> arguments = <ResolutionDartType>[];
|
| bool hasTypeArgumentMismatch = resolveTypeArguments(
|
| - visitor, node, typdef.typeVariables, arguments);
|
| + visitor, node, typdef.typeVariables, arguments,
|
| + visibleTypeParameterNames);
|
| if (hasTypeArgumentMismatch) {
|
| type = new BadTypedefType(
|
| typdef,
|
| @@ -241,7 +418,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(_, ResolutionDartType typeArgument,
|
| ResolutionTypeVariableType typeVariable, ResolutionDartType bound) {
|
| if (!types.isSubtype(typeArgument, bound)) {
|
| @@ -266,9 +443,10 @@ class TypeResolver {
|
| */
|
| bool resolveTypeArguments(
|
| MappingVisitor visitor,
|
| - TypeAnnotation node,
|
| + NominalTypeAnnotation node,
|
| List<ResolutionDartType> typeVariables,
|
| - List<ResolutionDartType> arguments) {
|
| + List<ResolutionDartType> arguments,
|
| + List<List<String>> visibleTypeParameterNames) {
|
| if (node.typeArguments == null) {
|
| return false;
|
| }
|
| @@ -283,8 +461,8 @@ class TypeResolver {
|
| typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
|
| typeArgumentCountMismatch = true;
|
| }
|
| - ResolutionDartType argType =
|
| - resolveTypeAnnotation(visitor, typeArguments.head);
|
| + ResolutionDartType argType = _resolveTypeAnnotation(
|
| + visitor, typeArguments.head, visibleTypeParameterNames);
|
| // TODO(karlklose): rewrite to not modify [arguments].
|
| arguments.add(argType);
|
| }
|
|
|