diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 947cf407491..46d588a839f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -462,7 +462,7 @@ public class JetTypeMapper { } for (ValueParameterDescriptor parameter : parameters) { Type type = mapType(parameter.getOutType()); - if(parameter.isVararg()) { + if(parameter.getVarargElementType() != null) { type = Type.getType("[" + type.getDescriptor()); } valueParameterTypes.add(type); @@ -562,7 +562,7 @@ public class JetTypeMapper { parameterTypes.add(mapType(receiver.getType())); } for (ValueParameterDescriptor parameter : parameters) { - if(parameter.isVararg()) { + if(parameter.getVarargElementType() != null) { Type type = mapType(parameter.getOutType()); type = Type.getType("[" + type.getDescriptor()); parameterTypes.add(type); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 67bb062e71e..a66b089f62c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -300,15 +300,26 @@ public class JavaDescriptorResolver { for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { PsiParameter parameter = parameters[i]; String name = parameter.getName(); + PsiType psiType = parameter.getType(); + + JetType varargElementType; + if (psiType instanceof PsiEllipsisType) { + PsiEllipsisType psiEllipsisType = (PsiEllipsisType) psiType; + varargElementType = semanticServices.getTypeTransformer().transformToType(psiEllipsisType.getComponentType()); + } + else { + varargElementType = null; + } + JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); result.add(new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO name == null ? "p" + i : name, null, // TODO : review - semanticServices.getTypeTransformer().transformToType(parameter.getType()), + outType, false, - parameter.isVarArgs() + varargElementType )); } return result; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 3990e09e9a7..cb193b40b69 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -16,35 +16,6 @@ import java.util.*; * @author abreslav */ public class FunctionDescriptorUtil { - /** @return Minimal number of arguments to be passed */ - public static int getMinimumArity(@NotNull FunctionDescriptor functionDescriptor) { - int result = 0; - for (ValueParameterDescriptor valueParameter : functionDescriptor.getValueParameters()) { - if (valueParameter.hasDefaultValue()) { - break; - } - result++; - } - return result; - } - - /** - * @return Maximum number of arguments that can be passed. -1 if unbound (vararg) - */ - public static int getMaximumArity(@NotNull FunctionDescriptor functionDescriptor) { - List unsubstitutedValueParameters = functionDescriptor.getValueParameters(); - if (unsubstitutedValueParameters.isEmpty()) { - return 0; - } - // TODO : check somewhere that vararg is only the last one, and that varargs do not have default values - - ValueParameterDescriptor lastParameter = unsubstitutedValueParameters.get(unsubstitutedValueParameters.size() - 1); - if (lastParameter.isVararg()) { - return -1; - } - return unsubstitutedValueParameters.size(); - } - public static Map createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List typeArguments) { if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap(); @@ -69,13 +40,16 @@ public class FunctionDescriptorUtil { ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i); // TODO : Lazy? JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getOutType(), Variance.IN_VARIANCE); + JetType varargElementType = unsubstitutedValueParameter.getVarargElementType(); + JetType substituteVarargElementType = varargElementType == null ? null : substitutor.substitute(varargElementType, Variance.IN_VARIANCE); if (substitutedType == null) return null; result.add(new ValueParameterDescriptorImpl( substitutedDescriptor, unsubstitutedValueParameter, unsubstitutedValueParameter.getAnnotations(), unsubstitutedValueParameter.getInType() == null ? null : substitutedType, - substitutedType + substitutedType, + substituteVarargElementType )); } return result; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java index ba7131b36c0..0cbe2362042 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.JetType; /** @@ -15,7 +16,7 @@ public interface ValueParameterDescriptor extends VariableDescriptor { int getIndex(); boolean hasDefaultValue(); boolean isRef(); - boolean isVararg(); + @Nullable JetType getVarargElementType(); @Override @NotNull @@ -26,4 +27,5 @@ public interface ValueParameterDescriptor extends VariableDescriptor { @NotNull ValueParameterDescriptor copy(DeclarationDescriptor newOwner); + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java index 8b13a526dc7..b56cf9f7ea9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java @@ -14,7 +14,7 @@ import java.util.List; */ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor { private final boolean hasDefaultValue; - private final boolean isVararg; + private final JetType varargElementType; private final boolean isVar; private final int index; private final ValueParameterDescriptor original; @@ -27,12 +27,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @Nullable JetType inType, @NotNull JetType outType, boolean hasDefaultValue, - boolean isVararg) { + @Nullable JetType varargElementType) { super(containingDeclaration, annotations, name, inType, outType); this.original = this; this.index = index; this.hasDefaultValue = hasDefaultValue; - this.isVararg = isVararg; + this.varargElementType = varargElementType; this.isVar = inType != null; } @@ -41,13 +41,14 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull ValueParameterDescriptor original, @NotNull List annotations, @Nullable JetType inType, - @NotNull JetType outType + @NotNull JetType outType, + @Nullable JetType varargElementType ) { super(containingDeclaration, annotations, original.getName(), inType, outType); this.original = original; this.index = original.getIndex(); this.hasDefaultValue = original.hasDefaultValue(); - this.isVararg = original.isVararg(); + this.varargElementType = varargElementType; this.isVar = inType != null; } @@ -76,9 +77,9 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme throw new UnsupportedOperationException(); // TODO } - @Override - public boolean isVararg() { - return isVararg; + @Nullable + public JetType getVarargElementType() { + return varargElementType; } @NotNull @@ -106,6 +107,6 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull @Override public ValueParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) { - return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, isVararg); + return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, varargElementType); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 4f7bf2ececf..112c798ab46 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -246,21 +246,56 @@ public class ClassDescriptorResolver { @NotNull public MutableValueParameterDescriptor resolveValueParameterDescriptor(DeclarationDescriptor declarationDescriptor, JetParameter valueParameter, int index, JetType type) { + JetType varargElementType = null; + JetType variableType = type; + if (valueParameter.hasModifier(JetTokens.VARARG_KEYWORD)) { + varargElementType = type; + variableType = getVarargParameterType(type); + } MutableValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl( declarationDescriptor, index, annotationResolver.createAnnotationStubs(valueParameter.getModifierList()), JetPsiUtil.safeName(valueParameter.getName()), - valueParameter.isMutable() ? type : null, - type, + valueParameter.isMutable() ? variableType : null, + variableType, valueParameter.getDefaultValue() != null, - valueParameter.hasModifier(JetTokens.VARARG_KEYWORD) + varargElementType ); trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor); return valueParameterDescriptor; } + private JetType getVarargParameterType(JetType type) { + JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary(); + if (type.equals(standardLibrary.getByteType())) { + return standardLibrary.getByteArrayType(); + } + if (type.equals(standardLibrary.getCharType())) { + return standardLibrary.getCharArrayType(); + } + if (type.equals(standardLibrary.getShortType())) { + return standardLibrary.getShortArrayType(); + } + if (type.equals(standardLibrary.getIntType())) { + return standardLibrary.getIntArrayType(); + } + if (type.equals(standardLibrary.getLongType())) { + return standardLibrary.getLongArrayType(); + } + if (type.equals(standardLibrary.getFloatType())) { + return standardLibrary.getFloatArrayType(); + } + if (type.equals(standardLibrary.getDoubleType())) { + return standardLibrary.getDoubleArrayType(); + } + if (type.equals(standardLibrary.getBooleanType())) { + return standardLibrary.getBooleanArrayType(); + } + return standardLibrary.getArrayType(type); + } + public List resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List typeParameters) { List result = new ArrayList(); for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) { 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 976d5b9c070..5b93320fe05 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 @@ -387,13 +387,15 @@ public class CallResolver { ResolvedValueArgument valueArgument = entry.getValue(); ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); + JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor); + for (JetExpression expression : valueArgument.getArgumentExpressions()) { // JetExpression expression = valueArgument.getArgumentExpression(); // TODO : more attempts, with different expected types ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace); JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); if (type != null) { - constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); + constraintSystem.addSubtypingConstraint(type, effectiveExpectedType); } else { candidateCall.argumentHasNoType(); @@ -512,6 +514,14 @@ public class CallResolver { return results; } + private JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { + JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType(); + if (effectiveExpectedType == null) { + effectiveExpectedType = valueParameterDescriptor.getOutType(); + } + return effectiveExpectedType; + } + private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { if (receiver instanceof AutoCastReceiver) { AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; @@ -606,7 +616,7 @@ public class CallResolver { ValueParameterDescriptor parameterDescriptor = entry.getKey(); ResolvedValueArgument resolvedArgument = entry.getValue(); - JetType parameterType = parameterDescriptor.getOutType(); + JetType parameterType = getEffectiveExpectedType(parameterDescriptor); List argumentExpressions = resolvedArgument.getArgumentExpressions(); for (JetExpression argumentExpression : argumentExpressions) { 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 402b3f1aa62..040a218e534 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 @@ -84,7 +84,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } else if (!valueParameters.isEmpty()) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { put(candidateCall, valueParameterDescriptor, valueArgument, varargs); usedParameters.add(valueParameterDescriptor); } @@ -123,7 +123,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); error = true; @@ -154,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; if (valueParameter.hasDefaultValue()) { candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT); } - else if (valueParameter.isVararg()) { + else if (valueParameter.getVarargElementType() != null) { candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); } else { @@ -182,7 +182,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } private static void put(ResolvedCallImpl candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map varargs) { - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { VarargValueArgument vararg = varargs.get(valueParameterDescriptor); if (vararg == null) { vararg = new VarargValueArgument(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 52af4480db1..522a1b0d156 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -147,7 +147,7 @@ public class ErrorUtils { ERROR_PARAMETER_TYPE, ERROR_PARAMETER_TYPE, false, - false)); + null)); } return result; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 70db11221a4..e637d05de72 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -378,7 +378,7 @@ public class JetStandardClasses { List valueParameters = Lists.newArrayList(); for (int i = first; i <= last; i++) { JetType parameterType = arguments.get(i).getType(); - ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.emptyList(), "p" + i, null, parameterType, false, false); + ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.emptyList(), "p" + i, null, parameterType, false, null); valueParameters.add(valueParameterDescriptor); } return valueParameters; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 6029d19c358..7b35d6f582e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -316,8 +316,8 @@ public class JetStandardLibrary { } @NotNull - public JetType getArrayType(@NotNull Variance variance, @NotNull JetType argument) { - List types = Collections.singletonList(new TypeProjection(variance, argument)); + public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) { + List types = Collections.singletonList(new TypeProjection(projectionType, argument)); return new JetTypeImpl( Collections.emptyList(), getArray().getTypeConstructor(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java index e0b992f735e..a8c2fde4a6c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java @@ -87,7 +87,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) { ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); ValueParameterDescriptor it = new ValueParameterDescriptorImpl( - functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg() + functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType() ); valueParameterDescriptors.add(it); parameterTypes.add(it.getOutType()); diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 2a52a1d3f54..a9bddbb2c7a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -133,7 +133,7 @@ public class DescriptorRenderer implements Renderer { @Override public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { builder.append(renderKeyword("value-parameter")).append(" "); - if (descriptor.isVararg()) { + if (descriptor.getVarargElementType() != null) { builder.append(renderKeyword("vararg")).append(" "); } return super.visitValueParameterDescriptor(descriptor, builder); diff --git a/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet b/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet new file mode 100644 index 00000000000..2ce06de117c --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet @@ -0,0 +1,26 @@ +// KT-389 Wrong type inference for varargs etc. + +import java.util.* + +fun foob(vararg a : Byte) : ByteArray = a +fun fooc(vararg a : Char) : CharArray = a +fun foos(vararg a : Short) : ShortArray = a +fun fooi(vararg a : Int) : IntArray = a +fun fool(vararg a : Long) : LongArray = a +fun food(vararg a : Double) : DoubleArray = a +fun foof(vararg a : Float) : FloatArray = a +fun foob(vararg a : Boolean) : BooleanArray = a +fun foos(vararg a : String) : Array = a + +fun test() { + Arrays.asList(1, 2, 3) + Arrays.asList(1, 2, 3) + + foob(1, 2, 3) + foos(1, 2, 3) + fooc('1', '2', '3') + fooi(1, 2, 3) + fool(1, 2, 3) + food(1.0, 2.0, 3.0) + foof(1.0.flt, 2.0.flt, 3.0.flt) +} \ No newline at end of file