KT-743 Wrong type inference
This commit is contained in:
@@ -226,11 +226,10 @@ public abstract class CodegenContext {
|
||||
pd.getModality(),
|
||||
pd.getVisibility(),
|
||||
pd.isVar(),
|
||||
pd.getExpectedThisObject(),
|
||||
pd.getName() + "$bridge$" + accessors.size()
|
||||
);
|
||||
JetType receiverType = pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null;
|
||||
myAccessor.setType(pd.getInType(), pd.getOutType(), Collections.<TypeParameterDescriptor>emptyList(), receiverType);
|
||||
myAccessor.setType(pd.getInType(), pd.getOutType(), Collections.<TypeParameterDescriptor>emptyList(), pd.getExpectedThisObject(), receiverType);
|
||||
|
||||
PropertyGetterDescriptor pgd = new PropertyGetterDescriptor(
|
||||
myAccessor, Collections.<AnnotationDescriptor>emptyList(), myAccessor.getModality(),
|
||||
|
||||
@@ -16,6 +16,19 @@ import java.util.*;
|
||||
* @author abreslav
|
||||
*/
|
||||
public class FunctionDescriptorUtil {
|
||||
private static final TypeSubstitutor MAKE_TYPE_PARAMETERS_FRESH = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
|
||||
|
||||
@Override
|
||||
public TypeProjection get(TypeConstructor key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
|
||||
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
|
||||
|
||||
@@ -93,4 +106,8 @@ public class FunctionDescriptorUtil {
|
||||
JetStandardClasses.getReturnTypeFromFunctionType(functionType),
|
||||
Modality.FINAL, Visibility.LOCAL);
|
||||
}
|
||||
|
||||
public static <D extends CallableDescriptor> D alphaConvertTypeParameters(D candidate) {
|
||||
return (D) candidate.substitute(MAKE_TYPE_PARAMETERS_FRESH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
import org.jetbrains.jet.lang.types.Variance;
|
||||
@@ -17,6 +18,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
@@ -25,10 +28,10 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
private final Modality modality;
|
||||
private final Visibility visibility;
|
||||
private final boolean isVar;
|
||||
private final ReceiverDescriptor expectedThisObject;
|
||||
private final Set<PropertyDescriptor> overriddenProperties = Sets.newLinkedHashSet();
|
||||
private final PropertyDescriptor original;
|
||||
|
||||
private ReceiverDescriptor expectedThisObject;
|
||||
private ReceiverDescriptor receiver;
|
||||
private List<TypeParameterDescriptor> typeParemeters;
|
||||
private PropertyGetterDescriptor getter;
|
||||
@@ -41,14 +44,11 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
@NotNull Modality modality,
|
||||
@NotNull Visibility visibility,
|
||||
boolean isVar,
|
||||
@NotNull ReceiverDescriptor expectedThisObject,
|
||||
@NotNull String name) {
|
||||
super(containingDeclaration, annotations, name);
|
||||
// assert outType != null;
|
||||
this.isVar = isVar;
|
||||
this.modality = modality;
|
||||
this.visibility = visibility;
|
||||
this.expectedThisObject = expectedThisObject;
|
||||
this.original = original == null ? this : original.getOriginal();
|
||||
}
|
||||
|
||||
@@ -58,9 +58,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
@NotNull Modality modality,
|
||||
@NotNull Visibility visibility,
|
||||
boolean isVar,
|
||||
@NotNull ReceiverDescriptor expectedThisObject,
|
||||
@NotNull String name) {
|
||||
this(null, containingDeclaration, annotations, modality, visibility, isVar, expectedThisObject, name);
|
||||
this(null, containingDeclaration, annotations, modality, visibility, isVar, name);
|
||||
}
|
||||
|
||||
public PropertyDescriptor(
|
||||
@@ -74,10 +73,9 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
@NotNull String name,
|
||||
@Nullable JetType inType,
|
||||
@NotNull JetType outType
|
||||
)
|
||||
{
|
||||
this(containingDeclaration, annotations, modality, visibility, isVar, expectedThisObject, name);
|
||||
setType(inType, outType, Collections.<TypeParameterDescriptor>emptyList(), receiverType);
|
||||
) {
|
||||
this(containingDeclaration, annotations, modality, visibility, isVar, name);
|
||||
setType(inType, outType, Collections.<TypeParameterDescriptor>emptyList(), expectedThisObject, receiverType);
|
||||
}
|
||||
|
||||
private PropertyDescriptor(
|
||||
@@ -86,8 +84,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
@NotNull ReceiverDescriptor expectedThisObject,
|
||||
@Nullable JetType inType,
|
||||
@NotNull JetType outType
|
||||
)
|
||||
{
|
||||
) {
|
||||
this(
|
||||
original,
|
||||
original.getContainingDeclaration(),
|
||||
@@ -95,26 +92,19 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
original.getModality(),
|
||||
original.getVisibility(),
|
||||
original.isVar,
|
||||
expectedThisObject,
|
||||
original.getName()
|
||||
);
|
||||
setType(inType, outType, Collections.<TypeParameterDescriptor>emptyList(), receiverType);
|
||||
setType(inType, outType, Collections.<TypeParameterDescriptor>emptyList(), expectedThisObject, receiverType);
|
||||
}
|
||||
|
||||
public void setType(@Nullable JetType inType, @NotNull JetType outType,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@Nullable JetType receiverType
|
||||
)
|
||||
{
|
||||
public void setType(@Nullable JetType inType, @NotNull JetType outType, @NotNull List<TypeParameterDescriptor> typeParameters, @NotNull ReceiverDescriptor expectedThisObject, @Nullable JetType receiverType) {
|
||||
ReceiverDescriptor receiver = receiverType == null
|
||||
? ReceiverDescriptor.NO_RECEIVER
|
||||
? NO_RECEIVER
|
||||
: new ExtensionReceiver(this, receiverType);
|
||||
setType(inType, outType, typeParameters, receiver);
|
||||
setType(inType, outType, typeParameters, expectedThisObject, receiver);
|
||||
}
|
||||
|
||||
public void setType(@Nullable JetType inType, @NotNull JetType outType,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull ReceiverDescriptor receiver)
|
||||
{
|
||||
public void setType(@Nullable JetType inType, @NotNull JetType outType, @NotNull List<TypeParameterDescriptor> typeParameters, @NotNull ReceiverDescriptor expectedThisObject, @NotNull ReceiverDescriptor receiver) {
|
||||
assert !isVar || inType != null;
|
||||
setInType(inType);
|
||||
setOutType(outType);
|
||||
@@ -122,11 +112,10 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
this.typeParemeters = typeParameters;
|
||||
|
||||
this.receiver = receiver;
|
||||
this.expectedThisObject = expectedThisObject;
|
||||
}
|
||||
|
||||
public void initialize(
|
||||
@Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter)
|
||||
{
|
||||
public void initialize(@Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) {
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
}
|
||||
@@ -191,7 +180,15 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyDescriptor substitute(TypeSubstitutor substitutor) {
|
||||
public PropertyDescriptor substitute(TypeSubstitutor originalSubstitutor) {
|
||||
if (originalSubstitutor.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
PropertyDescriptor substitutedDescriptor = new PropertyDescriptor(this, getContainingDeclaration(), getAnnotations(), getModality(), getVisibility(), isVar(), getName());
|
||||
|
||||
List<TypeParameterDescriptor> substitutedTypeParameters = Lists.newArrayList();
|
||||
TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters);
|
||||
|
||||
JetType originalInType = getInType();
|
||||
JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE);
|
||||
JetType originalOutType = getOutType();
|
||||
@@ -199,6 +196,16 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
if (inType == null && outType == null) {
|
||||
return null; // TODO : tell the user that the property was projected out
|
||||
}
|
||||
|
||||
ReceiverDescriptor substitutedExpectedThisObject;
|
||||
if (expectedThisObject.exists()) {
|
||||
JetType substitutedExpectedThisObjectType = substitutor.substitute(getExpectedThisObject().getType(), Variance.INVARIANT);
|
||||
substitutedExpectedThisObject = new TransientReceiver(substitutedExpectedThisObjectType);
|
||||
}
|
||||
else {
|
||||
substitutedExpectedThisObject = NO_RECEIVER;
|
||||
}
|
||||
|
||||
JetType substitutedReceiverType;
|
||||
if (receiver.exists()) {
|
||||
substitutedReceiverType = substitutor.substitute(receiver.getType(), Variance.IN_VARIANCE);
|
||||
@@ -207,13 +214,10 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
else {
|
||||
substitutedReceiverType = null;
|
||||
}
|
||||
return new PropertyDescriptor(
|
||||
this,
|
||||
substitutedReceiverType,
|
||||
expectedThisObject.exists() ? new TransientReceiver(substitutor.substitute(expectedThisObject.getType(), Variance.IN_VARIANCE)) : expectedThisObject,
|
||||
inType,
|
||||
outType
|
||||
);
|
||||
|
||||
substitutedDescriptor.setType(inType, outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType);
|
||||
|
||||
return substitutedDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,10 +248,9 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
|
||||
newOwner,
|
||||
Lists.newArrayList(getAnnotations()),
|
||||
DescriptorUtils.convertModality(modality, makeNonAbstract), visibility, isVar,
|
||||
expectedThisObject,
|
||||
getName());
|
||||
|
||||
propertyDescriptor.setType(getInType(), getOutType(), DescriptorUtils.copyTypeParameters(propertyDescriptor, getTypeParameters()), receiver.exists() ? receiver.getType() : null);
|
||||
propertyDescriptor.setType(getInType(), getOutType(), DescriptorUtils.copyTypeParameters(propertyDescriptor, getTypeParameters()), expectedThisObject, receiver.exists() ? receiver.getType() : null);
|
||||
|
||||
PropertyGetterDescriptor newGetter = getter == null ? null : new PropertyGetterDescriptor(
|
||||
propertyDescriptor, Lists.newArrayList(getter.getAnnotations()),
|
||||
|
||||
@@ -475,11 +475,10 @@ public class DescriptorResolver {
|
||||
Modality.FINAL,
|
||||
resolveVisibilityFromModifiers(objectDeclaration.getModifierList()),
|
||||
false,
|
||||
DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration),
|
||||
JetPsiUtil.safeName(objectDeclaration.getName())
|
||||
);
|
||||
|
||||
propertyDescriptor.setType(null, classDescriptor.getDefaultType(), Collections.<TypeParameterDescriptor>emptyList(), ReceiverDescriptor.NO_RECEIVER);
|
||||
propertyDescriptor.setType(null, classDescriptor.getDefaultType(), Collections.<TypeParameterDescriptor>emptyList(), DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), ReceiverDescriptor.NO_RECEIVER);
|
||||
propertyDescriptor.initialize(null, null);
|
||||
|
||||
JetObjectDeclarationName nameAsDeclaration = objectDeclaration.getNameAsDeclaration();
|
||||
@@ -518,7 +517,6 @@ public class DescriptorResolver {
|
||||
resolveModalityFromModifiers(property.getModifierList(), defaultModality),
|
||||
resolveVisibilityFromModifiers(property.getModifierList()),
|
||||
isVar,
|
||||
DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration),
|
||||
JetPsiUtil.safeName(property.getName())
|
||||
);
|
||||
|
||||
@@ -555,7 +553,7 @@ public class DescriptorResolver {
|
||||
JetType type = getVariableType(scope2, property, true);
|
||||
|
||||
JetType inType = isVar ? type : null;
|
||||
propertyDescriptor.setType(inType, type, typeParameterDescriptors, receiverDescriptor);
|
||||
propertyDescriptor.setType(inType, type, typeParameterDescriptors, DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), receiverDescriptor);
|
||||
|
||||
PropertyGetterDescriptor getter = resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor);
|
||||
PropertySetterDescriptor setter = resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor);
|
||||
@@ -838,14 +836,13 @@ public class DescriptorResolver {
|
||||
resolveModalityFromModifiers(parameter.getModifierList(), Modality.FINAL),
|
||||
resolveVisibilityFromModifiers(parameter.getModifierList()),
|
||||
isMutable,
|
||||
DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor),
|
||||
name == null ? "<no name>" : name
|
||||
);
|
||||
PropertyGetterDescriptor getter = createDefaultGetter(propertyDescriptor);
|
||||
PropertySetterDescriptor setter = createDefaultSetter(propertyDescriptor);
|
||||
|
||||
JetType inType = isMutable ? type : null;
|
||||
propertyDescriptor.setType(inType, type, Collections.<TypeParameterDescriptor>emptyList(), ReceiverDescriptor.NO_RECEIVER);
|
||||
propertyDescriptor.setType(inType, type, Collections.<TypeParameterDescriptor>emptyList(), DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), ReceiverDescriptor.NO_RECEIVER);
|
||||
propertyDescriptor.initialize(getter, setter);
|
||||
getter.initialize(propertyDescriptor.getOutType());
|
||||
|
||||
|
||||
@@ -433,15 +433,25 @@ public class CallResolver {
|
||||
|
||||
ConstraintSystem constraintSystem = new ConstraintSystemImpl(new DebugConstraintResolutionListener(debugInfo));
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
||||
// If the call is recursive, e.g.
|
||||
// fun foo<T>(t : T) : T = foo(t)
|
||||
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
|
||||
// because constraints become trivial (T :< T), and inference fails
|
||||
//
|
||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||
CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
|
||||
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
|
||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
|
||||
}
|
||||
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemImpl.makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE);
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemImpl.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE);
|
||||
|
||||
// Value parameters
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument valueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||
ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
|
||||
|
||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
|
||||
|
||||
@@ -463,25 +473,29 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
|
||||
ReceiverDescriptor receiverParameter = candidate.getReceiverParameter();
|
||||
ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
|
||||
if (receiverArgument.exists() && receiverParameter.exists()) {
|
||||
constraintSystem.addSubtypingConstraint(receiverArgument.getType(), receiverParameter.getType());
|
||||
}
|
||||
|
||||
// Return type
|
||||
if (expectedType != NO_EXPECTED_TYPE) {
|
||||
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
|
||||
constraintSystem.addSubtypingConstraint(candidateWithFreshVariables.getReturnType(), expectedType);
|
||||
}
|
||||
|
||||
// Solution
|
||||
ConstraintSystemSolution solution = constraintSystem.solve();
|
||||
if (solution.getStatus().isSuccessful()) {
|
||||
D substitute = (D) candidate.substitute(solution.getSubstitutor());
|
||||
D substitute = (D) candidateWithFreshVariables.substitute(solution.getSubstitutor());
|
||||
assert substitute != null;
|
||||
replaceValueParametersWithSubstitutedOnes(candidateCall, substitute);
|
||||
candidateCall.setResultingDescriptor(substitute);
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
|
||||
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(typeParameterDescriptor));
|
||||
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(candidateWithFreshVariables.getTypeParameters().get(typeParameterDescriptor.getIndex())));
|
||||
}
|
||||
|
||||
// Here we type check the arguments with inferred types expected
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//KT-743 Wrong type inference
|
||||
// +JDK
|
||||
class List<T>(val head: T, val tail: List<T>? = null)
|
||||
|
||||
fun <T, Q> List<T>.map(f: fun(T): Q): List<T>? = tail.sure<List<T>>().map(f)
|
||||
fun foo<T>(t : T) : T = foo(t)
|
||||
Reference in New Issue
Block a user