Index: compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
index ae59d39fde05ea633cdddf963f1bb986d5cb6204..c3151530f65bd9c55b207c7a51a1ee61ef4edc09 100644 |
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java |
@@ -9,6 +9,7 @@ import com.google.common.base.Joiner; |
import com.google.common.collect.ArrayListMultimap; |
import com.google.common.collect.LinkedListMultimap; |
import com.google.common.collect.Multimap; |
+import com.google.common.collect.Sets; |
import com.google.dart.compiler.DartCompilationError; |
import com.google.dart.compiler.DartCompilationPhase; |
import com.google.dart.compiler.DartCompilerContext; |
@@ -112,8 +113,10 @@ import java.util.Arrays; |
import java.util.Collection; |
import java.util.Collections; |
import java.util.Iterator; |
+import java.util.LinkedHashMap; |
import java.util.List; |
import java.util.Map; |
+import java.util.Map.Entry; |
import java.util.Set; |
import java.util.concurrent.ConcurrentHashMap; |
@@ -446,7 +449,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
private Type analyzeMethodInvocation(Type receiver, Member member, String name, |
DartNode diagnosticNode, |
List<Type> argumentTypes, |
- List<? extends DartExpression> argumentNodes) { |
+ List<DartExpression> argumentNodes) { |
if (member == null) { |
return dynamicType; |
} |
@@ -518,33 +521,80 @@ public class TypeAnalyzer implements DartCompilationPhase { |
} |
private Type checkArguments(DartNode diagnosticNode, |
- List<? extends DartExpression> argumentNodes, |
+ List<DartExpression> argumentNodes, |
Iterator<Type> argumentTypes, FunctionType ftype) { |
- int argumentCount = 0; |
- List<? extends Type> parameterTypes = ftype.getParameterTypes(); |
+ int argumentIndex = 0; |
+ // Check positional parameters. |
+ List<Type> parameterTypes = ftype.getParameterTypes(); |
for (Type parameterType : parameterTypes) { |
if (argumentTypes.hasNext()) { |
- checkAssignable(argumentNodes.get(argumentCount), parameterType, argumentTypes.next()); |
- argumentCount++; |
+ checkAssignable(argumentNodes.get(argumentIndex), parameterType, argumentTypes.next()); |
+ argumentIndex++; |
} else { |
- typeError(diagnosticNode, TypeErrorCode.MISSING_ARGUMENT, parameterType); |
+ onError(diagnosticNode, TypeErrorCode.MISSING_ARGUMENT, parameterType); |
+ return ftype.getReturnType(); |
} |
} |
- Map<String, Type> namedParameterTypes = ftype.getNamedParameterTypes(); |
- Iterator<Type> named = namedParameterTypes.values().iterator(); |
- while (named.hasNext() && argumentTypes.hasNext()) { |
- checkAssignable(argumentNodes.get(argumentCount), named.next(), argumentTypes.next()); |
- argumentCount++; |
+ // Check named parameters. |
+ { |
+ Set<String> usedNamedParametersPositional = Sets.newHashSet(); |
+ Set<String> usedNamedParametersNamed = Sets.newHashSet(); |
+ // Prepare named parameters. |
+ Map<String, Type> namedParameterTypes = ftype.getNamedParameterTypes(); |
+ assert namedParameterTypes.isEmpty() || namedParameterTypes instanceof LinkedHashMap; |
+ Iterator<Entry<String, Type>> namedParameterTypesIterator = |
+ namedParameterTypes.entrySet().iterator(); |
+ // Check positional arguments for named parameters. |
+ while (namedParameterTypesIterator.hasNext() |
+ && argumentTypes.hasNext() |
+ && !(argumentNodes.get(argumentIndex) instanceof DartNamedExpression)) { |
+ Entry<String, Type> namedEntry = namedParameterTypesIterator.next(); |
+ String parameterName = namedEntry.getKey(); |
+ usedNamedParametersPositional.add(parameterName); |
+ Type argumentType = argumentTypes.next(); |
+ checkAssignable(argumentNodes.get(argumentIndex), namedEntry.getValue(), argumentType); |
+ argumentIndex++; |
+ } |
+ // Check named arguments for named parameters. |
+ while (argumentTypes.hasNext() |
+ && argumentNodes.get(argumentIndex) instanceof DartNamedExpression) { |
+ DartNamedExpression namedExpression = |
+ (DartNamedExpression) argumentNodes.get(argumentIndex); |
+ DartExpression argumentNode = argumentNodes.get(argumentIndex); |
+ // Prepare parameter name. |
+ String parameterName = namedExpression.getName().getTargetName(); |
+ if (usedNamedParametersPositional.contains(parameterName)) { |
+ onError(argumentNode, TypeErrorCode.DUPLICATE_NAMED_ARGUMENT); |
+ } else if (usedNamedParametersNamed.contains(parameterName)) { |
+ onError(argumentNode, ResolverErrorCode.DUPLICATE_NAMED_ARGUMENT); |
+ } else { |
+ usedNamedParametersNamed.add(parameterName); |
+ } |
+ // Check parameter type. |
+ Type namedParameterType = namedParameterTypes.get(parameterName); |
+ Type argumentType = argumentTypes.next(); |
+ if (namedParameterType != null) { |
+ checkAssignable(argumentNode, namedParameterType, argumentType); |
+ } else { |
+ onError(argumentNode, TypeErrorCode.NO_SUCH_NAMED_PARAMETER, parameterName); |
+ } |
+ argumentIndex++; |
+ } |
} |
- while (ftype.hasRest() && argumentTypes.hasNext()) { |
- checkAssignable(argumentNodes.get(argumentCount), ftype.getRest(), argumentTypes.next()); |
- argumentCount++; |
+ // Check rest (currently removed from specification). |
+ if (ftype.hasRest()) { |
+ while (argumentTypes.hasNext()) { |
+ checkAssignable(argumentNodes.get(argumentIndex), ftype.getRest(), argumentTypes.next()); |
+ argumentIndex++; |
+ } |
} |
+ // Report extra arguments. |
while (argumentTypes.hasNext()) { |
argumentTypes.next(); |
- typeError(argumentNodes.get(argumentCount), TypeErrorCode.EXTRA_ARGUMENT); |
- argumentCount++; |
+ onError(argumentNodes.get(argumentIndex), TypeErrorCode.EXTRA_ARGUMENT); |
+ argumentIndex++; |
} |
+ // Return type. |
return ftype.getReturnType(); |
} |
@@ -575,8 +625,8 @@ public class TypeAnalyzer implements DartCompilationPhase { |
} |
private void validateBounds(List<? extends DartNode> diagnosticNodes, |
- List<? extends Type> arguments, |
- List<? extends Type> parameters, |
+ List<Type> arguments, |
+ List<Type> parameters, |
boolean badBoundIsError) { |
if (arguments.size() == parameters.size() && arguments.size() == diagnosticNodes.size()) { |
List<Type> bounds = new ArrayList<Type>(parameters.size()); |
@@ -1088,7 +1138,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
if (ftype != null && TypeKind.of(type).equals(TypeKind.INTERFACE)) { |
InterfaceType ifaceType = (InterfaceType) type; |
- List<? extends Type> substParams; |
+ List<Type> substParams; |
if (ifaceType.getElement().isInterface()) { |
// The constructor in the interface is resolved to the type parameters declared in |
// the interface, but the constructor body has type parameters resolved to the type |
@@ -1098,7 +1148,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
} else { |
substParams = ifaceType.getElement().getTypeParameters(); |
} |
- List<? extends Type> arguments = ifaceType.getArguments(); |
+ List<Type> arguments = ifaceType.getArguments(); |
ftype = (FunctionType) ftype.subst(arguments, substParams); |
checkInvocation(node, node, null, ftype); |
} |
@@ -1371,7 +1421,7 @@ public class TypeAnalyzer implements DartCompilationPhase { |
private Type checkInvocation(DartInvocation node, DartNode diagnosticNode, String name, |
Type type) { |
- List<? extends DartExpression> argumentNodes = node.getArgs(); |
+ List<DartExpression> argumentNodes = node.getArgs(); |
List<Type> argumentTypes = new ArrayList<Type>(argumentNodes.size()); |
for (DartExpression argumentNode : argumentNodes) { |
argumentTypes.add(nonVoidTypeOf(argumentNode)); |