KT-729 Need to support arrays as varargs: front-end checks done

#KT-729 In progress
This commit is contained in:
Andrey Breslav
2012-03-23 22:45:19 +01:00
parent 7708b2d009
commit cf108765ae
18 changed files with 215 additions and 76 deletions
@@ -79,9 +79,9 @@ public abstract class AnnotationCodegen {
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
ResolvedValueArgument valueArgument = entry.getValue(); ResolvedValueArgument valueArgument = entry.getValue();
if (!(valueArgument instanceof DefaultValueArgument)) { if (!(valueArgument instanceof DefaultValueArgument)) {
List<JetExpression> valueArguments = valueArgument.getArgumentExpressions(); List<ValueArgument> valueArguments = valueArgument.getArguments();
assert valueArguments.size() == 1 : "Number of assertions on " + resolvedCall.getResultingDescriptor() + " = " + valueArguments.size(); // todo 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; assert compileTimeConstant != null;
Object value = compileTimeConstant.getValue(); Object value = compileTimeConstant.getValue();
@@ -1495,7 +1495,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor.getIndex()); ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor.getIndex());
if(resolvedValueArgument instanceof ExpressionValueArgument) { if(resolvedValueArgument instanceof ExpressionValueArgument) {
ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument; ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument;
gen(valueArgument.getExpression(), valueParameterTypes.get(index)); gen(valueArgument.getValueArgument().getArgumentExpression(), valueParameterTypes.get(index));
} }
else if(resolvedValueArgument instanceof DefaultValueArgument) { else if(resolvedValueArgument instanceof DefaultValueArgument) {
Type type = valueParameterTypes.get(index); Type type = valueParameterTypes.get(index);
@@ -1522,14 +1522,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type type = asmType(outType); Type type = asmType(outType);
assert type.getSort() == Type.ARRAY; assert type.getSort() == Type.ARRAY;
Type elementType = correctElementType(type); 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); v.newarray(elementType);
for(int i = 0; i != size; ++i) { for(int i = 0; i != size; ++i) {
v.dup(); v.dup();
v.iconst(i); v.iconst(i);
gen(valueArgument.getArgumentExpressions().get(i), elementType); gen(valueArgument.getArguments().get(i).getArgumentExpression(), elementType);
StackValue.arrayElement(elementType, false).store(v); StackValue.arrayElement(elementType, false).store(v);
} }
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.diagnostics;
import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
@@ -113,6 +114,7 @@ public interface Errors {
DiagnosticFactory<JetReferenceExpression> ARGUMENT_PASSED_TWICE = DiagnosticFactory.create(ERROR, "An argument is already passed for this parameter"); DiagnosticFactory<JetReferenceExpression> 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"); UnresolvedReferenceDiagnosticFactory NAMED_PARAMETER_NOT_FOUND = UnresolvedReferenceDiagnosticFactory.create("Cannot find a parameter with this name");
DiagnosticFactory<JetExpression> VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory.create(ERROR, "Passing value as a vararg is only allowed inside a parenthesized argument list"); DiagnosticFactory<JetExpression> VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory.create(ERROR, "Passing value as a vararg is only allowed inside a parenthesized argument list");
DiagnosticFactory<LeafPsiElement> NON_VARARG_SPREAD = DiagnosticFactory.create(ERROR, "The spread operator (*foo) may only be applied in a vararg position");
DiagnosticFactory<JetExpression> MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory.create(ERROR, "Only one function literal is allowed outside a parenthesized argument list"); DiagnosticFactory<JetExpression> MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory.create(ERROR, "Only one function literal is allowed outside a parenthesized argument list");
DiagnosticFactory<PsiElement> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory.create(ERROR, "This property must either have a type annotation or be initialized"); DiagnosticFactory<PsiElement> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory.create(ERROR, "This property must either have a type annotation or be initialized");
@@ -1812,7 +1812,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
/* /*
* valueArguments * valueArguments
* : "(" (SimpleName "=")? ("out" | "ref")? element{","} ")" * : "(" (SimpleName "=")? "*"? element{","} ")"
* ; * ;
*/ */
public void parseValueArgumentList() { public void parseValueArgumentList() {
@@ -1841,7 +1841,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
} }
/* /*
* (SimpleName "=")? element * (SimpleName "=")? "*"? element
*/ */
private void parseValueArgument() { private void parseValueArgument() {
PsiBuilder.Marker argument = mark(); PsiBuilder.Marker argument = mark();
@@ -1853,6 +1853,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
argName.done(VALUE_ARGUMENT_NAME); argName.done(VALUE_ARGUMENT_NAME);
advance(); // EQ advance(); // EQ
} }
if (at(MUL)) {
advance(); // MUL
}
parseExpression(); parseExpression();
argument.done(VALUE_ARGUMENT); argument.done(VALUE_ARGUMENT);
} }
@@ -18,9 +18,11 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetTokens;
/** /**
* @author max * @author max
@@ -61,4 +63,10 @@ public class JetValueArgument extends JetElement implements ValueArgument {
public PsiElement asElement() { public PsiElement asElement() {
return this; return this;
} }
@Override
public LeafPsiElement getSpreadElement() {
ASTNode node = getNode().findChildByType(JetTokens.MUL);
return node == null ? null : (LeafPsiElement) node.getPsi();
}
} }
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -36,4 +37,7 @@ public interface ValueArgument {
@NotNull @NotNull
PsiElement asElement(); PsiElement asElement();
/* The '*' in something like foo(*arr) i.e. pass an array as a number of vararg arguments */
@Nullable
LeafPsiElement getSpreadElement();
} }
@@ -107,10 +107,10 @@ public class AnnotationResolver {
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
results.getResultingCall().getValueArguments().entrySet()) { results.getResultingCall().getValueArguments().entrySet()) {
// TODO: are varargs supported here? // TODO: are varargs supported here?
List<JetExpression> argumentExpressions = descriptorToArgument.getValue().getArgumentExpressions(); List<ValueArgument> valueArguments = descriptorToArgument.getValue().getArguments();
ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey(); ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
for (JetExpression argument : argumentExpressions) { for (ValueArgument argument : valueArguments) {
arguments.add(resolveAnnotationArgument(argument, parameterDescriptor.getType(), trace)); arguments.add(resolveAnnotationArgument(argument.getArgumentExpression(), parameterDescriptor.getType(), trace));
} }
} }
descriptor.setValueArguments(arguments); descriptor.setValueArguments(arguments);
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -37,9 +38,6 @@ public class CallMaker {
private final JetExpression expression; private final JetExpression expression;
private final PsiElement reportErrorsOn; private final PsiElement reportErrorsOn;
private ExpressionValueArgument(@NotNull JetExpression expression) {
this(expression, expression);
}
private ExpressionValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) { private ExpressionValueArgument(@Nullable JetExpression expression, @NotNull PsiElement reportErrorsOn) {
this.expression = expression; this.expression = expression;
@@ -67,6 +65,10 @@ public class CallMaker {
return reportErrorsOn; return reportErrorsOn;
} }
@Override
public LeafPsiElement getSpreadElement() {
return null;
}
} }
private static class CallImpl implements Call { private static class CallImpl implements Call {
@@ -467,19 +467,20 @@ public class CallResolver {
// Value parameters // Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ResolvedValueArgument valueArgument = entry.getValue(); ResolvedValueArgument resolvedValueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex()); 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 // 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 // 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 // and throw the results away
// We'll type check the arguments later, with the inferred types expected // We'll type check the arguments later, with the inferred types expected
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(context.trace); 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)) { if (type != null && !ErrorUtils.isErrorType(type)) {
constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType)); 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) { private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
if (receiver instanceof AutoCastReceiver) { if (receiver instanceof AutoCastReceiver) {
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
@@ -635,19 +628,19 @@ public class CallResolver {
ValueParameterDescriptor parameterDescriptor = entry.getKey(); ValueParameterDescriptor parameterDescriptor = entry.getKey();
ResolvedValueArgument resolvedArgument = entry.getValue(); ResolvedValueArgument resolvedArgument = entry.getValue();
JetType parameterType = getEffectiveExpectedType(parameterDescriptor);
List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions(); for (ValueArgument argument : resolvedArgument.getArguments()) {
for (JetExpression argumentExpression : argumentExpressions) { JetExpression expression = argument.getArgumentExpression();
if (argumentExpression == null) { if (expression == null) continue;
throw new IllegalStateException("A null instead of an expression in the arguments for " + entry.getKey());
} JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
JetType type = expressionTypingServices.getType(context.scope, argumentExpression, parameterType, context.dataFlowInfo, context.candidateCall.getTrace());
JetType type = expressionTypingServices.getType(context.scope, expression, expectedType, context.dataFlowInfo, context.candidateCall.getTrace());
if (type == null || ErrorUtils.isErrorType(type)) { if (type == null || ErrorUtils.isErrorType(type)) {
context.candidateCall.argumentHasNoType(); context.candidateCall.argumentHasNoType();
} }
else if (!typeChecker.isSubtypeOf(type, parameterType)) { else if (!typeChecker.isSubtypeOf(type, expectedType)) {
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); // VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument);
// if (variableDescriptor != null) { // if (variableDescriptor != null) {
// JetType autoCastType = null; // JetType autoCastType = null;
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { // for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
@@ -658,10 +651,10 @@ public class CallResolver {
// } // }
// if (autoCastType != null) { // if (autoCastType != null) {
// if (AutoCastUtils.isStableVariable(variableDescriptor)) { // if (AutoCastUtils.isStableVariable(variableDescriptor)) {
// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); // temporaryTrace.record(AUTOCAST, argument, autoCastType);
// } // }
// else { // else {
// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); // temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argument, autoCastType, variableDescriptor));
// result = false; // result = false;
// } // }
// } // }
@@ -674,6 +667,31 @@ public class CallResolver {
return result; 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 @NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeResultAndReportErrors( private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeResultAndReportErrors(
BindingTrace trace, BindingTrace trace,
@@ -17,7 +17,7 @@
package org.jetbrains.jet.lang.resolve.calls; package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull; 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.Collections;
import java.util.List; import java.util.List;
@@ -32,8 +32,8 @@ public class DefaultValueArgument implements ResolvedValueArgument {
@NotNull @NotNull
@Override @Override
public List<JetExpression> getArgumentExpressions() { public List<ValueArgument> getArguments() {
return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter"); return Collections.emptyList();
} }
@Override @Override
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.ValueArgument;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -27,27 +28,28 @@ import java.util.List;
* @author abreslav * @author abreslav
*/ */
public class ExpressionValueArgument implements ResolvedValueArgument { public class ExpressionValueArgument implements ResolvedValueArgument {
private final JetExpression expression; private final ValueArgument valueArgument;
public ExpressionValueArgument(@Nullable JetExpression expression) { public ExpressionValueArgument(@Nullable ValueArgument valueArgument) {
this.expression = expression; this.valueArgument = valueArgument;
} }
// Nullable when something like f(a, , b) was in the source code // Nullable when something like f(a, , b) was in the source code
@Nullable @Nullable
public JetExpression getExpression() { public ValueArgument getValueArgument() {
return expression; return valueArgument;
} }
@NotNull @NotNull
@Override @Override
public List<JetExpression> getArgumentExpressions() { public List<ValueArgument> getArguments() {
if (expression == null) return Collections.emptyList(); if (valueArgument == null) return Collections.emptyList();
return Collections.singletonList(expression); return Collections.singletonList(valueArgument);
} }
@Override @Override
public String toString() { public String toString() {
return expression.getText(); JetExpression expression = valueArgument.getArgumentExpression();
return expression == null ? "no expression" : expression.getText();
} }
} }
@@ -120,12 +120,12 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
} }
public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) { public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) {
assert !typeArguments.containsKey(typeParameter); assert !typeArguments.containsKey(typeParameter) : typeParameter + " -> " + typeArgument;
typeArguments.put(typeParameter, typeArgument); typeArguments.put(typeParameter, typeArgument);
} }
public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) { public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
assert !valueArguments.containsKey(valueParameter); assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
valueArguments.put(valueParameter, valueArgument); valueArguments.put(valueParameter, valueArgument);
} }
@@ -17,7 +17,7 @@
package org.jetbrains.jet.lang.resolve.calls; package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.ValueArgument;
import java.util.List; import java.util.List;
@@ -26,6 +26,6 @@ import java.util.List;
*/ */
public interface ResolvedValueArgument { public interface ResolvedValueArgument {
@NotNull @NotNull
List<JetExpression> getArgumentExpressions(); List<ValueArgument> getArguments();
} }
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 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); ValueArgument valueArgument = valueArguments.get(i);
if (valueArgument.isNamed()) { if (valueArgument.isNamed()) {
someNamed = true; someNamed = true;
JetReferenceExpression nameReference = valueArgument.getArgumentName().getReferenceExpression(); JetSimpleNameExpression nameReference = valueArgument.getArgumentName().getReferenceExpression();
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getReferenceExpression().getReferencedName()); ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(nameReference.getReferencedName());
if (valueParameterDescriptor == null) { if (valueParameterDescriptor == null) {
temporaryTrace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference)); temporaryTrace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference));
error = true; error = true;
@@ -200,13 +201,14 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
varargs.put(valueParameterDescriptor, vararg); varargs.put(valueParameterDescriptor, vararg);
candidateCall.recordValueArgument(valueParameterDescriptor, vararg); candidateCall.recordValueArgument(valueParameterDescriptor, vararg);
} }
JetExpression expression = valueArgument.getArgumentExpression(); vararg.addArgument(valueArgument);
if (expression != null) {
vararg.getArgumentExpressions().add(expression);
}
} }
else { 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); candidateCall.recordValueArgument(valueParameterDescriptor, argument);
} }
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.ValueArgument;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -27,20 +28,25 @@ import java.util.List;
* @author abreslav * @author abreslav
*/ */
public class VarargValueArgument implements ResolvedValueArgument { public class VarargValueArgument implements ResolvedValueArgument {
private final List<JetExpression> values = Lists.newArrayList(); private final List<ValueArgument> arguments = Lists.newArrayList();
public void addArgument(@NotNull ValueArgument argument) {
arguments.add(argument);
}
@NotNull
@Override @Override
public List<JetExpression> getArgumentExpressions() { @NotNull
return values; public List<ValueArgument> getArguments() {
return arguments;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder("vararg:{"); StringBuilder builder = new StringBuilder("vararg:{");
for (Iterator<JetExpression> iterator = values.iterator(); iterator.hasNext(); ) { for (Iterator<ValueArgument> iterator = arguments.iterator(); iterator.hasNext(); ) {
JetExpression expression = iterator.next(); ValueArgument valueArgument = iterator.next();
builder.append(expression.getText()); JetExpression expression = valueArgument.getArgumentExpression();
builder.append(expression == null ? "no expression" : expression.getText());
if (iterator.hasNext()) { if (iterator.hasNext()) {
builder.append(", "); builder.append(", ");
} }
@@ -0,0 +1,92 @@
fun <T> array1(vararg a : T) = a
fun main(args : Array<String>) {
val a = array1("a", "b")
val b = array1(1, 1)
join(1)
join(1, "2")
join(1, "2", "3")
join(<!NON_VARARG_SPREAD!>*<!>1, "2")
join(1, *<!TYPE_MISMATCH!>"2"<!>)
join(x = 1, a = <!TYPE_MISMATCH!>"2"<!>)
join(x = <!NON_VARARG_SPREAD!>*<!>1, a = *<!TYPE_MISMATCH!>"2"<!>)
join(x = 1, a = *a)
join(x = 1, a = *<!TYPE_MISMATCH!>b<!>)
join(1, *a)
join(1, *<!TYPE_MISMATCH!>b<!>)
join(1, *a, "3")
join(1, *<!TYPE_MISMATCH!>b<!>, "3")
join(1, "4", *a, "3")
join(1, "4", *<!TYPE_MISMATCH!>b<!>, "3")
join(1, "4", *a)
join(1, "4", *a, *a, "3")
join(1, "4", *a, *<!TYPE_MISMATCH!>b<!>, "3")
join(a = *a, x = 1)
join(a = *<!TYPE_MISMATCH!>b<!>, x = 1)
joinG<String>(1, "2")
joinG<String>(<!NON_VARARG_SPREAD!>*<!>1, "2")
joinG<String>(1, *<!TYPE_MISMATCH!>"2"<!>)
joinG<String>(x = 1, a = *a)
joinG<String>(x = 1, a = <!TYPE_MISMATCH!>"2"<!>)
joinG<String>(x = <!NON_VARARG_SPREAD!>*<!>1, a = *<!TYPE_MISMATCH!>"2"<!>)
joinG<String>(1, *a)
joinG<String>(1, *a, "3")
joinG<String>(1, "4", *a, "3")
joinG<String>(1, "4", *a)
joinG<String>(1, "4", *a, *a, "3")
joinG<String>(a = *a, x = 1)
joinG(1, "2")
joinG(<!NON_VARARG_SPREAD!>*<!>1, "2")
<!TYPE_INFERENCE_FAILED!>joinG(1, *<!TYPE_MISMATCH!>"2"<!>)<!>
joinG(x = 1, a = *a)
<!TYPE_INFERENCE_FAILED!>joinG(x = 1, a = <!TYPE_MISMATCH!>"2"<!>)<!>
<!TYPE_INFERENCE_FAILED!>joinG(x = <!NON_VARARG_SPREAD!>*<!>1, a = *<!TYPE_MISMATCH!>"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(<!NON_VARARG_SPREAD!>*<!>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 <T> joinG(x : Int, vararg a : T) : String {
val b = StringBuilder(x.toString())
for (s in a) {
b.append(s)
}
return b.toString()!!
}
fun <T> joinT(<!UNUSED_PARAMETER!>x<!> : Int, vararg <!UNUSED_PARAMETER!>a<!> : T) : T? {
return null
}
+1 -2
View File
@@ -152,7 +152,6 @@ longTemplate
: "${" expression "}" : "${" expression "}"
; ;
isRHS isRHS
: pattern : pattern
; ;
@@ -232,7 +231,7 @@ typeArguments
; ;
valueArguments valueArguments
: "(" (SimpleName "=")? expression{","} ")" : "(" (SimpleName "=")? "*"? expression{","} ")"
; ;
jump jump
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.VariableAsFunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetCallExpression; import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.calls.*;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.AbstractTranslator;
@@ -121,24 +122,24 @@ public final class CallExpressionTranslator extends AbstractTranslator {
@NotNull @NotNull
private List<JsExpression> translateSingleArgument(@NotNull ResolvedValueArgument actualArgument, private List<JsExpression> translateSingleArgument(@NotNull ResolvedValueArgument actualArgument,
@NotNull ValueParameterDescriptor parameterDescriptor) { @NotNull ValueParameterDescriptor parameterDescriptor) {
List<JetExpression> argumentExpressions = actualArgument.getArgumentExpressions(); List<ValueArgument> valueArguments = actualArgument.getArguments();
if (actualArgument instanceof VarargValueArgument) { if (actualArgument instanceof VarargValueArgument) {
return translateVarargArgument(argumentExpressions); return translateVarargArgument(valueArguments);
} }
if (actualArgument instanceof DefaultValueArgument) { if (actualArgument instanceof DefaultValueArgument) {
JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor); JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor);
return Arrays.asList(Translation.translateAsExpression(defaultArgument, context())); return Arrays.asList(Translation.translateAsExpression(defaultArgument, context()));
} }
assert actualArgument instanceof ExpressionValueArgument; assert actualArgument instanceof ExpressionValueArgument;
assert argumentExpressions.size() == 1; assert valueArguments.size() == 1;
return Arrays.asList(Translation.translateAsExpression(argumentExpressions.get(0), context())); return Arrays.asList(Translation.translateAsExpression(valueArguments.get(0).getArgumentExpression(), context()));
} }
@NotNull @NotNull
private List<JsExpression> translateVarargArgument(@NotNull List<JetExpression> arguments) { private List<JsExpression> translateVarargArgument(@NotNull List<ValueArgument> arguments) {
List<JsExpression> translatedArgs = Lists.newArrayList(); List<JsExpression> translatedArgs = Lists.newArrayList();
for (JetExpression argument : arguments) { for (ValueArgument argument : arguments) {
translatedArgs.add(Translation.translateAsExpression(argument, context())); translatedArgs.add(Translation.translateAsExpression(argument.getArgumentExpression(), context()));
} }
if (isNativeFunctionCall) { if (isNativeFunctionCall) {
return translatedArgs; return translatedArgs;