diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index 94bb32dd414..dba7f0cb1ba 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -79,9 +79,9 @@ public abstract class AnnotationCodegen { for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { ResolvedValueArgument valueArgument = entry.getValue(); if (!(valueArgument instanceof DefaultValueArgument)) { - List valueArguments = valueArgument.getArgumentExpressions(); + List valueArguments = valueArgument.getArguments(); assert valueArguments.size() == 1 : "Number of assertions on " + resolvedCall.getResultingDescriptor() + " = " + valueArguments.size(); // todo - CompileTimeConstant compileTimeConstant = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, valueArguments.get(0)); + CompileTimeConstant compileTimeConstant = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, valueArguments.get(0).getArgumentExpression()); assert compileTimeConstant != null; Object value = compileTimeConstant.getValue(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index aa11d9e6dcd..9c72de95925 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1495,7 +1495,7 @@ public class ExpressionCodegen extends JetVisitor { ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor.getIndex()); if(resolvedValueArgument instanceof ExpressionValueArgument) { ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument; - gen(valueArgument.getExpression(), valueParameterTypes.get(index)); + gen(valueArgument.getValueArgument().getArgumentExpression(), valueParameterTypes.get(index)); } else if(resolvedValueArgument instanceof DefaultValueArgument) { Type type = valueParameterTypes.get(index); @@ -1522,14 +1522,14 @@ public class ExpressionCodegen extends JetVisitor { Type type = asmType(outType); assert type.getSort() == Type.ARRAY; Type elementType = correctElementType(type); - int size = valueArgument.getArgumentExpressions().size(); + int size = valueArgument.getArguments().size(); - v.iconst(valueArgument.getArgumentExpressions().size()); + v.iconst(valueArgument.getArguments().size()); v.newarray(elementType); for(int i = 0; i != size; ++i) { v.dup(); v.iconst(i); - gen(valueArgument.getArgumentExpressions().get(i), elementType); + gen(valueArgument.getArguments().get(i).getArgumentExpression(), elementType); StackValue.arrayElement(elementType, false).store(v); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 1ca46d8fbae..932764ea5b4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.diagnostics; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -113,6 +114,7 @@ public interface Errors { DiagnosticFactory ARGUMENT_PASSED_TWICE = DiagnosticFactory.create(ERROR, "An argument is already passed for this parameter"); UnresolvedReferenceDiagnosticFactory NAMED_PARAMETER_NOT_FOUND = UnresolvedReferenceDiagnosticFactory.create("Cannot find a parameter with this name"); DiagnosticFactory VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory.create(ERROR, "Passing value as a vararg is only allowed inside a parenthesized argument list"); + DiagnosticFactory NON_VARARG_SPREAD = DiagnosticFactory.create(ERROR, "The spread operator (*foo) may only be applied in a vararg position"); DiagnosticFactory MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory.create(ERROR, "Only one function literal is allowed outside a parenthesized argument list"); DiagnosticFactory PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory.create(ERROR, "This property must either have a type annotation or be initialized"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 0ebf9560ac9..19ea99a25ca 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -1812,7 +1812,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * valueArguments - * : "(" (SimpleName "=")? ("out" | "ref")? element{","} ")" + * : "(" (SimpleName "=")? "*"? element{","} ")" * ; */ public void parseValueArgumentList() { @@ -1841,7 +1841,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * (SimpleName "=")? element + * (SimpleName "=")? "*"? element */ private void parseValueArgument() { PsiBuilder.Marker argument = mark(); @@ -1853,6 +1853,9 @@ public class JetExpressionParsing extends AbstractJetParsing { argName.done(VALUE_ARGUMENT_NAME); advance(); // EQ } + if (at(MUL)) { + advance(); // MUL + } parseExpression(); argument.done(VALUE_ARGUMENT); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetValueArgument.java index a6bd78ba99b..9e8d47b025f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetValueArgument.java @@ -18,9 +18,11 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; /** * @author max @@ -61,4 +63,10 @@ public class JetValueArgument extends JetElement implements ValueArgument { public PsiElement asElement() { return this; } + + @Override + public LeafPsiElement getSpreadElement() { + ASTNode node = getNode().findChildByType(JetTokens.MUL); + return node == null ? null : (LeafPsiElement) node.getPsi(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/ValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/ValueArgument.java index be116cf5327..58cd0b53bea 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/ValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/ValueArgument.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,4 +37,7 @@ public interface ValueArgument { @NotNull PsiElement asElement(); + /* The '*' in something like foo(*arr) i.e. pass an array as a number of vararg arguments */ + @Nullable + LeafPsiElement getSpreadElement(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index 7bbcb3ab53d..34e3d93b576 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -107,10 +107,10 @@ public class AnnotationResolver { for (Map.Entry descriptorToArgument : results.getResultingCall().getValueArguments().entrySet()) { // TODO: are varargs supported here? - List argumentExpressions = descriptorToArgument.getValue().getArgumentExpressions(); + List valueArguments = descriptorToArgument.getValue().getArguments(); ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey(); - for (JetExpression argument : argumentExpressions) { - arguments.add(resolveAnnotationArgument(argument, parameterDescriptor.getType(), trace)); + for (ValueArgument argument : valueArguments) { + arguments.add(resolveAnnotationArgument(argument.getArgumentExpression(), parameterDescriptor.getType(), trace)); } } descriptor.setValueArguments(arguments); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java index 83fe600bc22..abdb02465b6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; @@ -37,9 +38,6 @@ public class CallMaker { private final JetExpression expression; private final PsiElement reportErrorsOn; - private ExpressionValueArgument(@NotNull JetExpression expression) { - this(expression, expression); - } private ExpressionValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) { this.expression = expression; @@ -67,6 +65,10 @@ public class CallMaker { return reportErrorsOn; } + @Override + public LeafPsiElement getSpreadElement() { + return null; + } } private static class CallImpl implements Call { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 08e662357aa..75cfc768414 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -467,19 +467,20 @@ public class CallResolver { // Value parameters for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { - ResolvedValueArgument valueArgument = entry.getValue(); + ResolvedValueArgument resolvedValueArgument = entry.getValue(); ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex()); - JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor); - for (JetExpression expression : valueArgument.getArgumentExpressions()) { + for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) { // TODO : more attempts, with different expected types + JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument); + // Here we type check expecting an error type (that is a subtype of any type and a supertype of any type // and throw the results away // We'll type check the arguments later, with the inferred types expected TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(context.trace); - JetType type = expressionTypingServices.getType(context.scope, expression, substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT), traceForUnknown); + JetType type = expressionTypingServices.getType(context.scope, valueArgument.getArgumentExpression(), substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT), traceForUnknown); if (type != null && !ErrorUtils.isErrorType(type)) { constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType)); } @@ -525,14 +526,6 @@ public class CallResolver { } } - private static JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { - JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType(); - if (effectiveExpectedType == null) { - effectiveExpectedType = valueParameterDescriptor.getType(); - } - return effectiveExpectedType; - } - private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { if (receiver instanceof AutoCastReceiver) { AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; @@ -635,19 +628,19 @@ public class CallResolver { ValueParameterDescriptor parameterDescriptor = entry.getKey(); ResolvedValueArgument resolvedArgument = entry.getValue(); - JetType parameterType = getEffectiveExpectedType(parameterDescriptor); - List argumentExpressions = resolvedArgument.getArgumentExpressions(); - for (JetExpression argumentExpression : argumentExpressions) { - if (argumentExpression == null) { - throw new IllegalStateException("A null instead of an expression in the arguments for " + entry.getKey()); - } - JetType type = expressionTypingServices.getType(context.scope, argumentExpression, parameterType, context.dataFlowInfo, context.candidateCall.getTrace()); + for (ValueArgument argument : resolvedArgument.getArguments()) { + JetExpression expression = argument.getArgumentExpression(); + if (expression == null) continue; + + JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument); + + JetType type = expressionTypingServices.getType(context.scope, expression, expectedType, context.dataFlowInfo, context.candidateCall.getTrace()); if (type == null || ErrorUtils.isErrorType(type)) { context.candidateCall.argumentHasNoType(); } - else if (!typeChecker.isSubtypeOf(type, parameterType)) { -// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); + else if (!typeChecker.isSubtypeOf(type, expectedType)) { +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument); // if (variableDescriptor != null) { // JetType autoCastType = null; // for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { @@ -658,10 +651,10 @@ public class CallResolver { // } // if (autoCastType != null) { // if (AutoCastUtils.isStableVariable(variableDescriptor)) { -// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); +// temporaryTrace.record(AUTOCAST, argument, autoCastType); // } // else { -// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); +// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argument, autoCastType, variableDescriptor)); // result = false; // } // } @@ -674,6 +667,31 @@ public class CallResolver { return result; } + @NotNull + private JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) { + if (argument.getSpreadElement() != null) { + if (parameterDescriptor.getVarargElementType() == null) { + // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper + return ErrorUtils.createErrorType("Don't care"); + } + else { + return parameterDescriptor.getType(); + } + } + else { + if (argument.isNamed()) { + return parameterDescriptor.getType(); + } + else { + JetType varargElementType = parameterDescriptor.getVarargElementType(); + if (varargElementType == null) { + return parameterDescriptor.getType(); + } + return varargElementType; + } + } + } + @NotNull private OverloadResolutionResultsImpl computeResultAndReportErrors( BindingTrace trace, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java index ea0497611ba..873f57ad142 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java @@ -17,7 +17,7 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; import java.util.Collections; import java.util.List; @@ -32,8 +32,8 @@ public class DefaultValueArgument implements ResolvedValueArgument { @NotNull @Override - public List getArgumentExpressions() { - return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter"); + public List getArguments() { + return Collections.emptyList(); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java index b9fb592bf8a..fe19f456e20 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; import java.util.Collections; import java.util.List; @@ -27,27 +28,28 @@ import java.util.List; * @author abreslav */ public class ExpressionValueArgument implements ResolvedValueArgument { - private final JetExpression expression; + private final ValueArgument valueArgument; - public ExpressionValueArgument(@Nullable JetExpression expression) { - this.expression = expression; + public ExpressionValueArgument(@Nullable ValueArgument valueArgument) { + this.valueArgument = valueArgument; } // Nullable when something like f(a, , b) was in the source code @Nullable - public JetExpression getExpression() { - return expression; + public ValueArgument getValueArgument() { + return valueArgument; } @NotNull @Override - public List getArgumentExpressions() { - if (expression == null) return Collections.emptyList(); - return Collections.singletonList(expression); + public List getArguments() { + if (valueArgument == null) return Collections.emptyList(); + return Collections.singletonList(valueArgument); } @Override public String toString() { - return expression.getText(); + JetExpression expression = valueArgument.getArgumentExpression(); + return expression == null ? "no expression" : expression.getText(); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java index c620a57c204..771cca8c841 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCallImpl.java @@ -120,12 +120,12 @@ public class ResolvedCallImpl implements ResolvedC } public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) { - assert !typeArguments.containsKey(typeParameter); + assert !typeArguments.containsKey(typeParameter) : typeParameter + " -> " + typeArgument; typeArguments.put(typeParameter, typeArgument); } public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) { - assert !valueArguments.containsKey(valueParameter); + assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument; valueArguments.put(valueParameter, valueArgument); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java index dc692ba7bd2..98a52dcc27d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java @@ -17,7 +17,7 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; import java.util.List; @@ -26,6 +26,6 @@ import java.util.List; */ public interface ResolvedValueArgument { @NotNull - List getArgumentExpressions(); + List getArguments(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index e78984f3f05..17a75efc4b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -67,8 +68,8 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; ValueArgument valueArgument = valueArguments.get(i); if (valueArgument.isNamed()) { someNamed = true; - JetReferenceExpression nameReference = valueArgument.getArgumentName().getReferenceExpression(); - ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getReferenceExpression().getReferencedName()); + JetSimpleNameExpression nameReference = valueArgument.getArgumentName().getReferenceExpression(); + ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(nameReference.getReferencedName()); if (valueParameterDescriptor == null) { temporaryTrace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference)); error = true; @@ -200,13 +201,14 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; varargs.put(valueParameterDescriptor, vararg); candidateCall.recordValueArgument(valueParameterDescriptor, vararg); } - JetExpression expression = valueArgument.getArgumentExpression(); - if (expression != null) { - vararg.getArgumentExpressions().add(expression); - } + vararg.addArgument(valueArgument); } else { - ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument.getArgumentExpression()); + LeafPsiElement spread = valueArgument.getSpreadElement(); + if (spread != null) { + candidateCall.getTrace().report(NON_VARARG_SPREAD.on(spread)); + } + ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument); candidateCall.recordValueArgument(valueParameterDescriptor, argument); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java index 3748765d450..483be4abf27 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; import java.util.Iterator; import java.util.List; @@ -27,20 +28,25 @@ import java.util.List; * @author abreslav */ public class VarargValueArgument implements ResolvedValueArgument { - private final List values = Lists.newArrayList(); + private final List arguments = Lists.newArrayList(); + + public void addArgument(@NotNull ValueArgument argument) { + arguments.add(argument); + } - @NotNull @Override - public List getArgumentExpressions() { - return values; + @NotNull + public List getArguments() { + return arguments; } @Override public String toString() { StringBuilder builder = new StringBuilder("vararg:{"); - for (Iterator iterator = values.iterator(); iterator.hasNext(); ) { - JetExpression expression = iterator.next(); - builder.append(expression.getText()); + for (Iterator iterator = arguments.iterator(); iterator.hasNext(); ) { + ValueArgument valueArgument = iterator.next(); + JetExpression expression = valueArgument.getArgumentExpression(); + builder.append(expression == null ? "no expression" : expression.getText()); if (iterator.hasNext()) { builder.append(", "); } diff --git a/compiler/testData/diagnostics/tests/spreadArguments/SpreadVarargs.jet b/compiler/testData/diagnostics/tests/spreadArguments/SpreadVarargs.jet new file mode 100644 index 00000000000..eaf2e25cdb8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/spreadArguments/SpreadVarargs.jet @@ -0,0 +1,92 @@ +fun array1(vararg a : T) = a + +fun main(args : Array) { + val a = array1("a", "b") + val b = array1(1, 1) + join(1) + join(1, "2") + join(1, "2", "3") + join(*1, "2") + join(1, *"2") + join(x = 1, a = "2") + join(x = *1, a = *"2") + join(x = 1, a = *a) + join(x = 1, a = *b) + join(1, *a) + join(1, *b) + join(1, *a, "3") + join(1, *b, "3") + join(1, "4", *a, "3") + join(1, "4", *b, "3") + join(1, "4", *a) + join(1, "4", *a, *a, "3") + join(1, "4", *a, *b, "3") + join(a = *a, x = 1) + join(a = *b, x = 1) + + joinG(1, "2") + joinG(*1, "2") + joinG(1, *"2") + joinG(x = 1, a = *a) + joinG(x = 1, a = "2") + joinG(x = *1, a = *"2") + joinG(1, *a) + joinG(1, *a, "3") + joinG(1, "4", *a, "3") + joinG(1, "4", *a) + joinG(1, "4", *a, *a, "3") + joinG(a = *a, x = 1) + + joinG(1, "2") + joinG(*1, "2") + joinG(1, *"2") + joinG(x = 1, a = *a) + joinG(x = 1, a = "2") + joinG(x = *1, a = *"2") + joinG(1, *a) + joinG(1, *a, "3") + joinG(1, "4", *a, "3") + joinG(1, "4", *a) + joinG(1, "4", *a, *a, "3") + joinG(a = *a, x = 1) + + val x1 = joinT(1, "2") + x1 : String? + val x2 = joinT(*1, "2") + x2 : String? + val x6 = joinT(1, *a) + x6 : String? + val x7 = joinT(1, *a, "3") + x7 : String? + val x8 = joinT(1, "4", *a, "3") + x8 : String? + val x9 = joinT(1, "4", *a) + x9 : String? + val x10 = joinT(1, "4", *a, *a, "3") + x10 : String? + val x11 = joinT(a = *a, x = 1) + x11 : String? + val x12 = joinT(x = 1, a = *a) + x12 : String? +} + +fun join(x : Int, vararg a : String) : String { + val b = StringBuilder(x.toString()) + for (s in a) { + b.append(s) + } + return b.toString()!! +} + +fun joinG(x : Int, vararg a : T) : String { + val b = StringBuilder(x.toString()) + for (s in a) { + b.append(s) + } + return b.toString()!! +} + +fun joinT(x : Int, vararg a : T) : T? { + return null +} + diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index 1c3fc4d0f69..af008f7ef6c 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -152,7 +152,6 @@ longTemplate : "${" expression "}" ; - isRHS : pattern ; @@ -232,7 +231,7 @@ typeArguments ; valueArguments - : "(" (SimpleName "=")? expression{","} ")" + : "(" (SimpleName "=")? "*"? expression{","} ")" ; jump diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java index b2457440b30..8c5ddd45d18 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java @@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.VariableAsFunctionDescriptor; import org.jetbrains.jet.lang.psi.JetCallExpression; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; @@ -121,24 +122,24 @@ public final class CallExpressionTranslator extends AbstractTranslator { @NotNull private List translateSingleArgument(@NotNull ResolvedValueArgument actualArgument, @NotNull ValueParameterDescriptor parameterDescriptor) { - List argumentExpressions = actualArgument.getArgumentExpressions(); + List valueArguments = actualArgument.getArguments(); if (actualArgument instanceof VarargValueArgument) { - return translateVarargArgument(argumentExpressions); + return translateVarargArgument(valueArguments); } if (actualArgument instanceof DefaultValueArgument) { JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor); return Arrays.asList(Translation.translateAsExpression(defaultArgument, context())); } assert actualArgument instanceof ExpressionValueArgument; - assert argumentExpressions.size() == 1; - return Arrays.asList(Translation.translateAsExpression(argumentExpressions.get(0), context())); + assert valueArguments.size() == 1; + return Arrays.asList(Translation.translateAsExpression(valueArguments.get(0).getArgumentExpression(), context())); } @NotNull - private List translateVarargArgument(@NotNull List arguments) { + private List translateVarargArgument(@NotNull List arguments) { List translatedArgs = Lists.newArrayList(); - for (JetExpression argument : arguments) { - translatedArgs.add(Translation.translateAsExpression(argument, context())); + for (ValueArgument argument : arguments) { + translatedArgs.add(Translation.translateAsExpression(argument.getArgumentExpression(), context())); } if (isNativeFunctionCall) { return translatedArgs;