提交 739417dc 编写于 作者: A Andrey Breslav

KT-389 Wrong type inference for varargs etc.

上级 496bdc28
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
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);
}
......@@ -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) {
......
......@@ -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(),
......
......@@ -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);
......
// 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)
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册