KT-389 Wrong type inference for varargs etc.
This commit is contained in:
@@ -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);
|
||||
|
||||
+13
-2
@@ -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.<AnnotationDescriptor>emptyList(), // TODO
|
||||
name == null ? "p" + i : name,
|
||||
null, // TODO : review
|
||||
semanticServices.getTypeTransformer().transformToType(parameter.getType()),
|
||||
outType,
|
||||
false,
|
||||
parameter.isVarArgs()
|
||||
varargElementType
|
||||
));
|
||||
}
|
||||
return result;
|
||||
|
||||
+4
-30
@@ -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<ValueParameterDescriptor> 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<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> 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;
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+10
-9
@@ -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<AnnotationDescriptor> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
|
||||
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
|
||||
@@ -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<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions();
|
||||
for (JetExpression argumentExpression : argumentExpressions) {
|
||||
|
||||
+4
-4
@@ -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 <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
|
||||
if (valueParameterDescriptor.isVararg()) {
|
||||
if (valueParameterDescriptor.getVarargElementType() != null) {
|
||||
VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
|
||||
if (vararg == null) {
|
||||
vararg = new VarargValueArgument();
|
||||
|
||||
@@ -147,7 +147,7 @@ public class ErrorUtils {
|
||||
ERROR_PARAMETER_TYPE,
|
||||
ERROR_PARAMETER_TYPE,
|
||||
false,
|
||||
false));
|
||||
null));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ public class JetStandardClasses {
|
||||
List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
|
||||
for (int i = first; i <= last; i++) {
|
||||
JetType parameterType = arguments.get(i).getType();
|
||||
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, false);
|
||||
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, null);
|
||||
valueParameters.add(valueParameterDescriptor);
|
||||
}
|
||||
return valueParameters;
|
||||
|
||||
@@ -316,8 +316,8 @@ public class JetStandardLibrary {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType getArrayType(@NotNull Variance variance, @NotNull JetType argument) {
|
||||
List<TypeProjection> types = Collections.singletonList(new TypeProjection(variance, argument));
|
||||
public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) {
|
||||
List<TypeProjection> types = Collections.singletonList(new TypeProjection(projectionType, argument));
|
||||
return new JetTypeImpl(
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
getArray().getTypeConstructor(),
|
||||
|
||||
+1
-1
@@ -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.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg()
|
||||
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
|
||||
);
|
||||
valueParameterDescriptors.add(it);
|
||||
parameterTypes.add(it.getOutType());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<String> = a
|
||||
|
||||
fun test() {
|
||||
Arrays.asList(1, 2, 3)
|
||||
Arrays.asList<Int>(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)
|
||||
}
|
||||
Reference in New Issue
Block a user