Converted ConstraintSystem to Kotlin
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-29
@@ -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();
|
|
||||||
}
|
|
||||||
+239
-383
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+13
-19
@@ -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<R> is a supertype of List<String>"</tt> which leads to <tt>"R is equal to String"</tt>
|
* - <tt>"List<R> is a supertype of List<String>"</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 <E> newList()</pre> in invocation <tt>"val nl = newList()"</tt>
|
* For example, for <pre>fun <E> 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 <R> foo(t: List<R>) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
|
* For example, for <pre>fun <R> foo(t: List<R>) {}</pre> in invocation <tt>foo(hashSet("s"))</tt>
|
||||||
* there is type constructor mismatch: <tt>"HashSet<String> cannot be a subtype of List<R>"</tt>.
|
* there is type constructor mismatch: <tt>"HashSet<String> cannot be a subtype of List<R>"</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<String> cannot be a subtype of List<R>"</tt>
|
* there is type constructor mismatch: <tt>"HashSet<String> cannot be a subtype of List<R>"</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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+97
-172
@@ -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
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user