diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index 88ce2d7883b..373ab6f0d09 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -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.emptyList(), receiverType); + myAccessor.setType(pd.getInType(), pd.getOutType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); PropertyGetterDescriptor pgd = new PropertyGetterDescriptor( myAccessor, Collections.emptyList(), myAccessor.getModality(), 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 8208b807e8f..ca36c9b3e16 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -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 createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List 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 alphaConvertTypeParameters(D candidate) { + return (D) candidate.substitute(MAKE_TYPE_PARAMETERS_FRESH); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 11cf22db63f..ab9fb21417c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -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 overriddenProperties = Sets.newLinkedHashSet(); private final PropertyDescriptor original; + private ReceiverDescriptor expectedThisObject; private ReceiverDescriptor receiver; private List 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.emptyList(), receiverType); + ) { + this(containingDeclaration, annotations, modality, visibility, isVar, name); + setType(inType, outType, Collections.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.emptyList(), receiverType); + setType(inType, outType, Collections.emptyList(), expectedThisObject, receiverType); } - public void setType(@Nullable JetType inType, @NotNull JetType outType, - @NotNull List typeParameters, - @Nullable JetType receiverType - ) - { + public void setType(@Nullable JetType inType, @NotNull JetType outType, @NotNull List 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 typeParameters, @NotNull ReceiverDescriptor receiver) - { + public void setType(@Nullable JetType inType, @NotNull JetType outType, @NotNull List 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 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()), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index 87b1f0a72b2..168533ea03d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -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.emptyList(), ReceiverDescriptor.NO_RECEIVER); + propertyDescriptor.setType(null, classDescriptor.getDefaultType(), Collections.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 ? "" : name ); PropertyGetterDescriptor getter = createDefaultGetter(propertyDescriptor); PropertySetterDescriptor setter = createDefaultSetter(propertyDescriptor); JetType inType = isMutable ? type : null; - propertyDescriptor.setType(inType, type, Collections.emptyList(), ReceiverDescriptor.NO_RECEIVER); + propertyDescriptor.setType(inType, type, Collections.emptyList(), DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), ReceiverDescriptor.NO_RECEIVER); propertyDescriptor.initialize(getter, setter); getter.initialize(propertyDescriptor.getOutType()); 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 3db5f295442..de1fb006eca 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 @@ -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 = 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 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 diff --git a/compiler/testData/diagnostics/tests/regressions/kt743.jet b/compiler/testData/diagnostics/tests/regressions/kt743.jet new file mode 100644 index 00000000000..faecff09851 --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt743.jet @@ -0,0 +1,6 @@ +//KT-743 Wrong type inference +// +JDK +class List(val head: T, val tail: List? = null) + +fun List.map(f: fun(T): Q): List? = tail.sure>().map(f) +fun foo(t : T) : T = foo(t) \ No newline at end of file