Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -248,7 +248,7 @@ public class JetTypeMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof TypeParameterDescriptor) {
|
if (descriptor instanceof TypeParameterDescriptor) {
|
||||||
return mapType(((TypeParameterDescriptor) descriptor).getBoundsAsType(), kind);
|
return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Unknown type " + jetType);
|
throw new UnsupportedOperationException("Unknown type " + jetType);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace jet
|
namespace jet
|
||||||
|
|
||||||
namespace typeinfo {
|
namespace typeinfo {
|
||||||
class TypeInfo<T> {
|
class TypeInfo<out T> {
|
||||||
fun isSubtypeOf(other : TypeInfo<*>) : Boolean
|
fun isSubtypeOf(other : TypeInfo<*>) : Boolean
|
||||||
fun isInstance(obj : Any?) : Boolean
|
fun isInstance(obj : Any?) : Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
fun typeinfo<T>() : TypeInfo<T>
|
fun typeinfo<T>() : TypeInfo<T>
|
||||||
fun typeinfo<T>(expression : T) : TypeInfo<out T>
|
fun typeinfo<T>(expression : T) : TypeInfo<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace io {
|
namespace io {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang;
|
|||||||
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||||
@@ -14,19 +13,19 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
|||||||
*/
|
*/
|
||||||
public class JetSemanticServices {
|
public class JetSemanticServices {
|
||||||
public static JetSemanticServices createSemanticServices(JetStandardLibrary standardLibrary) {
|
public static JetSemanticServices createSemanticServices(JetStandardLibrary standardLibrary) {
|
||||||
return new JetSemanticServices(standardLibrary, JetControlFlowDataTraceFactory.EMPTY);
|
return new JetSemanticServices(standardLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JetSemanticServices createSemanticServices(Project project) {
|
public static JetSemanticServices createSemanticServices(Project project) {
|
||||||
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY);
|
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
private final JetStandardLibrary standardLibrary;
|
private final JetStandardLibrary standardLibrary;
|
||||||
private final JetTypeChecker typeChecker;
|
private final JetTypeChecker typeChecker;
|
||||||
|
|
||||||
private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
private JetSemanticServices(JetStandardLibrary standardLibrary) {
|
||||||
this.standardLibrary = standardLibrary;
|
this.standardLibrary = standardLibrary;
|
||||||
this.typeChecker = new JetTypeChecker(standardLibrary);
|
this.typeChecker = JetTypeChecker.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -61,11 +61,25 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
@Override
|
@Override
|
||||||
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
|
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
|
||||||
if (this.classObjectDescriptor != null) return ClassObjectStatus.DUPLICATE;
|
if (this.classObjectDescriptor != null) return ClassObjectStatus.DUPLICATE;
|
||||||
|
if (!isStatic(this.getContainingDeclaration())) {
|
||||||
|
return ClassObjectStatus.NOT_ALLOWED;
|
||||||
|
}
|
||||||
assert classObjectDescriptor.getKind() == ClassKind.OBJECT;
|
assert classObjectDescriptor.getKind() == ClassKind.OBJECT;
|
||||||
this.classObjectDescriptor = classObjectDescriptor;
|
this.classObjectDescriptor = classObjectDescriptor;
|
||||||
return ClassObjectStatus.OK;
|
return ClassObjectStatus.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isStatic(DeclarationDescriptor declarationDescriptor) {
|
||||||
|
if (declarationDescriptor instanceof NamespaceDescriptor) {
|
||||||
|
return true;
|
||||||
|
} else if (declarationDescriptor instanceof ClassDescriptor) {
|
||||||
|
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||||
|
return classDescriptor.getKind() == ClassKind.OBJECT || classDescriptor.getKind() == ClassKind.ENUM_CLASS;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public MutableClassDescriptor getClassObjectDescriptor() {
|
public MutableClassDescriptor getClassObjectDescriptor() {
|
||||||
return classObjectDescriptor;
|
return classObjectDescriptor;
|
||||||
|
|||||||
+27
-15
@@ -43,7 +43,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
|||||||
private final int index;
|
private final int index;
|
||||||
private final Variance variance;
|
private final Variance variance;
|
||||||
private final Set<JetType> upperBounds;
|
private final Set<JetType> upperBounds;
|
||||||
private JetType boundsAsType;
|
private JetType upperBoundsAsType;
|
||||||
private final TypeConstructor typeConstructor;
|
private final TypeConstructor typeConstructor;
|
||||||
private JetType defaultType;
|
private JetType defaultType;
|
||||||
private final Set<JetType> classObjectUpperBounds = Sets.newLinkedHashSet();
|
private final Set<JetType> classObjectUpperBounds = Sets.newLinkedHashSet();
|
||||||
@@ -85,10 +85,35 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
|||||||
upperBounds.add(bound); // TODO : Duplicates?
|
upperBounds.add(bound); // TODO : Duplicates?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public Set<JetType> getUpperBounds() {
|
public Set<JetType> getUpperBounds() {
|
||||||
return upperBounds;
|
return upperBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getUpperBoundsAsType() {
|
||||||
|
if (upperBoundsAsType == null) {
|
||||||
|
assert upperBounds != null : "Upper bound list is null in " + getName();
|
||||||
|
assert upperBounds.size() > 0 : "Upper bound list is empty in " + getName();
|
||||||
|
upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
|
||||||
|
if (upperBoundsAsType == null) {
|
||||||
|
upperBoundsAsType = JetStandardClasses.getNothingType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upperBoundsAsType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Set<JetType> getLowerBounds() {
|
||||||
|
return Collections.singleton(JetStandardClasses.getNothingType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getLowerBoundsAsType() {
|
||||||
|
return JetStandardClasses.getNothingType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public TypeConstructor getTypeConstructor() {
|
public TypeConstructor getTypeConstructor() {
|
||||||
@@ -100,19 +125,6 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
|||||||
return DescriptorRenderer.TEXT.render(this);
|
return DescriptorRenderer.TEXT.render(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JetType getBoundsAsType() {
|
|
||||||
if (boundsAsType == null) {
|
|
||||||
assert upperBounds != null : "Upper bound list is null in " + getName();
|
|
||||||
assert upperBounds.size() > 0 : "Upper bound list is empty in " + getName();
|
|
||||||
boundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
|
|
||||||
if (boundsAsType == null) {
|
|
||||||
boundsAsType = JetStandardClasses.getNothingType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return boundsAsType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
@Deprecated // Use the static method TypeParameterDescriptor.substitute()
|
@Deprecated // Use the static method TypeParameterDescriptor.substitute()
|
||||||
@@ -137,7 +149,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
|||||||
new LazyScopeAdapter(new LazyValue<JetScope>() {
|
new LazyScopeAdapter(new LazyValue<JetScope>() {
|
||||||
@Override
|
@Override
|
||||||
protected JetScope compute() {
|
protected JetScope compute() {
|
||||||
return getBoundsAsType().getMemberScope();
|
return getUpperBoundsAsType().getMemberScope();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ public class BodyResolver {
|
|||||||
resolveDelegationSpecifierLists();
|
resolveDelegationSpecifierLists();
|
||||||
resolveClassAnnotations();
|
resolveClassAnnotations();
|
||||||
|
|
||||||
resolveAnonymousInitializers();
|
|
||||||
resolvePropertyDeclarationBodies();
|
resolvePropertyDeclarationBodies();
|
||||||
|
resolveAnonymousInitializers();
|
||||||
|
|
||||||
resolveSecondaryConstructorBodies();
|
resolveSecondaryConstructorBodies();
|
||||||
resolveFunctionBodies();
|
resolveFunctionBodies();
|
||||||
@@ -484,16 +484,17 @@ public class BodyResolver {
|
|||||||
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
||||||
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
||||||
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE);
|
JetType expectedTypeForInitializer = property.getPropertyTypeRef() != null ? propertyDescriptor.getOutType() : NO_EXPECTED_TYPE;
|
||||||
|
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, expectedTypeForInitializer);
|
||||||
JetType expectedType = propertyDescriptor.getInType();
|
//
|
||||||
if (expectedType == null) {
|
// JetType expectedType = propertyDescriptor.getInType();
|
||||||
expectedType = propertyDescriptor.getOutType();
|
// if (expectedType == null) {
|
||||||
}
|
// expectedType = propertyDescriptor.getOutType();
|
||||||
if (type != null && expectedType != null
|
// }
|
||||||
&& !context.getSemanticServices().getTypeChecker().isSubtypeOf(type, expectedType)) {
|
// if (type != null && expectedType != null
|
||||||
context.getTrace().report(TYPE_MISMATCH.on(initializer, expectedType, type));
|
// && !context.getSemanticServices().getTypeChecker().isSubtypeOf(type, expectedType)) {
|
||||||
}
|
//// context.getTrace().report(TYPE_MISMATCH.on(initializer, expectedType, type));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveFunctionBodies() {
|
private void resolveFunctionBodies() {
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ public class ClassDescriptorResolver {
|
|||||||
parameter.addUpperBound(JetStandardClasses.getDefaultBound());
|
parameter.addUpperBound(JetStandardClasses.getDefaultBound());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JetStandardClasses.isNothing(parameter.getBoundsAsType())) {
|
if (JetStandardClasses.isNothing(parameter.getUpperBoundsAsType())) {
|
||||||
PsiElement nameIdentifier = typeParameters.get(parameter.getIndex()).getNameIdentifier();
|
PsiElement nameIdentifier = typeParameters.get(parameter.getIndex()).getNameIdentifier();
|
||||||
if (nameIdentifier != null) {
|
if (nameIdentifier != null) {
|
||||||
// trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Upper bounds of " + parameter.getName() + " have empty intersection");
|
// trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Upper bounds of " + parameter.getName() + " have empty intersection");
|
||||||
@@ -666,7 +666,7 @@ public class ClassDescriptorResolver {
|
|||||||
type = typeResolver.resolveType(scope, typeReference);
|
type = typeResolver.resolveType(scope, typeReference);
|
||||||
JetType inType = propertyDescriptor.getInType();
|
JetType inType = propertyDescriptor.getInType();
|
||||||
if (inType != null) {
|
if (inType != null) {
|
||||||
if (!semanticServices.getTypeChecker().equalTypes(type, inType)) {
|
if (!TypeUtils.equalTypes(type, inType)) {
|
||||||
// trace.getErrorHandler().genericError(typeReference.getNode(), "Setter parameter type must be equal to the type of the property, i.e. " + inType);
|
// trace.getErrorHandler().genericError(typeReference.getNode(), "Setter parameter type must be equal to the type of the property, i.e. " + inType);
|
||||||
trace.report(WRONG_SETTER_PARAMETER_TYPE.on(setter, typeReference, inType));
|
trace.report(WRONG_SETTER_PARAMETER_TYPE.on(setter, typeReference, inType));
|
||||||
}
|
}
|
||||||
@@ -709,7 +709,7 @@ public class ClassDescriptorResolver {
|
|||||||
JetTypeReference returnTypeReference = getter.getReturnTypeReference();
|
JetTypeReference returnTypeReference = getter.getReturnTypeReference();
|
||||||
if (returnTypeReference != null) {
|
if (returnTypeReference != null) {
|
||||||
returnType = typeResolver.resolveType(scope, returnTypeReference);
|
returnType = typeResolver.resolveType(scope, returnTypeReference);
|
||||||
if (outType != null && !semanticServices.getTypeChecker().equalTypes(returnType, outType)) {
|
if (outType != null && !TypeUtils.equalTypes(returnType, outType)) {
|
||||||
// trace.getErrorHandler().genericError(returnTypeReference.getNode(), "Getter return type must be equal to the type of the property, i.e. " + propertyDescriptor.getReturnType());
|
// trace.getErrorHandler().genericError(returnTypeReference.getNode(), "Getter return type must be equal to the type of the property, i.e. " + propertyDescriptor.getReturnType());
|
||||||
trace.report(WRONG_GETTER_RETURN_TYPE.on(getter, returnTypeReference, propertyDescriptor.getReturnType()));
|
trace.report(WRONG_GETTER_RETURN_TYPE.on(getter, returnTypeReference, propertyDescriptor.getReturnType()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ public class OverridingUtil {
|
|||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
||||||
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
||||||
|
|
||||||
if (!JetTypeImpl.equalTypes(superTypeParameter.getBoundsAsType(), subTypeParameter.getBoundsAsType(), axioms)) {
|
if (!JetTypeImpl.equalTypes(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), axioms)) {
|
||||||
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,13 +181,13 @@ public class TypeResolver {
|
|||||||
|
|
||||||
private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor) {
|
private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor) {
|
||||||
if (checkBounds) {
|
if (checkBounds) {
|
||||||
return typeParameterDescriptor.getBoundsAsType().getMemberScope();
|
return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new LazyScopeAdapter(new LazyValue<JetScope>() {
|
return new LazyScopeAdapter(new LazyValue<JetScope>() {
|
||||||
@Override
|
@Override
|
||||||
protected JetScope compute() {
|
protected JetScope compute() {
|
||||||
return typeParameterDescriptor.getBoundsAsType().getMemberScope();
|
return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
||||||
@@ -21,6 +20,8 @@ import org.jetbrains.jet.lang.types.*;
|
|||||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||||
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
|
||||||
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystemSolution;
|
||||||
|
import org.jetbrains.jet.lang.types.inference.ConstraintSystemImpl;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -51,11 +52,8 @@ public class CallResolver {
|
|||||||
public VariableDescriptor resolveSimpleProperty(
|
public VariableDescriptor resolveSimpleProperty(
|
||||||
@NotNull BindingTrace trace,
|
@NotNull BindingTrace trace,
|
||||||
@NotNull JetScope scope,
|
@NotNull JetScope scope,
|
||||||
// @NotNull ReceiverDescriptor receiver,
|
@NotNull Call call,
|
||||||
// @NotNull final JetSimpleNameExpression nameExpression,
|
|
||||||
@NotNull Call call,
|
|
||||||
@NotNull JetType expectedType) {
|
@NotNull JetType expectedType) {
|
||||||
// Call call = CallMaker.makePropertyCall(receiver, null, nameExpression);
|
|
||||||
JetExpression calleeExpression = call.getCalleeExpression();
|
JetExpression calleeExpression = call.getCalleeExpression();
|
||||||
assert calleeExpression instanceof JetSimpleNameExpression;
|
assert calleeExpression instanceof JetSimpleNameExpression;
|
||||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
|
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) calleeExpression;
|
||||||
@@ -115,7 +113,6 @@ public class CallResolver {
|
|||||||
if (descriptor instanceof ConstructorDescriptor) {
|
if (descriptor instanceof ConstructorDescriptor) {
|
||||||
Modality modality = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModality();
|
Modality modality = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModality();
|
||||||
if (modality == Modality.ABSTRACT) {
|
if (modality == Modality.ABSTRACT) {
|
||||||
// tracing.reportOverallResolutionError(trace, "Can not create an instance of an abstract class");
|
|
||||||
tracing.instantiationOfAbstractClass(trace);
|
tracing.instantiationOfAbstractClass(trace);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -148,14 +145,12 @@ public class CallResolver {
|
|||||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||||
Set<FunctionDescriptor> constructors = classDescriptor.getConstructors();
|
Set<FunctionDescriptor> constructors = classDescriptor.getConstructors();
|
||||||
if (constructors.isEmpty()) {
|
if (constructors.isEmpty()) {
|
||||||
// trace.getErrorHandler().genericError(reportAbsenceOn, "This class does not have a constructor");
|
|
||||||
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||||
return checkArgumentTypesAndFail(trace, scope, call);
|
return checkArgumentTypesAndFail(trace, scope, call);
|
||||||
}
|
}
|
||||||
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(TaskPrioritizer.convertWithImpliedThis(scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.EMPTY));
|
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(TaskPrioritizer.convertWithImpliedThis(scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.EMPTY));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
|
|
||||||
trace.report(NOT_A_CLASS.on(calleeExpression));
|
trace.report(NOT_A_CLASS.on(calleeExpression));
|
||||||
return checkArgumentTypesAndFail(trace, scope, call);
|
return checkArgumentTypesAndFail(trace, scope, call);
|
||||||
}
|
}
|
||||||
@@ -168,7 +163,6 @@ public class CallResolver {
|
|||||||
|
|
||||||
Set<FunctionDescriptor> constructors = classDescriptor.getConstructors();
|
Set<FunctionDescriptor> constructors = classDescriptor.getConstructors();
|
||||||
if (constructors.isEmpty()) {
|
if (constructors.isEmpty()) {
|
||||||
// trace.getErrorHandler().genericError(reportAbsenceOn, "This class does not have a constructor");
|
|
||||||
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
|
||||||
return checkArgumentTypesAndFail(trace, scope, call);
|
return checkArgumentTypesAndFail(trace, scope, call);
|
||||||
}
|
}
|
||||||
@@ -295,11 +289,9 @@ public class CallResolver {
|
|||||||
public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
|
public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
|
||||||
JetTypeArgumentList typeArgumentList = call.getTypeArgumentList();
|
JetTypeArgumentList typeArgumentList = call.getTypeArgumentList();
|
||||||
if (typeArgumentList != null) {
|
if (typeArgumentList != null) {
|
||||||
// trace.getErrorHandler().genericError(typeArgumentList.getNode(), message);
|
|
||||||
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount));
|
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// reportOverallResolutionError(trace, message);
|
|
||||||
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount));
|
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,7 +405,7 @@ public class CallResolver {
|
|||||||
if (!candidate.getTypeParameters().isEmpty()) {
|
if (!candidate.getTypeParameters().isEmpty()) {
|
||||||
// Type argument inference
|
// Type argument inference
|
||||||
|
|
||||||
ConstraintSystem constraintSystem = new ConstraintSystem();
|
ConstraintSystem constraintSystem = new ConstraintSystemImpl();
|
||||||
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
|
||||||
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
|
||||||
}
|
}
|
||||||
@@ -438,8 +430,6 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkReceiverAbsence(candidateCall, tracing, candidate);
|
|
||||||
|
|
||||||
// Error is already reported if something is missing
|
// Error is already reported if something is missing
|
||||||
ReceiverDescriptor receiverParameter = candidateCall.getReceiverArgument();
|
ReceiverDescriptor receiverParameter = candidateCall.getReceiverArgument();
|
||||||
ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter();
|
ReceiverDescriptor candidateReceiver = candidate.getReceiverParameter();
|
||||||
@@ -451,8 +441,7 @@ public class CallResolver {
|
|||||||
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
|
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstraintSystem.Solution solution = constraintSystem.solve();
|
ConstraintSystemSolution solution = constraintSystem.solve();
|
||||||
// solutions.put(candidate, solution);
|
|
||||||
if (solution.isSuccessful()) {
|
if (solution.isSuccessful()) {
|
||||||
D substitute = (D) candidate.substitute(solution.getSubstitutor());
|
D substitute = (D) candidate.substitute(solution.getSubstitutor());
|
||||||
assert substitute != null;
|
assert substitute != null;
|
||||||
@@ -505,7 +494,6 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
candidateCall.setStatus(OTHER_ERROR);
|
candidateCall.setStatus(OTHER_ERROR);
|
||||||
// tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate));
|
|
||||||
tracing.wrongNumberOfTypeArguments(temporaryTrace, expectedTypeArgumentCount);
|
tracing.wrongNumberOfTypeArguments(temporaryTrace, expectedTypeArgumentCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -884,7 +872,7 @@ public class CallResolver {
|
|||||||
for (int i = 0; i < valueParameters.size(); i++) {
|
for (int i = 0; i < valueParameters.size(); i++) {
|
||||||
ValueParameterDescriptor valueParameter = valueParameters.get(i);
|
ValueParameterDescriptor valueParameter = valueParameters.get(i);
|
||||||
JetType expectedType = parameterTypes.get(i);
|
JetType expectedType = parameterTypes.get(i);
|
||||||
if (!semanticServices.getTypeChecker().equalTypes(expectedType, valueParameter.getOutType())) return false;
|
if (!TypeUtils.equalTypes(expectedType, valueParameter.getOutType())) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -123,13 +124,13 @@ public class OverloadingConflictResolver {
|
|||||||
JetType _byte = standardLibrary.getByteType();
|
JetType _byte = standardLibrary.getByteType();
|
||||||
JetType _short = standardLibrary.getShortType();
|
JetType _short = standardLibrary.getShortType();
|
||||||
|
|
||||||
if (semanticServices.getTypeChecker().equalTypes(specific, _double) && semanticServices.getTypeChecker().equalTypes(general, _float)) return true;
|
if (TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float)) return true;
|
||||||
if (semanticServices.getTypeChecker().equalTypes(specific, _int)) {
|
if (TypeUtils.equalTypes(specific, _int)) {
|
||||||
if (semanticServices.getTypeChecker().equalTypes(general, _long)) return true;
|
if (TypeUtils.equalTypes(general, _long)) return true;
|
||||||
if (semanticServices.getTypeChecker().equalTypes(general, _byte)) return true;
|
if (TypeUtils.equalTypes(general, _byte)) return true;
|
||||||
if (semanticServices.getTypeChecker().equalTypes(general, _short)) return true;
|
if (TypeUtils.equalTypes(general, _short)) return true;
|
||||||
}
|
}
|
||||||
if (semanticServices.getTypeChecker().equalTypes(specific, _short) && semanticServices.getTypeChecker().equalTypes(general, _byte)) return true;
|
if (TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.resolve.calls.autocasts;
|
|||||||
|
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
@@ -11,7 +10,7 @@ import org.jetbrains.jet.lang.resolve.JetModuleUtil;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ public class DataFlowValueFactory {
|
|||||||
JetConstantExpression constantExpression = (JetConstantExpression) expression;
|
JetConstantExpression constantExpression = (JetConstantExpression) expression;
|
||||||
if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL;
|
if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL;
|
||||||
}
|
}
|
||||||
if (JetTypeChecker.INSTANCE.equalTypes(type, JetStandardClasses.getNullableNothingType())) return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?'
|
if (TypeUtils.equalTypes(type, JetStandardClasses.getNullableNothingType())) return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?'
|
||||||
Pair<Object, Boolean> result = getIdForStableIdentifier(expression, bindingContext, false);
|
Pair<Object, Boolean> result = getIdForStableIdentifier(expression, bindingContext, false);
|
||||||
return new DataFlowValue(result.first == null ? expression : result.first, type, result.second, getImmanentNullability(type));
|
return new DataFlowValue(result.first == null ? expression : result.first, type, result.second, getImmanentNullability(type));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -260,7 +260,7 @@ public class CompileTimeConstantResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean noExpectedType(JetType expectedType) {
|
private boolean noExpectedType(JetType expectedType) {
|
||||||
return expectedType == TypeUtils.NO_EXPECTED_TYPE || JetStandardClasses.isUnit(expectedType);
|
return expectedType == TypeUtils.NO_EXPECTED_TYPE || JetStandardClasses.isUnit(expectedType) || ErrorUtils.isErrorType(expectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
|
||||||
|
import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class CommonSupertypes {
|
||||||
|
@NotNull
|
||||||
|
public static JetType commonSupertype(@NotNull Collection<JetType> types) {
|
||||||
|
Collection<JetType> typeSet = new HashSet<JetType>(types);
|
||||||
|
assert !typeSet.isEmpty();
|
||||||
|
|
||||||
|
// If any of the types is nullable, the result must be nullable
|
||||||
|
// This also removed Nothing and Nothing? because they are subtypes of everything else
|
||||||
|
boolean nullable = false;
|
||||||
|
for (Iterator<JetType> iterator = typeSet.iterator(); iterator.hasNext();) {
|
||||||
|
JetType type = iterator.next();
|
||||||
|
assert type != null;
|
||||||
|
if (JetStandardClasses.isNothingOrNullableNothing(type)) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
nullable |= type.isNullable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything deleted => it's Nothing or Nothing?
|
||||||
|
if (typeSet.isEmpty()) {
|
||||||
|
// TODO : attributes
|
||||||
|
return nullable ? JetStandardClasses.getNullableNothingType() : JetStandardClasses.getNothingType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeSet.size() == 1) {
|
||||||
|
return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor of the supertype -> all of its instantiations occurring as supertypes
|
||||||
|
Map<TypeConstructor, Set<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
|
||||||
|
while (commonSupertypes.size() > 1) {
|
||||||
|
Set<JetType> merge = new HashSet<JetType>();
|
||||||
|
for (Set<JetType> supertypes : commonSupertypes.values()) {
|
||||||
|
merge.addAll(supertypes);
|
||||||
|
}
|
||||||
|
commonSupertypes = computeCommonRawSupertypes(merge);
|
||||||
|
}
|
||||||
|
assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types;
|
||||||
|
|
||||||
|
// constructor of the supertype -> all of its instantiations occurring as supertypes
|
||||||
|
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
|
||||||
|
|
||||||
|
// Reconstructing type arguments if possible
|
||||||
|
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
|
||||||
|
return TypeUtils.makeNullableIfNeeded(result, nullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw supertypes are superclasses w/o type arguments
|
||||||
|
// @return TypeConstructor -> all instantiations of this constructor occurring as supertypes
|
||||||
|
@NotNull
|
||||||
|
private static Map<TypeConstructor, Set<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) {
|
||||||
|
assert !types.isEmpty();
|
||||||
|
|
||||||
|
final Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>();
|
||||||
|
Set<TypeConstructor> commonSuperclasses = null;
|
||||||
|
|
||||||
|
List<TypeConstructor> order = null;
|
||||||
|
for (JetType type : types) {
|
||||||
|
Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
|
||||||
|
|
||||||
|
order = dfs(type, visited, new DfsNodeHandler<List<TypeConstructor>>() {
|
||||||
|
public LinkedList<TypeConstructor> list = new LinkedList<TypeConstructor>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeChildren(JetType current) {
|
||||||
|
TypeConstructor constructor = current.getConstructor();
|
||||||
|
|
||||||
|
Set<JetType> instances = constructorToAllInstances.get(constructor);
|
||||||
|
if (instances == null) {
|
||||||
|
instances = new HashSet<JetType>();
|
||||||
|
constructorToAllInstances.put(constructor, instances);
|
||||||
|
}
|
||||||
|
instances.add(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterChildren(JetType current) {
|
||||||
|
list.addFirst(current.getConstructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TypeConstructor> result() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (commonSuperclasses == null) {
|
||||||
|
commonSuperclasses = visited;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
commonSuperclasses.retainAll(visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert order != null;
|
||||||
|
|
||||||
|
Set<TypeConstructor> notSource = new HashSet<TypeConstructor>();
|
||||||
|
Map<TypeConstructor, Set<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>();
|
||||||
|
for (TypeConstructor superConstructor : order) {
|
||||||
|
if (!commonSuperclasses.contains(superConstructor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notSource.contains(superConstructor)) {
|
||||||
|
result.put(superConstructor, constructorToAllInstances.get(superConstructor));
|
||||||
|
markAll(superConstructor, notSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor - type constructor of a supertype to be instantiated
|
||||||
|
// types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
|
||||||
|
@NotNull
|
||||||
|
private static JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> types) {
|
||||||
|
// we assume that all the given types are applications of the same type constructor
|
||||||
|
|
||||||
|
assert !types.isEmpty();
|
||||||
|
|
||||||
|
if (types.size() == 1) {
|
||||||
|
return types.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
||||||
|
List<TypeProjection> newProjections = new ArrayList<TypeProjection>();
|
||||||
|
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
|
||||||
|
TypeParameterDescriptor parameterDescriptor = parameters.get(i);
|
||||||
|
Set<TypeProjection> typeProjections = new HashSet<TypeProjection>();
|
||||||
|
for (JetType type : types) {
|
||||||
|
typeProjections.add(type.getArguments().get(i));
|
||||||
|
}
|
||||||
|
newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean nullable = false;
|
||||||
|
for (JetType type : types) {
|
||||||
|
nullable |= type.isNullable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : attributes?
|
||||||
|
return new JetTypeImpl(Collections.<AnnotationDescriptor>emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB); // TODO : scope
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set<TypeProjection> typeProjections) {
|
||||||
|
if (typeProjections.size() == 1) {
|
||||||
|
return typeProjections.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<JetType> ins = new HashSet<JetType>();
|
||||||
|
Set<JetType> outs = new HashSet<JetType>();
|
||||||
|
|
||||||
|
Variance variance = parameterDescriptor.getVariance();
|
||||||
|
switch (variance) {
|
||||||
|
case INVARIANT:
|
||||||
|
// Nothing
|
||||||
|
break;
|
||||||
|
case IN_VARIANCE:
|
||||||
|
outs = null;
|
||||||
|
break;
|
||||||
|
case OUT_VARIANCE:
|
||||||
|
ins = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypeProjection projection : typeProjections) {
|
||||||
|
Variance projectionKind = projection.getProjectionKind();
|
||||||
|
if (projectionKind.allowsInPosition()) {
|
||||||
|
if (ins != null) {
|
||||||
|
ins.add(projection.getType());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ins = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectionKind.allowsOutPosition()) {
|
||||||
|
if (outs != null) {
|
||||||
|
outs.add(projection.getType());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outs = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ins != null) {
|
||||||
|
JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, ins);
|
||||||
|
if (intersection == null) {
|
||||||
|
if (outs != null) {
|
||||||
|
return new TypeProjection(OUT_VARIANCE, commonSupertype(outs));
|
||||||
|
}
|
||||||
|
return new TypeProjection(OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
|
||||||
|
}
|
||||||
|
Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE;
|
||||||
|
return new TypeProjection(projectionKind, intersection);
|
||||||
|
} else if (outs != null) {
|
||||||
|
Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
|
||||||
|
return new TypeProjection(projectionKind, commonSupertype(outs));
|
||||||
|
} else {
|
||||||
|
Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
|
||||||
|
return new TypeProjection(projectionKind, commonSupertype(parameterDescriptor.getUpperBounds()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
|
||||||
|
markerSet.add(typeConstructor);
|
||||||
|
for (JetType type : typeConstructor.getSupertypes()) {
|
||||||
|
markAll(type.getConstructor(), markerSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <R> R dfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<R> handler) {
|
||||||
|
doDfs(current, visited, handler);
|
||||||
|
return handler.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doDfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<?> handler) {
|
||||||
|
if (!visited.add(current.getConstructor())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.beforeChildren(current);
|
||||||
|
// Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
|
||||||
|
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
|
||||||
|
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
||||||
|
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
||||||
|
if (visited.contains(supertypeConstructor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JetType substitutedSupertype = substitutor.safeSubstitute(supertype, Variance.INVARIANT);
|
||||||
|
dfs(substitutedSupertype, visited, handler);
|
||||||
|
}
|
||||||
|
handler.afterChildren(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DfsNodeHandler<R> {
|
||||||
|
|
||||||
|
public void beforeChildren(JetType current) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterChildren(JetType current) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public R result() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ public class JetStandardLibrary {
|
|||||||
|
|
||||||
private JetScope libraryScope;
|
private JetScope libraryScope;
|
||||||
|
|
||||||
|
private ClassDescriptor numberClass;
|
||||||
private ClassDescriptor byteClass;
|
private ClassDescriptor byteClass;
|
||||||
private ClassDescriptor charClass;
|
private ClassDescriptor charClass;
|
||||||
private ClassDescriptor shortClass;
|
private ClassDescriptor shortClass;
|
||||||
@@ -152,6 +153,7 @@ public class JetStandardLibrary {
|
|||||||
private void initStdClasses() {
|
private void initStdClasses() {
|
||||||
if(libraryScope == null) {
|
if(libraryScope == null) {
|
||||||
this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope();
|
this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope();
|
||||||
|
this.numberClass = (ClassDescriptor) libraryScope.getClassifier("Number");
|
||||||
this.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte");
|
this.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte");
|
||||||
this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char");
|
this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char");
|
||||||
this.shortClass = (ClassDescriptor) libraryScope.getClassifier("Short");
|
this.shortClass = (ClassDescriptor) libraryScope.getClassifier("Short");
|
||||||
@@ -221,6 +223,12 @@ public class JetStandardLibrary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ClassDescriptor getNumber() {
|
||||||
|
initStdClasses();
|
||||||
|
return numberClass;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ClassDescriptor getByte() {
|
public ClassDescriptor getByte() {
|
||||||
initStdClasses();
|
initStdClasses();
|
||||||
|
|||||||
@@ -2,315 +2,27 @@ package org.jetbrains.jet.lang.types;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
|
||||||
|
import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
|
||||||
|
import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class JetTypeChecker {
|
public class JetTypeChecker {
|
||||||
|
|
||||||
public static final JetTypeChecker INSTANCE = new JetTypeChecker(null);
|
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
|
||||||
|
|
||||||
private final Map<TypeConstructor, Set<TypeConstructor>> conversionMap = new HashMap<TypeConstructor, Set<TypeConstructor>>();
|
private JetTypeChecker() {
|
||||||
private final JetStandardLibrary standardLibrary;
|
|
||||||
|
|
||||||
public JetTypeChecker(JetStandardLibrary standardLibrary) {
|
|
||||||
this.standardLibrary = standardLibrary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
private Map<TypeConstructor, Set<TypeConstructor>> getConversionMap() {
|
// return new TypeCheckingProcedure().run(subtype, supertype);
|
||||||
// if (conversionMap.size() == 0) {
|
return TYPE_CHECKER.run(subtype, supertype);
|
||||||
// addConversion(standardLibrary.getByte(),
|
|
||||||
// standardLibrary.getShort(),
|
|
||||||
// standardLibrary.getInt(),
|
|
||||||
// standardLibrary.getLong(),
|
|
||||||
// standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
//
|
|
||||||
// addConversion(standardLibrary.getShort(),
|
|
||||||
// standardLibrary.getInt(),
|
|
||||||
// standardLibrary.getLong(),
|
|
||||||
// standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
//
|
|
||||||
// addConversion(standardLibrary.getChar(),
|
|
||||||
// standardLibrary.getInt(),
|
|
||||||
// standardLibrary.getLong(),
|
|
||||||
// standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
//
|
|
||||||
// addConversion(standardLibrary.getInt(),
|
|
||||||
// standardLibrary.getLong(),
|
|
||||||
// standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
//
|
|
||||||
// addConversion(standardLibrary.getLong(),
|
|
||||||
// standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
//
|
|
||||||
// addConversion(standardLibrary.getFloat(),
|
|
||||||
// standardLibrary.getDouble());
|
|
||||||
// }
|
|
||||||
return conversionMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// private void addConversion(ClassDescriptor actual, ClassDescriptor... convertedTo) {
|
|
||||||
// TypeConstructor[] constructors = new TypeConstructor[convertedTo.length];
|
|
||||||
// for (int i = 0, convertedToLength = convertedTo.length; i < convertedToLength; i++) {
|
|
||||||
// ClassDescriptor classDescriptor = convertedTo[i];
|
|
||||||
// constructors[i] = classDescriptor.getTypeConstructor();
|
|
||||||
// }
|
|
||||||
// conversionMap.put(actual.getTypeConstructor(), new HashSet<TypeConstructor>(Arrays.asList(constructors)));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
@NotNull
|
|
||||||
public JetType commonSupertype(@NotNull JetType... types) {
|
|
||||||
return commonSupertype(Arrays.asList(types));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JetType commonSupertype(@NotNull Collection<JetType> types) {
|
|
||||||
Collection<JetType> typeSet = new HashSet<JetType>(types);
|
|
||||||
assert !typeSet.isEmpty();
|
|
||||||
boolean nullable = false;
|
|
||||||
for (Iterator<JetType> iterator = typeSet.iterator(); iterator.hasNext();) {
|
|
||||||
JetType type = iterator.next();
|
|
||||||
assert type != null;
|
|
||||||
// TODO : This admits 'Nothing?'. Review
|
|
||||||
if (JetStandardClasses.isNothingOrNullableNothing(type)) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
nullable |= type.isNullable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeSet.isEmpty()) {
|
|
||||||
// TODO : attributes
|
|
||||||
return nullable ? JetStandardClasses.getNullableNothingType() : JetStandardClasses.getNothingType();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeSet.size() == 1) {
|
|
||||||
return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<TypeConstructor, Set<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
|
|
||||||
while (commonSupertypes.size() > 1) {
|
|
||||||
Set<JetType> merge = new HashSet<JetType>();
|
|
||||||
for (Set<JetType> supertypes : commonSupertypes.values()) {
|
|
||||||
merge.addAll(supertypes);
|
|
||||||
}
|
|
||||||
commonSupertypes = computeCommonRawSupertypes(merge);
|
|
||||||
}
|
|
||||||
assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types;
|
|
||||||
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
|
|
||||||
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
|
|
||||||
|
|
||||||
return TypeUtils.makeNullableIfNeeded(result, nullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> types) {
|
|
||||||
// we assume that all the given types are applications of the same type constructor
|
|
||||||
|
|
||||||
assert !types.isEmpty();
|
|
||||||
|
|
||||||
if (types.size() == 1) {
|
|
||||||
return types.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
|
||||||
List<TypeProjection> newProjections = new ArrayList<TypeProjection>();
|
|
||||||
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
|
|
||||||
TypeParameterDescriptor parameterDescriptor = parameters.get(i);
|
|
||||||
Set<TypeProjection> typeProjections = new HashSet<TypeProjection>();
|
|
||||||
for (JetType type : types) {
|
|
||||||
typeProjections.add(type.getArguments().get(i));
|
|
||||||
}
|
|
||||||
newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean nullable = false;
|
|
||||||
for (JetType type : types) {
|
|
||||||
nullable |= type.isNullable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : attributes?
|
|
||||||
return new JetTypeImpl(Collections.<AnnotationDescriptor>emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB); // TODO : scope
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set<TypeProjection> typeProjections) {
|
|
||||||
if (typeProjections.size() == 1) {
|
|
||||||
return typeProjections.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<JetType> ins = new HashSet<JetType>();
|
|
||||||
Set<JetType> outs = new HashSet<JetType>();
|
|
||||||
|
|
||||||
Variance variance = parameterDescriptor.getVariance();
|
|
||||||
switch (variance) {
|
|
||||||
case INVARIANT:
|
|
||||||
// Nothing
|
|
||||||
break;
|
|
||||||
case IN_VARIANCE:
|
|
||||||
outs = null;
|
|
||||||
break;
|
|
||||||
case OUT_VARIANCE:
|
|
||||||
ins = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TypeProjection projection : typeProjections) {
|
|
||||||
Variance projectionKind = projection.getProjectionKind();
|
|
||||||
if (projectionKind.allowsInPosition()) {
|
|
||||||
if (ins != null) {
|
|
||||||
ins.add(projection.getType());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ins = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (projectionKind.allowsOutPosition()) {
|
|
||||||
if (outs != null) {
|
|
||||||
outs.add(projection.getType());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
outs = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ins != null) {
|
|
||||||
JetType intersection = TypeUtils.intersect(this, ins);
|
|
||||||
if (intersection == null) {
|
|
||||||
if (outs != null) {
|
|
||||||
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(outs));
|
|
||||||
}
|
|
||||||
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
|
|
||||||
}
|
|
||||||
Variance projectionKind = variance == Variance.IN_VARIANCE ? Variance.INVARIANT : Variance.IN_VARIANCE;
|
|
||||||
return new TypeProjection(projectionKind, intersection);
|
|
||||||
} else if (outs != null) {
|
|
||||||
Variance projectionKind = variance == Variance.OUT_VARIANCE ? Variance.INVARIANT : Variance.OUT_VARIANCE;
|
|
||||||
return new TypeProjection(projectionKind, commonSupertype(outs));
|
|
||||||
} else {
|
|
||||||
Variance projectionKind = variance == Variance.OUT_VARIANCE ? Variance.INVARIANT : Variance.OUT_VARIANCE;
|
|
||||||
return new TypeProjection(projectionKind, commonSupertype(parameterDescriptor.getUpperBounds()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Map<TypeConstructor, Set<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) {
|
|
||||||
assert !types.isEmpty();
|
|
||||||
|
|
||||||
final Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>();
|
|
||||||
Set<TypeConstructor> commonSuperclasses = null;
|
|
||||||
|
|
||||||
List<TypeConstructor> order = null;
|
|
||||||
for (JetType type : types) {
|
|
||||||
Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
|
|
||||||
|
|
||||||
order = dfs(type, visited, new DfsNodeHandler<List<TypeConstructor>>() {
|
|
||||||
public LinkedList<TypeConstructor> list = new LinkedList<TypeConstructor>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeChildren(JetType current) {
|
|
||||||
TypeConstructor constructor = current.getConstructor();
|
|
||||||
|
|
||||||
Set<JetType> instances = constructorToAllInstances.get(constructor);
|
|
||||||
if (instances == null) {
|
|
||||||
instances = new HashSet<JetType>();
|
|
||||||
constructorToAllInstances.put(constructor, instances);
|
|
||||||
}
|
|
||||||
instances.add(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterChildren(JetType current) {
|
|
||||||
list.addFirst(current.getConstructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeConstructor> result() {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (commonSuperclasses == null) {
|
|
||||||
commonSuperclasses = visited;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
commonSuperclasses.retainAll(visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert order != null;
|
|
||||||
|
|
||||||
Set<TypeConstructor> notSource = new HashSet<TypeConstructor>();
|
|
||||||
Map<TypeConstructor, Set<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>();
|
|
||||||
for (TypeConstructor superConstructor : order) {
|
|
||||||
if (!commonSuperclasses.contains(superConstructor)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!notSource.contains(superConstructor)) {
|
|
||||||
result.put(superConstructor, constructorToAllInstances.get(superConstructor));
|
|
||||||
markAll(superConstructor, notSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
|
|
||||||
markerSet.add(typeConstructor);
|
|
||||||
for (JetType type : typeConstructor.getSupertypes()) {
|
|
||||||
markAll(type.getConstructor(), markerSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <R> R dfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<R> handler) {
|
|
||||||
doDfs(current, visited, handler);
|
|
||||||
return handler.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doDfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<?> handler) {
|
|
||||||
if (!visited.add(current.getConstructor())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler.beforeChildren(current);
|
|
||||||
// Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
|
|
||||||
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
|
|
||||||
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
|
||||||
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
|
||||||
if (visited.contains(supertypeConstructor)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
JetType substitutedSupertype = substitutor.safeSubstitute(supertype, Variance.INVARIANT);
|
|
||||||
dfs(substitutedSupertype, visited, handler);
|
|
||||||
}
|
|
||||||
handler.afterChildren(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConvertibleTo(@NotNull JetType actual, @NotNull JetType expected) {
|
|
||||||
return isSubtypeOf(actual, expected) ||
|
|
||||||
isConvertibleBySpecialConversion(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConvertibleBySpecialConversion(@NotNull JetType actual, @NotNull JetType expected) {
|
|
||||||
if (expected.getConstructor().equals(JetStandardClasses.getTuple(0).getTypeConstructor())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// if (actual.getValueArguments().isEmpty()) {
|
|
||||||
// TypeConstructor actualConstructor = actual.getConstructor();
|
|
||||||
// TypeConstructor constructor = expected.getConstructor();
|
|
||||||
// Set<TypeConstructor> convertibleTo = getConversionMap().get(actualConstructor);
|
|
||||||
// if (convertibleTo != null) {
|
|
||||||
// return convertibleTo.contains(constructor);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method returns the supertype of the first parameter that has the same constructor
|
// This method returns the supertype of the first parameter that has the same constructor
|
||||||
@@ -330,288 +42,278 @@ public class JetTypeChecker {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
private static JetType getOutType(TypeParameterDescriptor parameter, TypeProjection argument) {
|
||||||
return new TypeCheckingProcedure().run(subtype, supertype);
|
boolean isOutProjected = argument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE;
|
||||||
|
return isOutProjected ? parameter.getUpperBoundsAsType() : argument.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
|
private static JetType getInType(TypeParameterDescriptor parameter, TypeProjection argument) {
|
||||||
return isSubtypeOf(a, b) && isSubtypeOf(b, a);
|
boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE;
|
||||||
|
return isOutProjected ? JetStandardClasses.getNothingType() : argument.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class OldProcedure {
|
/**
|
||||||
public static boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
* Methods of this class return true to continue type checking and false to fail
|
||||||
|
*/
|
||||||
|
public interface TypingConstraintBuilder {
|
||||||
|
boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b);
|
||||||
|
boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
|
boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypingConstraintBuilder() {
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
|
return TypeUtils.equalTypes(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
return INSTANCE.isSubtypeOf(subtype, supertype);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
return false; // type checking fails
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
public static class TypeCheckingProcedure {
|
||||||
|
|
||||||
|
private final TypingConstraintBuilder constraintBuilder;
|
||||||
|
|
||||||
|
public TypeCheckingProcedure(TypingConstraintBuilder constraintBuilder) {
|
||||||
|
this.constraintBuilder = constraintBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean run(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
return isSubtypeOf(subtype, supertype);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
|
if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!supertype.isNullable() && subtype.isNullable()) {
|
if (!supertype.isNullable() && subtype.isNullable()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (JetStandardClasses.isNothing(subtype)) {
|
if (JetStandardClasses.isNothingOrNullableNothing(subtype)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Nullable JetType closestSupertype = findCorrespondingSupertype(subtype, supertype);
|
@Nullable JetType closestSupertype = findCorrespondingSupertype(subtype, supertype);
|
||||||
if (closestSupertype == null) {
|
if (closestSupertype == null) {
|
||||||
return false;
|
if (!constraintBuilder.noCorrespondingSupertype(subtype, supertype)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkSubtypeForTheSameConstructor(closestSupertype, supertype);
|
return checkSubtypeForTheSameConstructor(closestSupertype, supertype);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
|
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
TypeConstructor constructor = subtype.getConstructor();
|
TypeConstructor constructor = subtype.getConstructor();
|
||||||
assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
|
assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
|
||||||
|
|
||||||
List<TypeProjection> subArguments = subtype.getArguments();
|
List<TypeProjection> subArguments = subtype.getArguments();
|
||||||
List<TypeProjection> superArguments = supertype.getArguments();
|
List<TypeProjection> superArguments = supertype.getArguments();
|
||||||
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
||||||
boolean status = true;
|
|
||||||
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
|
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
|
||||||
TypeParameterDescriptor parameter = parameters.get(i);
|
TypeParameterDescriptor parameter = parameters.get(i);
|
||||||
TypeProjection subArgument = subArguments.get(i);
|
|
||||||
TypeProjection superArgument = superArguments.get(i);
|
|
||||||
|
|
||||||
JetType subArgumentType = subArgument.getType();
|
TypeProjection subArgument = subArguments.get(i);
|
||||||
JetType superArgumentType = superArgument.getType();
|
JetType subIn = getInType(parameter, subArgument);
|
||||||
switch (parameter.getVariance()) {
|
JetType subOut = getOutType(parameter, subArgument);
|
||||||
case INVARIANT:
|
|
||||||
switch (superArgument.getProjectionKind()) {
|
TypeProjection superArgument = superArguments.get(i);
|
||||||
case INVARIANT:
|
JetType superIn = getInType(parameter, superArgument);
|
||||||
status = subArgumentType.equals(superArgumentType);
|
JetType superOut = getOutType(parameter, superArgument);
|
||||||
break;
|
|
||||||
case OUT_VARIANCE:
|
if (parameter.getVariance() == INVARIANT && subArgument.getProjectionKind() == INVARIANT && superArgument.getProjectionKind() == INVARIANT) {
|
||||||
if (!subArgument.getProjectionKind().allowsOutPosition()) {
|
if (!constraintBuilder.assertEqualTypes(subArgument.getType(), superArgument.getType())) return false;
|
||||||
status = false;
|
|
||||||
} else {
|
|
||||||
status = !isSubtypeOf(subArgumentType, superArgumentType);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IN_VARIANCE:
|
|
||||||
if (!subArgument.getProjectionKind().allowsInPosition()) {
|
|
||||||
status = false;
|
|
||||||
} else {
|
|
||||||
status = isSubtypeOf(superArgumentType, subArgumentType);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IN_VARIANCE:
|
|
||||||
switch (superArgument.getProjectionKind()) {
|
|
||||||
case INVARIANT:
|
|
||||||
case IN_VARIANCE:
|
|
||||||
status = isSubtypeOf(superArgumentType, subArgumentType);
|
|
||||||
break;
|
|
||||||
case OUT_VARIANCE:
|
|
||||||
status = isSubtypeOf(subArgumentType, superArgumentType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUT_VARIANCE:
|
|
||||||
switch (superArgument.getProjectionKind()) {
|
|
||||||
case INVARIANT:
|
|
||||||
case OUT_VARIANCE:
|
|
||||||
case IN_VARIANCE:
|
|
||||||
status = isSubtypeOf(subArgumentType, superArgumentType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!status) {
|
else {
|
||||||
return false;
|
if (!constraintBuilder.assertSubtype(subOut, superOut)) return false;
|
||||||
|
if (!constraintBuilder.assertSubtype(superIn, subIn)) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class AbstractTypeCheckingProcedure<T> {
|
// public static abstract class AbstractTypeCheckingProcedure<T> {
|
||||||
|
//
|
||||||
protected enum StatusAction {
|
// protected enum StatusAction {
|
||||||
PROCEED(false),
|
// PROCEED(false),
|
||||||
DONE_WITH_CURRENT_TYPE(true),
|
// DONE_WITH_CURRENT_TYPE(true),
|
||||||
ABORT_ALL(true);
|
// ABORT_ALL(true);
|
||||||
|
//
|
||||||
private final boolean abort;
|
// private final boolean abort;
|
||||||
|
//
|
||||||
private StatusAction(boolean abort) {
|
// private StatusAction(boolean abort) {
|
||||||
this.abort = abort;
|
// this.abort = abort;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public boolean isAbort() {
|
// public boolean isAbort() {
|
||||||
return abort;
|
// return abort;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public final T run(@NotNull JetType subtype, @NotNull JetType supertype) {
|
// public final T run(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
proceedOrStop(subtype, supertype);
|
// proceedOrStop(subtype, supertype);
|
||||||
return result();
|
// return result();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
protected abstract StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype);
|
// protected abstract StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
|
//
|
||||||
protected abstract StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype);
|
// protected abstract StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
|
//
|
||||||
protected abstract StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType);
|
// protected abstract StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType);
|
||||||
|
//
|
||||||
protected abstract StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument);
|
// protected abstract StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument);
|
||||||
|
//
|
||||||
protected abstract StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype);
|
// protected abstract StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype);
|
||||||
|
//
|
||||||
protected abstract T result();
|
// protected abstract T result();
|
||||||
|
//
|
||||||
private StatusAction proceedOrStop(@NotNull JetType subtype, @NotNull JetType supertype) {
|
// private StatusAction proceedOrStop(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
StatusAction statusAction = startForPairOfTypes(subtype, supertype);
|
// StatusAction statusAction = startForPairOfTypes(subtype, supertype);
|
||||||
if (statusAction.isAbort()) {
|
// if (statusAction.isAbort()) {
|
||||||
return statusAction;
|
// return statusAction;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
JetType closestSupertype = findCorrespondingSupertype(subtype, supertype);
|
// JetType closestSupertype = findCorrespondingSupertype(subtype, supertype);
|
||||||
if (closestSupertype == null) {
|
// if (closestSupertype == null) {
|
||||||
return noCorrespondingSupertype(subtype, supertype);
|
// return noCorrespondingSupertype(subtype, supertype);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
proceed(closestSupertype, supertype);
|
// proceed(closestSupertype, supertype);
|
||||||
return doneForPairOfTypes(subtype, supertype);
|
// return doneForPairOfTypes(subtype, supertype);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void proceed(@NotNull JetType subtype, @NotNull JetType supertype) {
|
// private void proceed(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
TypeConstructor constructor = subtype.getConstructor();
|
// TypeConstructor constructor = subtype.getConstructor();
|
||||||
assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
|
// assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
|
||||||
|
//
|
||||||
List<TypeProjection> subArguments = subtype.getArguments();
|
// List<TypeProjection> subArguments = subtype.getArguments();
|
||||||
List<TypeProjection> superArguments = supertype.getArguments();
|
// List<TypeProjection> superArguments = supertype.getArguments();
|
||||||
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
// List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
||||||
|
//
|
||||||
loop:
|
// loop:
|
||||||
for (int i = 0; i < parameters.size(); i++) {
|
// for (int i = 0; i < parameters.size(); i++) {
|
||||||
TypeParameterDescriptor parameter = parameters.get(i);
|
// TypeParameterDescriptor parameter = parameters.get(i);
|
||||||
TypeProjection subArgument = subArguments.get(i);
|
// TypeProjection subArgument = subArguments.get(i);
|
||||||
TypeProjection superArgument = superArguments.get(i);
|
// TypeProjection superArgument = superArguments.get(i);
|
||||||
|
//
|
||||||
JetType subArgumentType = subArgument.getType();
|
// JetType subArgumentType = subArgument.getType();
|
||||||
JetType superArgumentType = superArgument.getType();
|
// JetType superArgumentType = superArgument.getType();
|
||||||
|
//
|
||||||
StatusAction action = null;
|
// StatusAction action = null;
|
||||||
switch (parameter.getVariance()) {
|
// switch (parameter.getVariance()) {
|
||||||
case INVARIANT:
|
// case INVARIANT:
|
||||||
switch (superArgument.getProjectionKind()) {
|
// switch (superArgument.getProjectionKind()) {
|
||||||
case INVARIANT:
|
// case INVARIANT:
|
||||||
action = equalTypesRequired(subArgumentType, superArgumentType);
|
// action = equalTypesRequired(subArgumentType, superArgumentType);
|
||||||
break;
|
// break;
|
||||||
case OUT_VARIANCE:
|
// case OUT_VARIANCE:
|
||||||
if (!subArgument.getProjectionKind().allowsOutPosition()) {
|
// if (!subArgument.getProjectionKind().allowsOutPosition()) {
|
||||||
action = varianceConflictFound(subArgument, superArgument);
|
// action = varianceConflictFound(subArgument, superArgument);
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
action = proceedOrStop(subArgumentType, superArgumentType);
|
// action = proceedOrStop(subArgumentType, superArgumentType);
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
case IN_VARIANCE:
|
// case IN_VARIANCE:
|
||||||
if (!subArgument.getProjectionKind().allowsInPosition()) {
|
// if (!subArgument.getProjectionKind().allowsInPosition()) {
|
||||||
action = varianceConflictFound(subArgument, superArgument);
|
// action = varianceConflictFound(subArgument, superArgument);
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
action = proceedOrStop(superArgumentType, subArgumentType);
|
// action = proceedOrStop(superArgumentType, subArgumentType);
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
case IN_VARIANCE:
|
// case IN_VARIANCE:
|
||||||
switch (superArgument.getProjectionKind()) {
|
// switch (superArgument.getProjectionKind()) {
|
||||||
case INVARIANT:
|
// case INVARIANT:
|
||||||
case IN_VARIANCE:
|
// case IN_VARIANCE:
|
||||||
action = proceedOrStop(superArgumentType, subArgumentType);
|
// action = proceedOrStop(superArgumentType, subArgumentType);
|
||||||
break;
|
// break;
|
||||||
case OUT_VARIANCE:
|
// case OUT_VARIANCE:
|
||||||
action = proceedOrStop(subArgumentType, superArgumentType);
|
// action = proceedOrStop(subArgumentType, superArgumentType);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
case OUT_VARIANCE:
|
// case OUT_VARIANCE:
|
||||||
switch (superArgument.getProjectionKind()) {
|
// switch (superArgument.getProjectionKind()) {
|
||||||
case INVARIANT:
|
// case INVARIANT:
|
||||||
case OUT_VARIANCE:
|
// case OUT_VARIANCE:
|
||||||
case IN_VARIANCE:
|
// case IN_VARIANCE:
|
||||||
action = proceedOrStop(subArgumentType, superArgumentType);
|
// action = proceedOrStop(subArgumentType, superArgumentType);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
switch (action) {
|
// switch (action) {
|
||||||
case ABORT_ALL: break loop;
|
// case ABORT_ALL: break loop;
|
||||||
case DONE_WITH_CURRENT_TYPE:
|
// case DONE_WITH_CURRENT_TYPE:
|
||||||
default:
|
// default:
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
private static class TypeCheckingProcedure extends AbstractTypeCheckingProcedure<Boolean> {
|
// private static class TypeCheckingProcedure extends AbstractTypeCheckingProcedure<Boolean> {
|
||||||
|
//
|
||||||
|
// private boolean result = true;
|
||||||
|
//
|
||||||
|
// private StatusAction fail() {
|
||||||
|
// result = false;
|
||||||
|
// return StatusAction.ABORT_ALL;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
// if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
|
||||||
|
// return StatusAction.DONE_WITH_CURRENT_TYPE;
|
||||||
|
// }
|
||||||
|
// if (!supertype.isNullable() && subtype.isNullable()) {
|
||||||
|
// return fail();
|
||||||
|
// }
|
||||||
|
// if (JetStandardClasses.isNothingOrNullableNothing(subtype)) {
|
||||||
|
// return StatusAction.DONE_WITH_CURRENT_TYPE;
|
||||||
|
// }
|
||||||
|
// return StatusAction.PROCEED;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
// return fail();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) {
|
||||||
|
// if (!subArgumentType.equals(superArgumentType)) {
|
||||||
|
// return fail();
|
||||||
|
// }
|
||||||
|
// return StatusAction.PROCEED;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) {
|
||||||
|
// return fail();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
// return StatusAction.PROCEED;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected Boolean result() {
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
private boolean result = true;
|
|
||||||
|
|
||||||
private StatusAction fail() {
|
|
||||||
result = false;
|
|
||||||
return StatusAction.ABORT_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
|
|
||||||
return StatusAction.DONE_WITH_CURRENT_TYPE;
|
|
||||||
}
|
|
||||||
if (!supertype.isNullable() && subtype.isNullable()) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
if (JetStandardClasses.isNothingOrNullableNothing(subtype)) {
|
|
||||||
return StatusAction.DONE_WITH_CURRENT_TYPE;
|
|
||||||
}
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) {
|
|
||||||
if (!subArgumentType.equals(superArgumentType)) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean result() {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DfsNodeHandler<R> {
|
|
||||||
|
|
||||||
public void beforeChildren(JetType current) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterChildren(JetType current) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public R result() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public class TypeSubstitutor {
|
|||||||
case OUT_VARIANCE:
|
case OUT_VARIANCE:
|
||||||
if (projectionKindValue == Variance.IN_VARIANCE) {
|
if (projectionKindValue == Variance.IN_VARIANCE) {
|
||||||
effectiveProjectionKindValue = Variance.INVARIANT;
|
effectiveProjectionKindValue = Variance.INVARIANT;
|
||||||
effectiveTypeValue = correspondingTypeParameter.getBoundsAsType();
|
effectiveTypeValue = correspondingTypeParameter.getUpperBoundsAsType();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
effectiveTypeValue = typeValue;
|
effectiveTypeValue = typeValue;
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ public class TypeUtils {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
|
public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
|
||||||
return new TypeProjection(Variance.OUT_VARIANCE, parameterDescriptor.getBoundsAsType());
|
return new TypeProjection(Variance.OUT_VARIANCE, parameterDescriptor.getUpperBoundsAsType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection<JetType> result) {
|
private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection<JetType> result) {
|
||||||
@@ -424,4 +424,7 @@ public class TypeUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
|
return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -57,7 +57,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getSelectorReturnType(NO_RECEIVER, null, expression, context); // TODO : Extensions to this
|
return DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context); // TODO : Extensions to this
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -419,14 +419,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitQualifiedExpression(JetQualifiedExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
public JetType visitQualifiedExpression(JetQualifiedExpression expression, ExpressionTypingContext context) {
|
||||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
|
|
||||||
// TODO : functions as values
|
// TODO : functions as values
|
||||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||||
|
ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE);
|
||||||
JetType receiverType = facade.getType(receiverExpression,
|
JetType receiverType = facade.getType(receiverExpression,
|
||||||
context
|
contextWithNoExpectedType
|
||||||
.replaceExpectedType(NO_EXPECTED_TYPE)
|
|
||||||
.replaceExpectedReturnType(NO_EXPECTED_TYPE)
|
.replaceExpectedReturnType(NO_EXPECTED_TYPE)
|
||||||
.replaceNamespacesAllowed(true));
|
.replaceNamespacesAllowed(true));
|
||||||
if (selectorExpression == null) return null;
|
if (selectorExpression == null) return null;
|
||||||
@@ -462,14 +461,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
|
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
|
||||||
}
|
}
|
||||||
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
|
return DataFlowUtils.checkType(result, expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
|
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
|
||||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||||
CompileTimeConstant<?> receiverValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression);
|
CompileTimeConstant<?> receiverValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression);
|
||||||
CompileTimeConstant<?> wholeExpressionValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
|
CompileTimeConstant<?> wholeExpressionValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||||
if (wholeExpressionValue == null && receiverValue != null && !(receiverValue instanceof ErrorValue) && receiverValue.getValue() instanceof Number) {
|
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, selectorExpression);
|
||||||
|
if (wholeExpressionValue == null && receiverValue != null && !(receiverValue instanceof ErrorValue) && receiverValue.getValue() instanceof Number
|
||||||
|
&& context.semanticServices.getStandardLibrary().getNumber() == declarationDescriptor) {
|
||||||
Number value = (Number) receiverValue.getValue();
|
Number value = (Number) receiverValue.getValue();
|
||||||
String referencedName = selectorExpression.getReferencedName();
|
String referencedName = selectorExpression.getReferencedName();
|
||||||
if (OperatorConventions.NUMBER_CONVERSIONS.contains(referencedName)) {
|
if (OperatorConventions.NUMBER_CONVERSIONS.contains(referencedName)) {
|
||||||
@@ -508,14 +509,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression);
|
VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression);
|
||||||
if (variableDescriptor != null) {
|
if (variableDescriptor != null) {
|
||||||
temporaryTrace.commit();
|
temporaryTrace.commit();
|
||||||
return DataFlowUtils.checkType(variableDescriptor.getOutType(), nameExpression, context);
|
return variableDescriptor.getOutType();
|
||||||
}
|
}
|
||||||
ExpressionTypingContext newContext = receiver.exists() ? context.replaceScope(receiver.getType().getMemberScope()) : context;
|
ExpressionTypingContext newContext = receiver.exists() ? context.replaceScope(receiver.getType().getMemberScope()) : context;
|
||||||
JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext);
|
JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext);
|
||||||
if (jetType == null) {
|
if (jetType == null) {
|
||||||
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
|
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
|
||||||
}
|
}
|
||||||
return DataFlowUtils.checkType(jetType, nameExpression, context);
|
return jetType;
|
||||||
}
|
}
|
||||||
else if (selectorExpression instanceof JetQualifiedExpression) {
|
else if (selectorExpression instanceof JetQualifiedExpression) {
|
||||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
|
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
|
||||||
@@ -712,7 +713,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
if (rightType != null) {
|
if (rightType != null) {
|
||||||
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
|
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
|
||||||
return TypeUtils.makeNullableAsSpecified(context.semanticServices.getTypeChecker().commonSupertype(leftType, rightType), rightType.isNullable());
|
return TypeUtils.makeNullableAsSpecified(CommonSupertypes.commonSupertype(Arrays.asList(leftType, rightType)), rightType.isNullable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-10
@@ -16,15 +16,9 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
|||||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
||||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||||
@@ -99,7 +93,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
result = thenType;
|
result = thenType;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = context.semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType));
|
result = CommonSupertypes.commonSupertype(Arrays.asList(thenType, elseType));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean jumpInThen = thenType != null && JetStandardClasses.isNothing(thenType);
|
boolean jumpInThen = thenType != null && JetStandardClasses.isNothing(thenType);
|
||||||
@@ -352,7 +346,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return context.semanticServices.getTypeChecker().commonSupertype(types);
|
return CommonSupertypes.commonSupertype(types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -86,7 +86,7 @@ public class ExpressionTypingServices {
|
|||||||
Collection<JetType> types = typeMap.values();
|
Collection<JetType> types = typeMap.values();
|
||||||
return types.isEmpty()
|
return types.isEmpty()
|
||||||
? JetStandardClasses.getNothingType()
|
? JetStandardClasses.getNothingType()
|
||||||
: semanticServices.getTypeChecker().commonSupertype(types);
|
: CommonSupertypes.commonSupertype(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
|
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
|
||||||
|
|||||||
+1
-2
@@ -13,7 +13,6 @@ import org.jetbrains.jet.lang.psi.JetExpression;
|
|||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
|
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
|
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
@@ -47,7 +46,7 @@ public class ExpressionTypingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBoolean(@NotNull JetSemanticServices semanticServices, @NotNull JetType type) {
|
public static boolean isBoolean(@NotNull JetSemanticServices semanticServices, @NotNull JetType type) {
|
||||||
return semanticServices.getTypeChecker().isConvertibleTo(type, semanticServices.getStandardLibrary().getBooleanType());
|
return semanticServices.getTypeChecker().isSubtypeOf(type, semanticServices.getStandardLibrary().getBooleanType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean ensureBooleanResult(JetExpression operationSign, String name, JetType resultType, ExpressionTypingContext context) {
|
public static boolean ensureBooleanResult(JetExpression operationSign, String name, JetType resultType, ExpressionTypingContext context) {
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!expressionTypes.isEmpty()) {
|
if (!expressionTypes.isEmpty()) {
|
||||||
return context.semanticServices.getTypeChecker().commonSupertype(expressionTypes);
|
return CommonSupertypes.commonSupertype(expressionTypes);
|
||||||
}
|
}
|
||||||
else if (expression.getEntries().isEmpty()) {
|
else if (expression.getEntries().isEmpty()) {
|
||||||
// context.trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression");
|
// context.trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression");
|
||||||
|
|||||||
+7
-402
@@ -1,413 +1,18 @@
|
|||||||
package org.jetbrains.jet.lang.types.inference;
|
package org.jetbrains.jet.lang.types.inference;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.Variance;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class ConstraintSystem {
|
public interface ConstraintSystem {
|
||||||
|
void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance);
|
||||||
|
|
||||||
// private static final Supplier<Set<TypeValue>> SET_SUPPLIER = new Supplier<Set<TypeValue>>() {
|
void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper);
|
||||||
// @Override
|
|
||||||
// public Set<TypeValue> get() {
|
|
||||||
// return Sets.newHashSet();
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
|
||||||
private LoopInTypeVariableConstraintsException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoopInTypeVariableConstraintsException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class TypeValue {
|
|
||||||
private final Set<TypeValue> upperBounds = Sets.newHashSet();
|
|
||||||
private final Set<TypeValue> lowerBounds = Sets.newHashSet();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Set<TypeValue> getUpperBounds() {
|
|
||||||
return upperBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Set<TypeValue> getLowerBounds() {
|
|
||||||
return lowerBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public abstract KnownType getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UnknownType extends TypeValue {
|
|
||||||
|
|
||||||
private final TypeParameterDescriptor typeParameterDescriptor;
|
|
||||||
private final Variance positionVariance;
|
|
||||||
private KnownType value;
|
|
||||||
private boolean beingComputed = false;
|
|
||||||
|
|
||||||
private UnknownType(TypeParameterDescriptor typeParameterDescriptor, Variance positionVariance) {
|
|
||||||
this.typeParameterDescriptor = typeParameterDescriptor;
|
|
||||||
this.positionVariance = positionVariance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TypeParameterDescriptor getTypeParameterDescriptor() {
|
|
||||||
return typeParameterDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KnownType getValue() {
|
|
||||||
if (beingComputed) {
|
|
||||||
throw new LoopInTypeVariableConstraintsException();
|
|
||||||
}
|
|
||||||
if (value == null) {
|
|
||||||
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
|
||||||
beingComputed = true;
|
|
||||||
try {
|
|
||||||
if (positionVariance == Variance.IN_VARIANCE) {
|
|
||||||
// maximal solution
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// minimal solution
|
|
||||||
|
|
||||||
Set<TypeValue> lowerBounds = getLowerBounds();
|
|
||||||
if (!lowerBounds.isEmpty()) {
|
|
||||||
Set<JetType> types = getTypes(lowerBounds);
|
|
||||||
|
|
||||||
JetType commonSupertype = typeChecker.commonSupertype(types);
|
|
||||||
for (TypeValue upperBound : getUpperBounds()) {
|
|
||||||
if (!typeChecker.isSubtypeOf(commonSupertype, upperBound.getValue().getType())) {
|
|
||||||
value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
|
|
||||||
value = new KnownType(commonSupertype);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Set<TypeValue> upperBounds = getUpperBounds();
|
|
||||||
Set<JetType> types = getTypes(upperBounds);
|
|
||||||
JetType intersect = TypeUtils.intersect(typeChecker, types);
|
|
||||||
|
|
||||||
value = new KnownType(intersect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
beingComputed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<JetType> getTypes(Set<TypeValue> lowerBounds) {
|
|
||||||
Set<JetType> types = Sets.newHashSet();
|
|
||||||
for (TypeValue lowerBound : lowerBounds) {
|
|
||||||
types.add(lowerBound.getValue().getType());
|
|
||||||
}
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "?" + typeParameterDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class KnownType extends TypeValue {
|
|
||||||
|
|
||||||
private final JetType type;
|
|
||||||
|
|
||||||
public KnownType(@NotNull JetType type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public JetType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KnownType getValue() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return type.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<JetType, KnownType> knownTypes = Maps.newHashMap();
|
|
||||||
private final Map<TypeParameterDescriptor, UnknownType> unknownTypes = Maps.newHashMap();
|
|
||||||
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TypeValue getTypeValueFor(@NotNull JetType type) {
|
ConstraintSystemSolution solve();
|
||||||
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
|
}
|
||||||
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
|
|
||||||
UnknownType unknownType = unknownTypes.get(typeParameterDescriptor);
|
|
||||||
if (unknownType != null) {
|
|
||||||
return unknownType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KnownType typeValue = knownTypes.get(type);
|
|
||||||
if (typeValue == null) {
|
|
||||||
typeValue = new KnownType(type);
|
|
||||||
knownTypes.put(type, typeValue);
|
|
||||||
}
|
|
||||||
return typeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) {
|
|
||||||
assert !unknownTypes.containsKey(typeParameterDescriptor);
|
|
||||||
UnknownType typeValue = new UnknownType(typeParameterDescriptor, positionVariance);
|
|
||||||
unknownTypes.put(typeParameterDescriptor, typeValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private UnknownType getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) {
|
|
||||||
UnknownType unknownType = unknownTypes.get(typeParameterDescriptor);
|
|
||||||
if (unknownType == null) {
|
|
||||||
throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system: " + typeParameterDescriptor);
|
|
||||||
}
|
|
||||||
return unknownType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) {
|
|
||||||
TypeValue typeValueForLower = getTypeValueFor(lower);
|
|
||||||
TypeValue typeValueForUpper = getTypeValueFor(upper);
|
|
||||||
addSubtypingConstraintOnTypeValues(typeValueForLower, typeValueForUpper);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
|
||||||
println(typeValueForLower + " :< " + typeValueForUpper);
|
|
||||||
typeValueForLower.getUpperBounds().add(typeValueForUpper);
|
|
||||||
typeValueForUpper.getLowerBounds().add(typeValueForLower);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Solution solve() {
|
|
||||||
// Expand custom bounds, e.g. List<T> <: List<Int>
|
|
||||||
for (Map.Entry<JetType, KnownType> entry : Sets.newHashSet(knownTypes.entrySet())) {
|
|
||||||
JetType jetType = entry.getKey();
|
|
||||||
KnownType typeValue = entry.getValue();
|
|
||||||
|
|
||||||
for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
|
||||||
if (upperBound instanceof KnownType) {
|
|
||||||
KnownType knownBoundType = (KnownType) upperBound;
|
|
||||||
boolean ok = new TypeConstraintExpander().run(jetType, knownBoundType.getType());
|
|
||||||
if (!ok) {
|
|
||||||
return new Solution(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower bounds?
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in upper bounds from type parameter bounds
|
|
||||||
for (Map.Entry<TypeParameterDescriptor, UnknownType> entry : Sets.newHashSet(unknownTypes.entrySet())) {
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
|
|
||||||
UnknownType typeValue = entry.getValue();
|
|
||||||
for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) {
|
|
||||||
addSubtypingConstraintOnTypeValues(typeValue, getTypeValueFor(upperBound));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// effective bounds for each node
|
|
||||||
Set<TypeValue> visited = Sets.newHashSet();
|
|
||||||
for (KnownType knownType : knownTypes.values()) {
|
|
||||||
transitiveClosure(knownType, visited);
|
|
||||||
}
|
|
||||||
for (UnknownType unknownType : unknownTypes.values()) {
|
|
||||||
transitiveClosure(unknownType, visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find inconsistencies
|
|
||||||
Solution solution = new Solution(false);
|
|
||||||
|
|
||||||
for (UnknownType unknownType : unknownTypes.values()) {
|
|
||||||
check(unknownType, solution);
|
|
||||||
}
|
|
||||||
for (KnownType knownType : knownTypes.values()) {
|
|
||||||
check(knownType, solution);
|
|
||||||
}
|
|
||||||
|
|
||||||
return solution;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void check(TypeValue typeValue, Solution solution) {
|
|
||||||
try {
|
|
||||||
KnownType resultingValue = typeValue.getValue();
|
|
||||||
JetType type = solution.getSubstitutor().substitute(resultingValue.getType(), Variance.INVARIANT); // TODO
|
|
||||||
for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
|
||||||
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
|
||||||
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
|
||||||
solution.registerError();
|
|
||||||
println("Constraint violation: " + type + " :< " + boundingType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
|
||||||
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
|
||||||
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
|
||||||
solution.registerError();
|
|
||||||
println("Constraint violation: " + boundingType + " :< " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (LoopInTypeVariableConstraintsException e) {
|
|
||||||
solution.registerError();
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transitiveClosure(TypeValue current, Set<TypeValue> visited) {
|
|
||||||
if (!visited.add(current)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) {
|
|
||||||
transitiveClosure(upperBound, visited);
|
|
||||||
Set<TypeValue> upperBounds = upperBound.getUpperBounds();
|
|
||||||
for (TypeValue transitiveBound : upperBounds) {
|
|
||||||
addSubtypingConstraintOnTypeValues(current, transitiveBound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Solution {
|
|
||||||
private final TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
|
|
||||||
@Override
|
|
||||||
public TypeProjection get(TypeConstructor key) {
|
|
||||||
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
|
|
||||||
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
|
||||||
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
|
||||||
println(descriptor + " |-> " + getValue(descriptor));
|
|
||||||
return new TypeProjection(getValue(descriptor));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
private boolean failed;
|
|
||||||
|
|
||||||
public Solution(boolean failed) {
|
|
||||||
this.failed = failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerError() {
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccessful() {
|
|
||||||
return !failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) {
|
|
||||||
KnownType value = getTypeVariable(typeParameterDescriptor).getValue();
|
|
||||||
return value == null ? null : value.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeSubstitutor getSubstitutor() {
|
|
||||||
return typeSubstitutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TypeConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure<Boolean> {
|
|
||||||
|
|
||||||
private boolean error = false;
|
|
||||||
|
|
||||||
private StatusAction fail() {
|
|
||||||
error = true;
|
|
||||||
return StatusAction.ABORT_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
return tryToAddConstraint(subtype, supertype);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StatusAction tryToAddConstraint(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
TypeValue subtypeValue = getTypeValueFor(subtype);
|
|
||||||
TypeValue supertypeValue = getTypeValueFor(supertype);
|
|
||||||
|
|
||||||
if (someUnknown(subtypeValue, supertypeValue)) {
|
|
||||||
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
|
|
||||||
}
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
|
|
||||||
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
if (someUnknown(getTypeValueFor(subtype), getTypeValueFor(supertype))) {
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) {
|
|
||||||
if (!subArgumentType.equals(superArgumentType)) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) {
|
|
||||||
return fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) {
|
|
||||||
return StatusAction.PROCEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean result() {
|
|
||||||
return !error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void println(String message) {
|
|
||||||
// System.out.println(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+421
@@ -0,0 +1,421 @@
|
|||||||
|
package org.jetbrains.jet.lang.types.inference;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class ConstraintSystemImpl implements ConstraintSystem {
|
||||||
|
|
||||||
|
private static class LoopInTypeVariableConstraintsException extends RuntimeException {
|
||||||
|
private LoopInTypeVariableConstraintsException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoopInTypeVariableConstraintsException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoopInTypeVariableConstraintsException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoopInTypeVariableConstraintsException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class TypeValue {
|
||||||
|
private final Set<TypeValue> upperBounds = Sets.newHashSet();
|
||||||
|
private final Set<TypeValue> lowerBounds = Sets.newHashSet();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Set<TypeValue> getUpperBounds() {
|
||||||
|
return upperBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Set<TypeValue> getLowerBounds() {
|
||||||
|
return lowerBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract KnownType getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UnknownType extends TypeValue {
|
||||||
|
|
||||||
|
private final TypeParameterDescriptor typeParameterDescriptor;
|
||||||
|
private final Variance positionVariance;
|
||||||
|
private KnownType value;
|
||||||
|
private boolean beingComputed = false;
|
||||||
|
|
||||||
|
private UnknownType(TypeParameterDescriptor typeParameterDescriptor, Variance positionVariance) {
|
||||||
|
this.typeParameterDescriptor = typeParameterDescriptor;
|
||||||
|
this.positionVariance = positionVariance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public TypeParameterDescriptor getTypeParameterDescriptor() {
|
||||||
|
return typeParameterDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KnownType getValue() {
|
||||||
|
if (beingComputed) {
|
||||||
|
throw new LoopInTypeVariableConstraintsException();
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||||
|
beingComputed = true;
|
||||||
|
try {
|
||||||
|
if (positionVariance == Variance.IN_VARIANCE) {
|
||||||
|
// maximal solution
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// minimal solution
|
||||||
|
|
||||||
|
Set<TypeValue> lowerBounds = getLowerBounds();
|
||||||
|
if (!lowerBounds.isEmpty()) {
|
||||||
|
Set<JetType> types = getTypes(lowerBounds);
|
||||||
|
|
||||||
|
JetType commonSupertype = CommonSupertypes.commonSupertype(types);
|
||||||
|
for (TypeValue upperBound : getUpperBounds()) {
|
||||||
|
if (!typeChecker.isSubtypeOf(commonSupertype, upperBound.getValue().getType())) {
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
|
||||||
|
value = new KnownType(commonSupertype);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Set<TypeValue> upperBounds = getUpperBounds();
|
||||||
|
Set<JetType> types = getTypes(upperBounds);
|
||||||
|
JetType intersect = TypeUtils.intersect(typeChecker, types);
|
||||||
|
|
||||||
|
value = new KnownType(intersect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
beingComputed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setValue(@NotNull KnownType value) {
|
||||||
|
if (this.value != null) {
|
||||||
|
// If we have already assigned a value to this unknown,
|
||||||
|
// it is a conflict to assign another one, unless this new one is equal to the previous
|
||||||
|
return TypeUtils.equalTypes(this.value.getType(), value.getType());
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<JetType> getTypes(Set<TypeValue> lowerBounds) {
|
||||||
|
Set<JetType> types = Sets.newHashSet();
|
||||||
|
for (TypeValue lowerBound : lowerBounds) {
|
||||||
|
types.add(lowerBound.getValue().getType());
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "?" + typeParameterDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class KnownType extends TypeValue {
|
||||||
|
|
||||||
|
private final JetType type;
|
||||||
|
|
||||||
|
public KnownType(@NotNull JetType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KnownType getValue() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return type.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<JetType, KnownType> knownTypes = Maps.newHashMap();
|
||||||
|
private final Map<TypeParameterDescriptor, UnknownType> unknownTypes = Maps.newHashMap();
|
||||||
|
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||||
|
|
||||||
|
private final JetTypeChecker.TypeCheckingProcedure constraintExpander = new JetTypeChecker.TypeCheckingProcedure(new JetTypeChecker.TypingConstraintBuilder() {
|
||||||
|
@Override
|
||||||
|
public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
|
TypeValue aValue = getTypeValueFor(a);
|
||||||
|
TypeValue bValue = getTypeValueFor(b);
|
||||||
|
|
||||||
|
if (aValue instanceof UnknownType) {
|
||||||
|
UnknownType aUnknown = (UnknownType) aValue;
|
||||||
|
if (bValue instanceof UnknownType) {
|
||||||
|
UnknownType bUnknown = (UnknownType) bValue;
|
||||||
|
mergeUnknowns(aUnknown, bUnknown);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!aUnknown.setValue((KnownType) bValue)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bValue instanceof UnknownType) {
|
||||||
|
UnknownType bUnknown = (UnknownType) bValue;
|
||||||
|
if (!bUnknown.setValue((KnownType) aValue)) return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return TypeUtils.equalTypes(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
TypeValue subtypeValue = getTypeValueFor(subtype);
|
||||||
|
TypeValue supertypeValue = getTypeValueFor(supertype);
|
||||||
|
|
||||||
|
if (someUnknown(subtypeValue, supertypeValue)) {
|
||||||
|
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
|
// If some of the types is an unknown, the constraint is already generated, and we should carry on
|
||||||
|
// otherwise there can be no solution, and we should fail
|
||||||
|
return someUnknown(getTypeValueFor(subtype), getTypeValueFor(supertype));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
|
||||||
|
return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
public ConstraintSystemImpl() {}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TypeValue getTypeValueFor(@NotNull JetType type) {
|
||||||
|
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
|
||||||
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
UnknownType unknownType = unknownTypes.get(typeParameterDescriptor);
|
||||||
|
if (unknownType != null) {
|
||||||
|
return unknownType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KnownType typeValue = knownTypes.get(type);
|
||||||
|
if (typeValue == null) {
|
||||||
|
typeValue = new KnownType(type);
|
||||||
|
knownTypes.put(type, typeValue);
|
||||||
|
}
|
||||||
|
return typeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) {
|
||||||
|
assert !unknownTypes.containsKey(typeParameterDescriptor);
|
||||||
|
UnknownType typeValue = new UnknownType(typeParameterDescriptor, positionVariance);
|
||||||
|
unknownTypes.put(typeParameterDescriptor, typeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private UnknownType getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) {
|
||||||
|
UnknownType unknownType = unknownTypes.get(typeParameterDescriptor);
|
||||||
|
if (unknownType == null) {
|
||||||
|
throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system: " + typeParameterDescriptor);
|
||||||
|
}
|
||||||
|
return unknownType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeUnknowns(@NotNull UnknownType a, @NotNull UnknownType b) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) {
|
||||||
|
TypeValue typeValueForLower = getTypeValueFor(lower);
|
||||||
|
TypeValue typeValueForUpper = getTypeValueFor(upper);
|
||||||
|
addSubtypingConstraintOnTypeValues(typeValueForLower, typeValueForUpper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
|
||||||
|
println(typeValueForLower + " :< " + typeValueForUpper);
|
||||||
|
typeValueForLower.getUpperBounds().add(typeValueForUpper);
|
||||||
|
typeValueForUpper.getLowerBounds().add(typeValueForLower);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public ConstraintSystemSolution solve() {
|
||||||
|
// Expand custom bounds, e.g. List<T> <: List<Int>
|
||||||
|
for (Map.Entry<JetType, KnownType> entry : Sets.newHashSet(knownTypes.entrySet())) {
|
||||||
|
JetType jetType = entry.getKey();
|
||||||
|
KnownType typeValue = entry.getValue();
|
||||||
|
|
||||||
|
for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
||||||
|
if (upperBound instanceof KnownType) {
|
||||||
|
KnownType knownBoundType = (KnownType) upperBound;
|
||||||
|
boolean ok = constraintExpander.run(jetType, knownBoundType.getType());
|
||||||
|
if (!ok) {
|
||||||
|
return new Solution(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower bounds?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in upper bounds from type parameter bounds
|
||||||
|
for (Map.Entry<TypeParameterDescriptor, UnknownType> entry : Sets.newHashSet(unknownTypes.entrySet())) {
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
|
||||||
|
UnknownType typeValue = entry.getValue();
|
||||||
|
for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) {
|
||||||
|
addSubtypingConstraintOnTypeValues(typeValue, getTypeValueFor(upperBound));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// effective bounds for each node
|
||||||
|
Set<TypeValue> visited = Sets.newHashSet();
|
||||||
|
for (KnownType knownType : knownTypes.values()) {
|
||||||
|
transitiveClosure(knownType, visited);
|
||||||
|
}
|
||||||
|
for (UnknownType unknownType : unknownTypes.values()) {
|
||||||
|
transitiveClosure(unknownType, visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find inconsistencies
|
||||||
|
Solution solution = new Solution(false);
|
||||||
|
|
||||||
|
for (UnknownType unknownType : unknownTypes.values()) {
|
||||||
|
check(unknownType, solution);
|
||||||
|
}
|
||||||
|
for (KnownType knownType : knownTypes.values()) {
|
||||||
|
check(knownType, solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : check that all bounds are respected by solutions:
|
||||||
|
// we have set some of them from equality constraints with known types
|
||||||
|
// and thus the bounds may be violated if some of the constraints conflict
|
||||||
|
|
||||||
|
return solution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(TypeValue typeValue, Solution solution) {
|
||||||
|
try {
|
||||||
|
KnownType resultingValue = typeValue.getValue();
|
||||||
|
JetType type = solution.getSubstitutor().substitute(resultingValue.getType(), Variance.INVARIANT); // TODO
|
||||||
|
for (TypeValue upperBound : typeValue.getUpperBounds()) {
|
||||||
|
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
|
||||||
|
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
|
||||||
|
solution.registerError();
|
||||||
|
println("Constraint violation: " + type + " :< " + boundingType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
|
||||||
|
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
|
||||||
|
if (!typeChecker.isSubtypeOf(boundingType, type)) {
|
||||||
|
solution.registerError();
|
||||||
|
println("Constraint violation: " + boundingType + " :< " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LoopInTypeVariableConstraintsException e) {
|
||||||
|
solution.registerError();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transitiveClosure(TypeValue current, Set<TypeValue> visited) {
|
||||||
|
if (!visited.add(current)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) {
|
||||||
|
transitiveClosure(upperBound, visited);
|
||||||
|
Set<TypeValue> upperBounds = upperBound.getUpperBounds();
|
||||||
|
for (TypeValue transitiveBound : upperBounds) {
|
||||||
|
addSubtypingConstraintOnTypeValues(current, transitiveBound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Solution implements ConstraintSystemSolution {
|
||||||
|
private final TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
|
||||||
|
@Override
|
||||||
|
public TypeProjection get(TypeConstructor key) {
|
||||||
|
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
|
||||||
|
if (declarationDescriptor instanceof TypeParameterDescriptor) {
|
||||||
|
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
println(descriptor + " |-> " + getValue(descriptor));
|
||||||
|
return new TypeProjection(getValue(descriptor));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
private boolean failed;
|
||||||
|
|
||||||
|
public Solution(boolean failed) {
|
||||||
|
this.failed = failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerError() {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return !failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) {
|
||||||
|
KnownType value = getTypeVariable(typeParameterDescriptor).getValue();
|
||||||
|
return value == null ? null : value.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeSubstitutor getSubstitutor() {
|
||||||
|
return typeSubstitutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void println(String message) {
|
||||||
|
// System.out.println(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package org.jetbrains.jet.lang.types.inference;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public interface ConstraintSystemSolution {
|
||||||
|
boolean isSuccessful();
|
||||||
|
|
||||||
|
TypeSubstitutor getSubstitutor();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
JetType getValue(TypeParameterDescriptor typeParameterDescriptor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// KT-258 Support equality constraints in type inference
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val attributes : HashMap<String, String> = HashMap()
|
||||||
|
attributes["href"] = "1" // inference fails, but it shouldn't
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> java.util.Map<K, V>.set(key : K, value : V) {}//= this.put(key, value)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// KT-287 Infer constructor type arguments
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun attributes() : Map<String, String> = HashMap() // Should be inferred;
|
||||||
|
val attributes : Map<String, String> = HashMap() // Should be inferred;
|
||||||
|
|
||||||
|
fun foo(m : Map<String, String>) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo(HashMap())
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// KT-459 Type argument inference fails when class names are fully qualified
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val attributes : java.util.HashMap<String, String> = java.util.HashMap() // failure!
|
||||||
|
attributes["href"] = "1" // inference fails, but it shouldn't
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K, V> java.util.Map<K, V>.set(key : K, value : V) {}//= this.put(key, value)
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// http://youtrack.jetbrains.net/issue/KT-419
|
||||||
|
|
||||||
|
class A(w: Int) {
|
||||||
|
var c = w
|
||||||
|
|
||||||
|
{
|
||||||
|
c = 81
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// http://youtrack.jetbrains.net/issue/KT-449
|
||||||
|
|
||||||
|
class A {
|
||||||
|
class B {
|
||||||
|
<!CLASS_OBJECT_NOT_ALLOWED!>class object { }<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
class object {
|
||||||
|
class B {
|
||||||
|
class object {
|
||||||
|
class C {
|
||||||
|
class object { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
class C<T>() {
|
||||||
|
fun foo() : T <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>{}<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C<Int>) {}
|
||||||
|
fun bar<T>() : C<T> <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>{}<!>
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
val a : C<Int> = C();
|
||||||
|
val x : C<in String> = C()
|
||||||
|
val y : C<out String> = C()
|
||||||
|
val z : C<*> = C()
|
||||||
|
|
||||||
|
val ba : C<Int> = bar();
|
||||||
|
val bx : C<in String> = bar()
|
||||||
|
val by : C<out String> = bar()
|
||||||
|
val bz : C<*> = bar()
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
class Point() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class G<T>() {}
|
||||||
|
|
||||||
|
fun f<T>(expression : T) : G<out T> = G<T>
|
||||||
|
|
||||||
|
|
||||||
|
fun foo() : G<Point> {
|
||||||
|
val p = Point()
|
||||||
|
return <!TYPE_MISMATCH!>f<Point>(p)<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Out<out T>() {}
|
||||||
|
|
||||||
|
fun fout<T>(expression : T) : Out<out T> = Out<T>
|
||||||
|
|
||||||
|
fun fooout() : Out<Point> {
|
||||||
|
val p = Point();
|
||||||
|
return fout<Point>(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// KT-353 Generic type argument inference sometimes doesn't work
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
fun <T> gen() : T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(a: A) {
|
||||||
|
val g : fun() : Unit = {
|
||||||
|
a.gen() //it works: Unit is derived
|
||||||
|
}
|
||||||
|
|
||||||
|
val u: Unit = a.gen() //type mismatch, but Unit can be derived
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
a.gen() //it works: Unit is derived
|
||||||
|
}
|
||||||
|
|
||||||
|
val b : fun() : Unit = {
|
||||||
|
if (true) {
|
||||||
|
a.gen() //type mismatch, but Unit can be derived
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val f : fun() : Int = { () : Int =>
|
||||||
|
a.gen() //type mismatch, but Int can be derived
|
||||||
|
}
|
||||||
|
|
||||||
|
a.gen() //it works: Unit is derived
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// KT-399 Type argument inference not implemented for CALL_EXPRESSION
|
||||||
|
|
||||||
|
fun <T> getSameTypeChecker(obj: T) : Function1<Any,Boolean> {
|
||||||
|
return { (a : Any) => a is T }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
if(getSameTypeChecker<String>("lala")(10)) return "fail"
|
||||||
|
if(!getSameTypeChecker<String>("mama")("lala")) return "fail"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1,35 +1,14 @@
|
|||||||
namespace x
|
namespace x
|
||||||
|
|
||||||
class Outer(val name: String) {
|
class Outer() {
|
||||||
class Inner() {
|
|
||||||
val me = name
|
|
||||||
|
|
||||||
class object {
|
|
||||||
fun bar() = "bar"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
class StaticInner() {
|
class Inner() {
|
||||||
class object {
|
|
||||||
fun f() = "oo"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box (): String {
|
fun box (): String {
|
||||||
val inner = Outer("mama").Inner() //verify error
|
val inner = Outer.Inner()
|
||||||
if(inner.me != "mama")
|
|
||||||
return "fail"
|
|
||||||
|
|
||||||
val outer = Outer ("papa")
|
|
||||||
val inner2 = outer.Inner ()
|
|
||||||
if(inner2.me != "papa")
|
|
||||||
return "fail"
|
|
||||||
|
|
||||||
if(Outer.StaticInner.f() != "oo" )
|
|
||||||
return "fail"
|
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ public class JetTypeCheckerTest extends JetLiteFixture {
|
|||||||
for (String type : types) {
|
for (String type : types) {
|
||||||
subtypes.add(makeType(type));
|
subtypes.add(makeType(type));
|
||||||
}
|
}
|
||||||
JetType result = semanticServices.getTypeChecker().commonSupertype(subtypes);
|
JetType result = CommonSupertypes.commonSupertype(subtypes);
|
||||||
assertTrue(result + " != " + expected, result.equals(makeType(expected)));
|
assertTrue(result + " != " + expected, result.equals(makeType(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user