Converted ConstraintSystem to Kotlin

This commit is contained in:
Svetlana Isakova
2014-07-21 13:16:53 +04:00
parent 38d38e14c8
commit 578f6d4811
9 changed files with 390 additions and 641 deletions
@@ -428,8 +428,8 @@ public class Renderers {
Function<TypeBoundsImpl.Bound, String> renderBound = new Function<TypeBoundsImpl.Bound, String>() { Function<TypeBoundsImpl.Bound, String> renderBound = new Function<TypeBoundsImpl.Bound, String>() {
@Override @Override
public String fun(TypeBoundsImpl.Bound bound) { public String fun(TypeBoundsImpl.Bound bound) {
String arrow = bound.kind == LOWER_BOUND ? ">: " : bound.kind == UPPER_BOUND ? "<: " : ":= "; String arrow = bound.getKind() == LOWER_BOUND ? ">: " : bound.getKind() == UPPER_BOUND ? "<: " : ":= ";
return arrow + RENDER_TYPE.render(bound.type) + '(' + bound.position + ')'; return arrow + RENDER_TYPE.render(bound.getConstrainingType()) + '(' + bound.getPosition() + ')';
} }
}; };
Name typeVariableName = typeBounds.getTypeVariable().getName(); Name typeVariableName = typeBounds.getTypeVariable().getName();
@@ -134,7 +134,7 @@ public class CallCompleter(
trace: BindingTrace trace: BindingTrace
) { ) {
fun updateSystemIfSuccessful(update: (ConstraintSystem) -> Boolean) { fun updateSystemIfSuccessful(update: (ConstraintSystem) -> Boolean) {
val copy = getConstraintSystem()!!.copy() val copy = (getConstraintSystem() as ConstraintSystemImpl).copy()
if (update(copy)) { if (update(copy)) {
setConstraintSystem(copy) setConstraintSystem(copy)
} }
@@ -34,6 +34,7 @@ public class ConstraintPosition {
private static final Map<Integer, ConstraintPosition> valueParameterPositions = new HashMap<Integer, ConstraintPosition>(); private static final Map<Integer, ConstraintPosition> valueParameterPositions = new HashMap<Integer, ConstraintPosition>();
private static final Map<Integer, ConstraintPosition> typeBoundPositions = new HashMap<Integer, ConstraintPosition>(); private static final Map<Integer, ConstraintPosition> typeBoundPositions = new HashMap<Integer, ConstraintPosition>();
@NotNull
public static ConstraintPosition getValueParameterPosition(int index) { public static ConstraintPosition getValueParameterPosition(int index) {
ConstraintPosition position = valueParameterPositions.get(index); ConstraintPosition position = valueParameterPositions.get(index);
if (position == null) { if (position == null) {
@@ -43,6 +44,7 @@ public class ConstraintPosition {
return position; return position;
} }
@NotNull
public static ConstraintPosition getTypeBoundPosition(int index) { public static ConstraintPosition getTypeBoundPosition(int index) {
ConstraintPosition position = typeBoundPositions.get(index); ConstraintPosition position = typeBoundPositions.get(index);
if (position == null) { if (position == null) {
@@ -74,6 +76,7 @@ public class ConstraintPosition {
} }
} }
@NotNull
public static ConstraintPosition getCompoundConstraintPosition(ConstraintPosition... positions) { public static ConstraintPosition getCompoundConstraintPosition(ConstraintPosition... positions) {
return new CompoundConstraintPosition(Arrays.asList(positions)); return new CompoundConstraintPosition(Arrays.asList(positions));
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2013 JetBrains s.r.o. * Copyright 2010-2014 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,30 +14,24 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.resolve.calls.inference; package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeSubstitutor
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Map; public trait ConstraintSystem {
import java.util.Set;
public interface ConstraintSystem {
/** /**
* Registers variables in a constraint system. * Registers variables in a constraint system.
*/ */
void registerTypeVariables(@NotNull Map<TypeParameterDescriptor, Variance> typeVariables); public fun registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>)
/** /**
* Returns a set of all registered type variables. * Returns a set of all registered type variables.
*/ */
@NotNull public fun getTypeVariables(): Set<TypeParameterDescriptor>
Set<TypeParameterDescriptor> getTypeVariables();
/** /**
* Adds a constraint that the constraining type is a subtype of the subject type.<p/> * Adds a constraint that the constraining type is a subtype of the subject type.<p/>
@@ -46,7 +40,7 @@ public interface ConstraintSystem {
* For example, for {@code "fun <T> id(t: T) {}"} to infer <tt>T</tt> in invocation <tt>"id(1)"</tt> * For example, for {@code "fun <T> id(t: T) {}"} to infer <tt>T</tt> in invocation <tt>"id(1)"</tt>
* should be generated a constraint <tt>"Int is a subtype of T"</tt> where T is a subject type, and Int is a constraining type. * should be generated a constraint <tt>"Int is a subtype of T"</tt> where T is a subject type, and Int is a constraining type.
*/ */
void addSubtypeConstraint(@Nullable JetType constrainingType, @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition); public fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition)
/** /**
* Adds a constraint that the constraining type is a supertype of the subject type. <p/> * Adds a constraint that the constraining type is a supertype of the subject type. <p/>
@@ -55,17 +49,15 @@ public interface ConstraintSystem {
* For example, for {@code "fun <T> create() : T"} to infer <tt>T</tt> in invocation <tt>"val i: Int = create()"</tt> * For example, for {@code "fun <T> create() : T"} to infer <tt>T</tt> in invocation <tt>"val i: Int = create()"</tt>
* should be generated a constraint <tt>"Int is a supertype of T"</tt> where T is a subject type, and Int is a constraining type. * should be generated a constraint <tt>"Int is a supertype of T"</tt> where T is a subject type, and Int is a constraining type.
*/ */
void addSupertypeConstraint(@Nullable JetType constrainingType, @NotNull JetType subjectType, @NotNull ConstraintPosition constraintPosition); public fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition)
@NotNull public fun getStatus(): ConstraintSystemStatus
ConstraintSystemStatus getStatus();
/** /**
* Returns the resulting type constraints of solving the constraint system for specific type variable. <p/> * Returns the resulting type constraints of solving the constraint system for specific type variable. <p/>
* Returns null if the type variable was not registered. * Returns null if the type variable was not registered.
*/ */
@NotNull public fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds
TypeBounds getTypeBounds(@NotNull TypeParameterDescriptor typeVariable);
/** /**
* Returns a result of solving the constraint system (mapping from the type variable to the resulting type projection). <p/> * Returns a result of solving the constraint system (mapping from the type variable to the resulting type projection). <p/>
@@ -76,16 +68,11 @@ public interface ConstraintSystem {
* If the addition of the 'expected type' constraint made the system fail, * If the addition of the 'expected type' constraint made the system fail,
* this constraint is not included in the resulting substitution. * this constraint is not included in the resulting substitution.
*/ */
@NotNull public fun getResultingSubstitutor(): TypeSubstitutor
TypeSubstitutor getResultingSubstitutor();
/** /**
* Returns a current result of solving the constraint system (mapping from the type variable to the resulting type projection). * Returns a current result of solving the constraint system (mapping from the type variable to the resulting type projection).
* If there is no information for type parameter, returns type projection for DONT_CARE type. * If there is no information for type parameter, returns type projection for DONT_CARE type.
*/ */
@NotNull public fun getCurrentSubstitutor(): TypeSubstitutor
TypeSubstitutor getCurrentSubstitutor(); }
@NotNull
ConstraintSystem copy();
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2013 JetBrains s.r.o. * Copyright 2010-2014 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,464 +14,337 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.resolve.calls.inference; package org.jetbrains.jet.lang.resolve.calls.inference
import kotlin.Function1; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import kotlin.KotlinPackage; import org.jetbrains.jet.lang.types.TypeProjection
import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.types.TypeProjectionImpl
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.TypeSubstitutor
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.jet.lang.types.checker.TypingConstraints; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind
import org.jetbrains.jet.utils.UtilsPackage; import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure
import org.jetbrains.jet.lang.types.checker.TypingConstraints
import org.jetbrains.jet.lang.types.TypeConstructor
import java.util.LinkedHashMap
import java.util.HashSet
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.*
import java.util.HashMap
import java.util.ArrayList
import org.jetbrains.kotlin.util.sure
import java.util.*; public class ConstraintSystemImpl : ConstraintSystem {
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL; public enum class ConstraintKind {
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE; SUB_TYPE
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.Bound; EQUAL
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*;
import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE;
public class ConstraintSystemImpl implements ConstraintSystem {
public enum ConstraintKind {
SUB_TYPE, EQUAL
} }
private final Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds = private val typeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
new LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>(); private val errorConstraintPositions = HashSet<ConstraintPosition>()
private final Set<ConstraintPosition> errorConstraintPositions = new HashSet<ConstraintPosition>(); private var hasErrorInConstrainingTypes: Boolean = false
private boolean hasErrorInConstrainingTypes;
private final ConstraintSystemStatus constraintSystemStatus = new ConstraintSystemStatus() { private val constraintSystemStatus = object : ConstraintSystemStatus {
// for debug ConstraintsUtil.getDebugMessageForStatus might be used // for debug ConstraintsUtil.getDebugMessageForStatus might be used
@Override override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
public boolean isSuccessful() {
return !hasContradiction() && !hasUnknownParameters(); override fun hasContradiction() = hasTypeConstructorMismatch() || hasConflictingConstraints()
override fun hasViolatedUpperBound(): Boolean {
if (isSuccessful()) return false
return getSystemWithoutWeakConstraints().getStatus().isSuccessful()
} }
@Override override fun hasConflictingConstraints(): Boolean {
public boolean hasContradiction() { for (typeBounds in typeParameterBounds.values()) {
return hasTypeConstructorMismatch() || hasConflictingConstraints(); if (typeBounds.getValues().size() > 1) return true
}
@Override
public boolean hasViolatedUpperBound() {
if (isSuccessful()) return false;
return getSystemWithoutWeakConstraints().getStatus().isSuccessful();
}
@Override
public boolean hasConflictingConstraints() {
for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
if (typeBounds.getValues().size() > 1) return true;
} }
return false; return false
} }
@Override override fun hasUnknownParameters(): Boolean {
public boolean hasUnknownParameters() { for (typeBounds in typeParameterBounds.values()) {
for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
if (typeBounds.isEmpty()) { if (typeBounds.isEmpty()) {
return true; return true
} }
} }
return false; return false
} }
@Override override fun hasTypeConstructorMismatch() = !errorConstraintPositions.isEmpty()
public boolean hasTypeConstructorMismatch() {
return !errorConstraintPositions.isEmpty();
}
@Override override fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition) =
public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) { errorConstraintPositions.contains(constraintPosition)
return errorConstraintPositions.contains(constraintPosition);
}
@Override override fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean {
public boolean hasOnlyErrorsFromPosition(ConstraintPosition constraintPosition) { if (isSuccessful()) return false
if (isSuccessful()) return false; val systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition)
ConstraintSystem systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition);
if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) { if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) {
return true; return true
} }
if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(constraintPosition)) { if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(constraintPosition)) {
// e.g. if systemWithoutConstraintsFromPosition has unknown type parameters, it's not successful // e.g. if systemWithoutConstraintsFromPosition has unknown type parameters, it's not successful
return true; return true
} }
return false; return false
} }
@Override override fun hasErrorInConstrainingTypes() = hasErrorInConstrainingTypes
public boolean hasErrorInConstrainingTypes() { }
return hasErrorInConstrainingTypes;
}
};
@NotNull private fun getParameterToInferredValueMap(typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>, getDefaultTypeProjection: Function1<TypeParameterDescriptor, TypeProjection>): Map<TypeParameterDescriptor, TypeProjection> {
private static Map<TypeParameterDescriptor, TypeProjection> getParameterToInferredValueMap( val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
@NotNull Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds, for ((typeParameter, typeBounds) in typeParameterBounds) {
@NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultTypeProjection val typeProjection: TypeProjection
) { val value = typeBounds.getValue()
Map<TypeParameterDescriptor, TypeProjection> substitutionContext = if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) {
UtilsPackage.newHashMapWithExpectedSize(typeParameterBounds.size()); typeProjection = TypeProjectionImpl(value)
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeParameter = entry.getKey();
TypeBounds typeBounds = entry.getValue();
TypeProjection typeProjection;
JetType value = typeBounds.getValue();
if (value != null && !TypeUtils.containsSpecialType(value, TypeUtils.DONT_CARE)) {
typeProjection = new TypeProjectionImpl(value);
} }
else { else {
typeProjection = getDefaultTypeProjection.invoke(typeParameter); typeProjection = getDefaultTypeProjection.invoke(typeParameter)
} }
substitutionContext.put(typeParameter, typeProjection); substitutionContext.put(typeParameter, typeProjection)
} }
return substitutionContext; return substitutionContext
} }
private TypeSubstitutor replaceUninferredBy(@NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultValue) { private fun replaceUninferredBy(getDefaultValue: (TypeParameterDescriptor) -> TypeProjection): TypeSubstitutor {
return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(typeParameterBounds, getDefaultValue)); return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(typeParameterBounds, getDefaultValue))
} }
private TypeSubstitutor replaceUninferredBy(@NotNull final JetType defaultValue) { private fun replaceUninferredBy(defaultValue: JetType): TypeSubstitutor {
return replaceUninferredBy( return replaceUninferredBy { TypeProjectionImpl(defaultValue) }
new Function1<TypeParameterDescriptor, TypeProjection>() {
@Override
public TypeProjection invoke(TypeParameterDescriptor descriptor) {
return new TypeProjectionImpl(defaultValue);
}
}
);
} }
private TypeSubstitutor replaceUninferredBySpecialErrorType() { private fun replaceUninferredBySpecialErrorType(): TypeSubstitutor {
return replaceUninferredBy( return replaceUninferredBy { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
new Function1<TypeParameterDescriptor, TypeProjection>() {
@Override
public TypeProjection invoke(TypeParameterDescriptor descriptor) {
return new TypeProjectionImpl(ErrorUtils.createUninferredParameterType(descriptor));
}
}
);
} }
@NotNull override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
@Override
public ConstraintSystemStatus getStatus() {
return constraintSystemStatus;
}
@Override override fun registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>) {
public void registerTypeVariables(@NotNull Map<TypeParameterDescriptor, Variance> typeVariables) { for ((typeVariable, positionVariance) in typeVariables) {
for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) { typeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable, positionVariance))
TypeParameterDescriptor typeVariable = entry.getKey();
Variance positionVariance = entry.getValue();
typeParameterBounds.put(typeVariable, new TypeBoundsImpl(typeVariable, positionVariance));
} }
TypeSubstitutor constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterBounds.keySet(), DONT_CARE); val constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterBounds.keySet(), DONT_CARE)
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) { for ((typeVariable, typeBounds) in typeParameterBounds) {
TypeParameterDescriptor typeVariable = entry.getKey(); for (declaredUpperBound in typeVariable.getUpperBounds()) {
TypeBoundsImpl typeBounds = entry.getValue(); if (KotlinBuiltIns.getInstance().getNullableAnyType() == declaredUpperBound) continue //todo remove this line (?)
val substitutedBound = constantSubstitutor?.substitute(declaredUpperBound, Variance.INVARIANT)
for (JetType declaredUpperBound : typeVariable.getUpperBounds()) {
if (KotlinBuiltIns.getInstance().getNullableAnyType().equals(declaredUpperBound)) continue; //todo remove this line (?)
JetType substitutedBound = constantSubstitutor.substitute(declaredUpperBound, Variance.INVARIANT);
if (substitutedBound != null) { if (substitutedBound != null) {
typeBounds.addBound(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex())); typeBounds.addBound(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex()))
} }
} }
} }
} }
@Override public fun copy(): ConstraintSystem = createNewConstraintSystemFromThis({ it }, { it.copy() }, { true })
@NotNull
public ConstraintSystem copy() { public fun substituteTypeVariables(typeVariablesMap: (TypeParameterDescriptor) -> TypeParameterDescriptor?): ConstraintSystem {
return createNewConstraintSystemFromThis( // type bounds are proper types and don't contain other variables
UtilsPackage.<TypeParameterDescriptor>identity(), return createNewConstraintSystemFromThis(typeVariablesMap, { it }, { true })
new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
@Override
public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
return typeBounds.copy();
}
},
UtilsPackage.<ConstraintPosition>alwaysTrue()
);
} }
@NotNull public fun filterConstraintsOut(vararg excludePositions: ConstraintPosition): ConstraintSystem {
public ConstraintSystem substituteTypeVariables(@NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) { val positions = excludePositions.toSet()
return createNewConstraintSystemFromThis( return filterConstraints { !positions.contains(it) }
typeVariablesMap,
// type bounds are proper types and don't contain other variables
UtilsPackage.<TypeBoundsImpl>identity(),
UtilsPackage.<ConstraintPosition>alwaysTrue()
);
} }
@NotNull public fun filterConstraints(condition: (ConstraintPosition) -> Boolean): ConstraintSystem {
public ConstraintSystem filterConstraintsOut(@NotNull final ConstraintPosition excludePosition) { return createNewConstraintSystemFromThis({ it }, { it.filter(condition) }, condition)
return filterConstraints(new Function1<ConstraintPosition, Boolean>() { }
@Override
public Boolean invoke(ConstraintPosition constraintPosition) { public fun getSystemWithoutWeakConstraints(): ConstraintSystem {
return !excludePosition.equals(constraintPosition); return filterConstraints {
constraintPosition ->
// 'isStrong' for compound means 'has some strong constraints'
// but for testing absence of weak constraints we need 'has only strong constraints' here
if (constraintPosition is ConstraintPosition.CompoundConstraintPosition) {
val position = constraintPosition as ConstraintPosition.CompoundConstraintPosition
position.consistsOfOnlyStrongConstraints()
} }
}); else {
} constraintPosition.isStrong()
@NotNull
private ConstraintSystem filterConstraints(@NotNull final Function1<ConstraintPosition, Boolean> condition) {
return createNewConstraintSystemFromThis(
UtilsPackage.<TypeParameterDescriptor>identity(),
new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
@Override
public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
return typeBounds.filter(condition);
}
},
condition
);
}
@NotNull
public ConstraintSystem getSystemWithoutWeakConstraints() {
return filterConstraints(new Function1<ConstraintPosition, Boolean>() {
@Override
public Boolean invoke(ConstraintPosition constraintPosition) {
// 'isStrong' for compound means 'has some strong constraints'
// but for testing absence of weak constraints we need 'has only strong constraints' here
if (constraintPosition instanceof ConstraintPosition.CompoundConstraintPosition) {
ConstraintPosition.CompoundConstraintPosition position =
(ConstraintPosition.CompoundConstraintPosition) constraintPosition;
return position.consistsOfOnlyStrongConstraints();
}
return constraintPosition.isStrong();
} }
});
}
@NotNull
private ConstraintSystem createNewConstraintSystemFromThis(
@NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> substituteTypeVariable,
@NotNull Function1<TypeBoundsImpl, TypeBoundsImpl> replaceTypeBounds,
@NotNull Function1<ConstraintPosition, Boolean> filterConstraintPosition
) {
ConstraintSystemImpl newSystem = new ConstraintSystemImpl();
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
TypeParameterDescriptor typeParameter = entry.getKey();
TypeBoundsImpl typeBounds = entry.getValue();
TypeParameterDescriptor newTypeParameter = substituteTypeVariable.invoke(typeParameter);
assert newTypeParameter != null;
newSystem.typeParameterBounds.put(newTypeParameter, replaceTypeBounds.invoke(typeBounds));
} }
newSystem.errorConstraintPositions.addAll(KotlinPackage.filter(errorConstraintPositions, filterConstraintPosition)); }
private fun createNewConstraintSystemFromThis(
substituteTypeVariable: (TypeParameterDescriptor) -> TypeParameterDescriptor?,
replaceTypeBounds: (TypeBoundsImpl) -> TypeBoundsImpl,
filterConstraintPosition: (ConstraintPosition) -> Boolean
): ConstraintSystem {
val newSystem = ConstraintSystemImpl()
for ((typeParameter, typeBounds) in typeParameterBounds) {
val newTypeParameter = substituteTypeVariable(typeParameter)
newSystem.typeParameterBounds.put(newTypeParameter!!, replaceTypeBounds(typeBounds))
}
newSystem.errorConstraintPositions.addAll(errorConstraintPositions.filter(filterConstraintPosition))
//todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes' //todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes'
newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes; newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes
return newSystem; return newSystem
} }
@Override override fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
public void addSupertypeConstraint( if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
@Nullable JetType constrainingType,
@NotNull JetType subjectType,
@NotNull ConstraintPosition constraintPosition
) {
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return;
addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition); addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition)
} }
@Override override fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
public void addSubtypeConstraint( addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition)
@Nullable JetType constrainingType,
@NotNull JetType subjectType,
@NotNull ConstraintPosition constraintPosition
) {
addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
} }
private void addConstraint( private fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
@NotNull ConstraintKind constraintKind, val typeCheckingProcedure = TypeCheckingProcedure(object : TypingConstraints {
@Nullable JetType subType, override fun assertEqualTypes(a: JetType, b: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
@Nullable JetType superType, doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure)
@NotNull final ConstraintPosition constraintPosition return true
) {
TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
@Override
public boolean assertEqualTypes(
@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
) {
doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
return true;
} }
@Override override fun assertEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
public boolean assertEqualTypeConstructors( return a == b
@NotNull TypeConstructor a, @NotNull TypeConstructor b
) {
return a.equals(b);
} }
@Override override fun assertSubtype(subtype: JetType, supertype: JetType, typeCheckingProcedure: TypeCheckingProcedure): Boolean {
public boolean assertSubtype( doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure)
@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure return true
) {
doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
return true;
} }
@Override override fun noCorrespondingSupertype(subtype: JetType, supertype: JetType): Boolean {
public boolean noCorrespondingSupertype( errorConstraintPositions.add(constraintPosition)
@NotNull JetType subtype, @NotNull JetType supertype return true
) {
errorConstraintPositions.add(constraintPosition);
return true;
} }
}); })
doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure); doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure)
} }
private boolean isErrorOrSpecialType(@Nullable JetType type) { private fun isErrorOrSpecialType(type: JetType?): Boolean {
if (TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type)) { if (TypeUtils.isDontCarePlaceholder(type) || ErrorUtils.isUninferredParameter(type)) {
return true; return true
} }
if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) { if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
hasErrorInConstrainingTypes = true; hasErrorInConstrainingTypes = true
return true; return true
} }
return false; return false
} }
private void doAddConstraint( private fun doAddConstraint(
@NotNull ConstraintKind constraintKind, constraintKind: ConstraintKind,
@Nullable JetType subType, subType: JetType?,
@Nullable JetType superType, superType: JetType?,
@NotNull ConstraintPosition constraintPosition, constraintPosition: ConstraintPosition,
@NotNull TypeCheckingProcedure typeCheckingProcedure typeCheckingProcedure: TypeCheckingProcedure
) { ) {
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return
if (subType == null || superType == null) return
if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return; assert(superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
assert subType != null && superType != null; "The type for " + constraintPosition + " shouldn't be a placeholder for function type"
}
assert superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
if (subType == TypeUtils.PLACEHOLDER_FUNCTION_TYPE) { if (subType == TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
if (!KotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) { if (!KotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
if (isMyTypeVariable(superType)) { if (isMyTypeVariable(superType)) {
// a constraint binds type parameter and any function type, so there is no new info and no error // a constraint binds type parameter and any function type, so there is no new info and no error
return; return
} }
errorConstraintPositions.add(constraintPosition); errorConstraintPositions.add(constraintPosition)
} }
return; return
} }
// todo temporary hack // todo temporary hack
// function literal without declaring receiver type { x -> ... } // function literal without declaring receiver type { x -> ... }
// can be considered as extension function if one is expected // can be considered as extension function if one is expected
// (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE) // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
if (constraintKind == SUB_TYPE && KotlinBuiltIns.isFunctionType(subType) && KotlinBuiltIns.isExtensionFunctionType(superType)) { val newSubType = if (constraintKind == SUB_TYPE
subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE); && KotlinBuiltIns.isFunctionType(subType)
&& KotlinBuiltIns.isExtensionFunctionType(superType)) {
createCorrespondingExtensionFunctionType(subType, DONT_CARE)
}
else {
subType : JetType
} }
// can be equal for the recursive invocations: fun simplifyConstraint(subType: JetType, superType: JetType) {
// fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T // can be equal for the recursive invocations:
if (isMyTypeVariable(subType) && isMyTypeVariable(superType) && JetTypeChecker.DEFAULT.equalTypes(subType, superType)) return; // fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
if (subType == superType) return
//todo temporary hack KT-6320 assert(!isMyTypeVariable(subType) || !isMyTypeVariable(superType)) {
if (isMyTypeVariable(subType) && isMyTypeVariable(superType)) return; "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType
assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) : }
"The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
if (isMyTypeVariable(subType)) {
if (isMyTypeVariable(subType)) { val boundKind = if (constraintKind == SUB_TYPE) UPPER_BOUND else EXACT_BOUND
generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND, constraintPosition); generateTypeParameterConstraint(subType, superType, boundKind, constraintPosition)
return; return
}
if (isMyTypeVariable(superType)) {
val boundKind = if (constraintKind == SUB_TYPE) LOWER_BOUND else EXACT_BOUND
generateTypeParameterConstraint(superType, subType, boundKind, constraintPosition)
return
}
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
// but constraint system should be solved anyway
typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType))
} }
if (isMyTypeVariable(superType)) { simplifyConstraint(newSubType, superType)
generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND, constraintPosition);
return;
}
// if superType is nullable and subType is not nullable, unsafe call error will be generated later,
// but constraint system should be solved anyway
typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
} }
private void generateTypeParameterConstraint( private fun generateTypeParameterConstraint(
@NotNull JetType parameterType, parameterType: JetType,
@NotNull JetType constrainingType, constrainingType: JetType,
@NotNull TypeBoundsImpl.BoundKind boundKind, boundKind: TypeBounds.BoundKind,
@NotNull ConstraintPosition constraintPosition constraintPosition: ConstraintPosition
) { ) {
// Here we are handling the case when T! gets a bound Foo (or Foo?) val typeBounds = getTypeBounds(parameterType).sure("constraint should be generated only for type variables")
// In this case, type parameter T is supposed to get the bound Foo!
// Example:
// val c: Collection<Foo> = Collections.singleton(null : Foo?)
// Constraints for T are:
// Foo? <: T!
// Foo >: T!
// both Foo and Foo? transform to Foo! here
if (TypesPackage.isFlexible(parameterType)) {
CustomTypeVariable typeVariable = TypesPackage.getCustomTypeVariable(parameterType);
if (typeVariable != null) {
constrainingType = typeVariable.substitutionResult(constrainingType);
}
}
TypeBoundsImpl typeBounds = getTypeBounds(parameterType);
assert typeBounds != null : "constraint should be generated only for type variables";
if (!parameterType.isMarkedNullable() || !constrainingType.isMarkedNullable()) { if (!parameterType.isMarkedNullable() || !constrainingType.isMarkedNullable()) {
typeBounds.addBound(boundKind, constrainingType, constraintPosition); typeBounds.addBound(boundKind, constrainingType, constraintPosition)
return; return
} }
// For parameter type T: // For parameter type T:
// constraint T? = Int? should transform to T >: Int and T <: Int? // constraint T? = Int? should transform to T >: Int and T <: Int?
// constraint T? >: Int? should transform to T >: Int // constraint T? >: Int? should transform to T >: Int
JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType); val notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType)
if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) { if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
typeBounds.addBound(LOWER_BOUND, notNullConstrainingType, constraintPosition); typeBounds.addBound(LOWER_BOUND, notNullConstrainingType, constraintPosition)
} }
// constraint T? <: Int? should transform to T <: Int? // constraint T? <: Int? should transform to T <: Int?
if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) { if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
typeBounds.addBound(UPPER_BOUND, constrainingType, constraintPosition); typeBounds.addBound(UPPER_BOUND, constrainingType, constraintPosition)
} }
} }
public void processDeclaredBoundConstraints() { public fun processDeclaredBoundConstraints() {
for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) { for ((typeParameterDescriptor, typeBounds) in typeParameterBounds) {
TypeParameterDescriptor typeParameterDescriptor = entry.getKey(); for (declaredUpperBound in typeParameterDescriptor.getUpperBounds()) {
TypeBoundsImpl typeBounds = entry.getValue();
for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
//todo order matters here //todo order matters here
Collection<Bound> bounds = new ArrayList<Bound>(typeBounds.getBounds()); val bounds = ArrayList(typeBounds.bounds)
for (Bound bound : bounds) { for (bound in bounds) {
if (bound.kind == LOWER_BOUND || bound.kind == EXACT_BOUND) { if (bound.kind == LOWER_BOUND || bound.kind == EXACT_BOUND) {
ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition( val position = ConstraintPosition.getCompoundConstraintPosition(ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position)
ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position); addSubtypeConstraint(bound.constrainingType, declaredUpperBound, position)
addSubtypeConstraint(bound.type, declaredUpperBound, position);
} }
} }
ClassifierDescriptor declarationDescriptor = declaredUpperBound.getConstructor().getDeclarationDescriptor(); val declarationDescriptor = declaredUpperBound.getConstructor().getDeclarationDescriptor()
if (declarationDescriptor instanceof TypeParameterDescriptor && typeParameterBounds.containsKey(declarationDescriptor)) { if (declarationDescriptor is TypeParameterDescriptor && typeParameterBounds.containsKey(declarationDescriptor)) {
TypeBoundsImpl typeBoundsForUpperBound = typeParameterBounds.get(declarationDescriptor); val typeBoundsForUpperBound = typeParameterBounds.get(declarationDescriptor)
for (Bound bound : typeBoundsForUpperBound.getBounds()) { for (bound in typeBoundsForUpperBound!!.bounds) {
if (bound.kind == UPPER_BOUND || bound.kind == EXACT_BOUND) { if (bound.kind == UPPER_BOUND || bound.kind == EXACT_BOUND) {
ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition( val position = ConstraintPosition.getCompoundConstraintPosition(ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position)
ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position); typeBounds.addBound(UPPER_BOUND, bound.constrainingType, position)
typeBounds.addBound(UPPER_BOUND, bound.type, position);
} }
} }
} }
@@ -479,64 +352,47 @@ public class ConstraintSystemImpl implements ConstraintSystem {
} }
} }
@NotNull override fun getTypeVariables() = typeParameterBounds.keySet()
@Override
public Set<TypeParameterDescriptor> getTypeVariables() { override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds {
return typeParameterBounds.keySet(); return typeParameterBounds.get(typeVariable).sure(
"TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
} }
@Override private fun getTypeBounds(type: JetType): TypeBoundsImpl? {
@NotNull val parameterDescriptor = type.getConstructor().getDeclarationDescriptor()
public TypeBounds getTypeBounds(@NotNull TypeParameterDescriptor typeVariable) { if (parameterDescriptor is TypeParameterDescriptor) {
TypeBoundsImpl typeBounds = typeParameterBounds.get(typeVariable); return typeParameterBounds.get(parameterDescriptor)
assert typeBounds != null : "TypeParameterDescriptor is not a type variable for constraint system: " + typeVariable;
return typeBounds;
}
@Nullable
private TypeBoundsImpl getTypeBounds(@NotNull JetType type) {
ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
if (parameterDescriptor instanceof TypeParameterDescriptor) {
return typeParameterBounds.get(parameterDescriptor);
} }
return null; return null
} }
private boolean isMyTypeVariable(@NotNull JetType type) { private fun isMyTypeVariable(type: JetType): Boolean {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); val descriptor = type.getConstructor().getDeclarationDescriptor()
return descriptor instanceof TypeParameterDescriptor && typeParameterBounds.get(descriptor) != null; return descriptor is TypeParameterDescriptor && typeParameterBounds.get(descriptor) != null
} }
@NotNull override fun getResultingSubstitutor() = replaceUninferredBySpecialErrorType()
@Override
public TypeSubstitutor getResultingSubstitutor() {
return replaceUninferredBySpecialErrorType();
}
@NotNull override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE)
@Override
public TypeSubstitutor getCurrentSubstitutor() {
return replaceUninferredBy(TypeUtils.DONT_CARE);
}
@NotNull private fun createCorrespondingExtensionFunctionType(functionType: JetType, receiverType: JetType): JetType {
public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) { assert(KotlinBuiltIns.isFunctionType(functionType))
assert KotlinBuiltIns.isFunctionType(functionType);
List<TypeProjection> typeArguments = functionType.getArguments(); val typeArguments = functionType.getArguments()
assert !typeArguments.isEmpty(); assert(!typeArguments.isEmpty())
val arguments = ArrayList<JetType>()
// excluding the last type argument of the function type, which is the return type // excluding the last type argument of the function type, which is the return type
int index = 0; var index = 0
int lastIndex = typeArguments.size() - 1; val lastIndex = typeArguments.size() - 1
List<JetType> arguments = new ArrayList<JetType>(lastIndex); for (typeArgument in typeArguments) {
for (TypeProjection typeArgument : typeArguments) {
if (index < lastIndex) { if (index < lastIndex) {
arguments.add(typeArgument.getType()); arguments.add(typeArgument.getType())
} }
index++; index++
} }
JetType returnType = typeArguments.get(lastIndex).getType(); val returnType = typeArguments.get(lastIndex).getType()
return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType); return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType)
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2013 JetBrains s.r.o. * Copyright 2010-2014 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,24 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.resolve.calls.inference; package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull; public trait ConstraintSystemStatus {
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
public interface ConstraintSystemStatus {
/** /**
* Returns <tt>true</tt> if constraint system has a solution (has no contradiction and has enough information to infer each registered type variable). * Returns <tt>true</tt> if constraint system has a solution (has no contradiction and has enough information to infer each registered type variable).
*/ */
boolean isSuccessful(); public fun isSuccessful(): Boolean
/** /**
* Return <tt>true</tt> if constraint system has no contradiction (it can be not successful because of the lack of information for a type variable). * Return <tt>true</tt> if constraint system has no contradiction (it can be not successful because of the lack of information for a type variable).
*/ */
boolean hasContradiction(); public fun hasContradiction(): Boolean
/** /**
* Returns <tt>true</tt> if type constraints for some type variable are contradicting. <p/> * Returns <tt>true</tt> if type constraints for some type variable are contradicting. <p/>
@@ -41,7 +35,7 @@ public interface ConstraintSystemStatus {
* - <tt>"R is a supertype of Int"</tt> <p/> * - <tt>"R is a supertype of Int"</tt> <p/>
* - <tt>"List&lt;R&gt; is a supertype of List&lt;String&gt;"</tt> which leads to <tt>"R is equal to String"</tt> * - <tt>"List&lt;R&gt; is a supertype of List&lt;String&gt;"</tt> which leads to <tt>"R is equal to String"</tt>
*/ */
boolean hasConflictingConstraints(); public fun hasConflictingConstraints(): Boolean
/** /**
* Returns <tt>true</tt> if contradiction of type constraints comes from declared bounds for type parameters. * Returns <tt>true</tt> if contradiction of type constraints comes from declared bounds for type parameters.
@@ -51,7 +45,7 @@ public interface ConstraintSystemStatus {
* *
* It's the special case of 'hasConflictingConstraints' case. * It's the special case of 'hasConflictingConstraints' case.
*/ */
boolean hasViolatedUpperBound(); public fun hasViolatedUpperBound(): Boolean
/** /**
* Returns <tt>true</tt> if there is no information for some registered type variable. * Returns <tt>true</tt> if there is no information for some registered type variable.
@@ -59,7 +53,7 @@ public interface ConstraintSystemStatus {
* For example, for <pre>fun &lt;E&gt; newList()</pre> in invocation <tt>"val nl = newList()"</tt> * For example, for <pre>fun &lt;E&gt; newList()</pre> in invocation <tt>"val nl = newList()"</tt>
* there is no information to infer type variable <tt>E</tt>. * there is no information to infer type variable <tt>E</tt>.
*/ */
boolean hasUnknownParameters(); public fun hasUnknownParameters(): Boolean
/** /**
* Returns <tt>true</tt> if some constraint cannot be processed because of type constructor mismatch. * Returns <tt>true</tt> if some constraint cannot be processed because of type constructor mismatch.
@@ -67,7 +61,7 @@ public interface ConstraintSystemStatus {
* For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt> * For example, for <pre>fun &lt;R&gt; foo(t: List&lt;R&gt;) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>. * there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>.
*/ */
boolean hasTypeConstructorMismatch(); public fun hasTypeConstructorMismatch(): Boolean
/** /**
* Returns <tt>true</tt> if there is type constructor mismatch error at a specific {@code constraintPosition}. * Returns <tt>true</tt> if there is type constructor mismatch error at a specific {@code constraintPosition}.
@@ -76,17 +70,17 @@ public interface ConstraintSystemStatus {
* there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt> * there is type constructor mismatch: <tt>"HashSet&lt;String&gt; cannot be a subtype of List&lt;R&gt;"</tt>
* at a constraint position {@code ConstraintPosition.getValueParameterPosition(0)}. * at a constraint position {@code ConstraintPosition.getValueParameterPosition(0)}.
*/ */
boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition); public fun hasTypeConstructorMismatchAt(constraintPosition: ConstraintPosition): Boolean
/** /**
* Returns <tt>true</tt> if there is type constructor mismatch only in constraintPosition or * Returns <tt>true</tt> if there is type constructor mismatch only in constraintPosition or
* constraint system is successful without constraints from this position. * constraint system is successful without constraints from this position.
*/ */
boolean hasOnlyErrorsFromPosition(ConstraintPosition constraintPosition); public fun hasOnlyErrorsFromPosition(constraintPosition: ConstraintPosition): Boolean
/** /**
* Returns <tt>true</tt> if there is an error in constraining types. <p/> * Returns <tt>true</tt> if there is an error in constraining types. <p/>
* Is used not to generate type inference error if there was one in argument types. * Is used not to generate type inference error if there was one in argument types.
*/ */
boolean hasErrorInConstrainingTypes(); public fun hasErrorInConstrainingTypes(): Boolean
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2013 JetBrains s.r.o. * Copyright 2010-2014 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,47 +14,30 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.resolve.calls.inference; package org.jetbrains.jet.lang.resolve.calls.inference
import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Collection; public trait TypeBounds {
public val varianceOfPosition: Variance
public interface TypeBounds { public val typeVariable: TypeParameterDescriptor
@NotNull
Variance getVarianceOfPosition();
@NotNull public val bounds: Collection<Bound>
TypeParameterDescriptor getTypeVariable();
@NotNull public fun isEmpty(): Boolean
Collection<Bound> getBounds();
boolean isEmpty(); public fun getValue(): JetType?
@Nullable public fun getValues(): Collection<JetType>
JetType getValue();
@NotNull public enum class BoundKind {
Collection<JetType> getValues(); LOWER_BOUND
UPPER_BOUND
enum BoundKind { EXACT_BOUND
LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
} }
class Bound { public class Bound(public val constrainingType: JetType, public val kind: BoundKind, public val position: ConstraintPosition)
public final JetType type; }
public final BoundKind kind;
public final ConstraintPosition position;
public Bound(@NotNull JetType type, @NotNull BoundKind kind, @NotNull ConstraintPosition position) {
this.type = type;
this.kind = kind;
this.position = position;
}
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2013 JetBrains s.r.o. * Copyright 2010-2014 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,238 +14,163 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.lang.resolve.calls.inference; package org.jetbrains.jet.lang.resolve.calls.inference
import kotlin.Function1; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import kotlin.KotlinPackage; import org.jetbrains.jet.lang.types.Variance
import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.Bound
import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor; import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.CommonSupertypes
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.utils.UtilsPackage; import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor
import java.util.LinkedHashSet
import org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*
import org.jetbrains.jet.utils.addIfNotNull
import java.util.*; public class TypeBoundsImpl(
override val typeVariable: TypeParameterDescriptor,
override val varianceOfPosition: Variance
) : TypeBounds {
override val bounds = LinkedHashSet<Bound>()
import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND; private var resultValues: Collection<JetType>? = null
public class TypeBoundsImpl implements TypeBounds { public fun addBound(kind: BoundKind, constrainingType: JetType, position: ConstraintPosition) {
private final TypeParameterDescriptor typeVariable; resultValues = null
private final Variance varianceOfPosition; bounds.add(Bound(constrainingType, kind, position))
private final Set<Bound> bounds = new LinkedHashSet<Bound>();
private Collection<JetType> resultValues;
public TypeBoundsImpl(
@NotNull TypeParameterDescriptor typeVariable,
@NotNull Variance varianceOfPosition
) {
this.typeVariable = typeVariable;
this.varianceOfPosition = varianceOfPosition;
} }
@NotNull override fun isEmpty(): Boolean {
@Override return getValues().isEmpty()
public Variance getVarianceOfPosition() {
return varianceOfPosition;
} }
public void addBound(@NotNull BoundKind kind, @NotNull JetType type, @NotNull ConstraintPosition position) { private fun filterBounds(bounds: Collection<Bound>, kind: BoundKind): Set<JetType> {
resultValues = null; return filterBounds(bounds, kind, null)
bounds.add(new Bound(type, kind, position));
} }
@Override private fun filterBounds(bounds: Collection<Bound>, kind: BoundKind, errorValues: MutableCollection<JetType>?): Set<JetType> {
public boolean isEmpty() { val result = LinkedHashSet<JetType>()
return getValues().isEmpty(); for (bound in bounds) {
}
@NotNull
@Override
public TypeParameterDescriptor getTypeVariable() {
return typeVariable;
}
@Override
@NotNull
public Collection<Bound> getBounds() {
return bounds;
}
@NotNull
private static Set<JetType> filterBounds(
@NotNull Collection<Bound> bounds,
@NotNull BoundKind kind
) {
return filterBounds(bounds, kind, null);
}
@NotNull
private static Set<JetType> filterBounds(
@NotNull Collection<Bound> bounds,
@NotNull BoundKind kind,
@Nullable Collection<JetType> errorValues
) {
Set<JetType> result = new LinkedHashSet<JetType>();
for (Bound bound : bounds) {
if (bound.kind == kind) { if (bound.kind == kind) {
if (!ErrorUtils.containsErrorType(bound.type)) { if (!ErrorUtils.containsErrorType(bound.constrainingType)) {
result.add(bound.type); result.add(bound.constrainingType)
} }
else if (errorValues != null) { else {
errorValues.add(bound.type); errorValues?.add(bound.constrainingType)
} }
} }
} }
return result; return result
} }
/*package*/ TypeBoundsImpl copy() { fun copy(): TypeBoundsImpl {
TypeBoundsImpl typeBounds = new TypeBoundsImpl(typeVariable, varianceOfPosition); val typeBounds = TypeBoundsImpl(typeVariable, varianceOfPosition)
typeBounds.bounds.addAll(bounds); typeBounds.bounds.addAll(bounds)
typeBounds.resultValues = resultValues; typeBounds.resultValues = resultValues
return typeBounds; return typeBounds
} }
@NotNull public fun filter(condition: (ConstraintPosition) -> Boolean): TypeBoundsImpl {
public TypeBoundsImpl filter(@NotNull final Function1<ConstraintPosition, Boolean> condition) { val result = TypeBoundsImpl(typeVariable, varianceOfPosition)
TypeBoundsImpl result = new TypeBoundsImpl(typeVariable, varianceOfPosition); result.bounds.addAll(bounds.filter { condition(it.position) })
result.bounds.addAll(KotlinPackage.filter(bounds, new Function1<Bound, Boolean>() { return result
@Override
public Boolean invoke(Bound bound) {
return condition.invoke(bound.position);
}
}));
return result;
} }
@Nullable override fun getValue(): JetType? {
@Override val values = getValues()
public JetType getValue() {
Collection<JetType> values = getValues();
if (values.size() == 1) { if (values.size() == 1) {
return values.iterator().next(); return values.iterator().next()
} }
return null; return null
} }
@NotNull override fun getValues(): Collection<JetType> {
@Override
public Collection<JetType> getValues() {
if (resultValues == null) { if (resultValues == null) {
resultValues = computeValues(); resultValues = computeValues()
} }
return resultValues; return resultValues!!
} }
@NotNull private fun computeValues(): Collection<JetType> {
private Collection<JetType> computeValues() { val values = LinkedHashSet<JetType>()
Set<JetType> values = new LinkedHashSet<JetType>();
if (bounds.isEmpty()) { if (bounds.isEmpty()) {
return Collections.emptyList(); return listOf()
} }
boolean hasStrongBound = KotlinPackage.any(bounds, new Function1<Bound, Boolean>() { val hasStrongBound = bounds.any { it.position.isStrong() }
@Override
public Boolean invoke(Bound bound) {
return bound.position.isStrong();
}
});
if (!hasStrongBound) { if (!hasStrongBound) {
return Collections.emptyList(); return listOf()
} }
Set<JetType> exactBounds = filterBounds(bounds, BoundKind.EXACT_BOUND, values); val exactBounds = filterBounds(bounds, EXACT_BOUND, values)
JetType bestFit = TypesPackage.singleBestRepresentative(exactBounds); if (exactBounds.size() == 1) {
if (bestFit != null) { val exactBound = exactBounds.iterator().next()
if (tryPossibleAnswer(bestFit)) { if (tryPossibleAnswer(exactBound)) {
return Collections.singleton(bestFit); return setOf(exactBound)
} }
} }
values.addAll(exactBounds); values.addAll(exactBounds)
Collection<JetType> numberLowerBounds = new LinkedHashSet<JetType>(); val (numberLowerBounds, generalLowerBounds) =
Collection<JetType> generalLowerBounds = new LinkedHashSet<JetType>(); filterBounds(bounds, LOWER_BOUND, values).partition { it.getConstructor() is IntegerValueTypeConstructor }
filterNumberTypes(filterBounds(bounds, LOWER_BOUND, values), numberLowerBounds, generalLowerBounds);
JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds); val superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds)
if (tryPossibleAnswer(superTypeOfLowerBounds)) { if (tryPossibleAnswer(superTypeOfLowerBounds)) {
return Collections.singleton(superTypeOfLowerBounds); return setOf(superTypeOfLowerBounds!!)
} }
UtilsPackage.addIfNotNull(values, superTypeOfLowerBounds); values.addIfNotNull(superTypeOfLowerBounds)
//todo //todo
//fun <T> foo(t: T, consumer: Consumer<T>): T //fun <T> foo(t: T, consumer: Consumer<T>): T
//foo(1, c: Consumer<Any>) - infer Int, not Any here //foo(1, c: Consumer<Any>) - infer Int, not Any here
JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds); val superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds)
if (tryPossibleAnswer(superTypeOfNumberLowerBounds)) { if (tryPossibleAnswer(superTypeOfNumberLowerBounds)) {
return Collections.singleton(superTypeOfNumberLowerBounds); return setOf(superTypeOfNumberLowerBounds!!)
} }
UtilsPackage.addIfNotNull(values, superTypeOfNumberLowerBounds); values.addIfNotNull(superTypeOfNumberLowerBounds)
if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) { if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes( val superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(listOf(superTypeOfLowerBounds, superTypeOfNumberLowerBounds))
Arrays.asList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds)
);
if (tryPossibleAnswer(superTypeOfAllLowerBounds)) { if (tryPossibleAnswer(superTypeOfAllLowerBounds)) {
return Collections.singleton(superTypeOfAllLowerBounds); return setOf(superTypeOfAllLowerBounds!!)
} }
} }
Set<JetType> upperBounds = filterBounds(bounds, BoundKind.UPPER_BOUND, values); val upperBounds = filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND, values)
JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds); val intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds)
if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) { if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) {
if (tryPossibleAnswer(intersectionOfUpperBounds)) { if (tryPossibleAnswer(intersectionOfUpperBounds)) {
return Collections.singleton(intersectionOfUpperBounds); return setOf(intersectionOfUpperBounds)
} }
} }
values.addAll(filterBounds(bounds, BoundKind.UPPER_BOUND)); values.addAll(filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND))
return values; return values
} }
private static void filterNumberTypes( private fun tryPossibleAnswer(possibleAnswer: JetType?): Boolean {
@NotNull Collection<JetType> types, if (possibleAnswer == null) return false
@NotNull Collection<JetType> numberTypes, if (!possibleAnswer.getConstructor().isDenotable()) return false
@NotNull Collection<JetType> otherTypes
) { for (bound in bounds) {
for (JetType type : types) { when (bound.kind) {
if (type.getConstructor() instanceof IntegerValueTypeConstructor) { LOWER_BOUND -> if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.constrainingType, possibleAnswer)) {
numberTypes.add(type); return false
} }
else {
otherTypes.add(type); UPPER_BOUND -> if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.constrainingType)) {
return false
}
EXACT_BOUND -> if (!JetTypeChecker.DEFAULT.equalTypes(bound.constrainingType, possibleAnswer)) {
return false
}
} }
} }
return true
} }
}
private boolean tryPossibleAnswer(@Nullable JetType possibleAnswer) {
if (possibleAnswer == null) return false;
if (!possibleAnswer.getConstructor().isDenotable()) return false;
for (Bound bound : bounds) {
switch (bound.kind) {
case LOWER_BOUND:
if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.type, possibleAnswer)) {
return false;
}
break;
case UPPER_BOUND:
if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.type)) {
return false;
}
break;
case EXACT_BOUND:
if (!JetTypeChecker.DEFAULT.equalTypes(bound.type, possibleAnswer)) {
return false;
}
break;
}
}
return true;
}
}
@@ -711,6 +711,7 @@ public class TypeUtils {
}); });
} }
@NotNull
public static TypeSubstitutor makeSubstitutorForTypeParametersMap( public static TypeSubstitutor makeSubstitutorForTypeParametersMap(
@NotNull final Map<TypeParameterDescriptor, TypeProjection> substitutionContext @NotNull final Map<TypeParameterDescriptor, TypeProjection> substitutionContext
) { ) {