From d4ea1d42c8e5972ba6107cdc038b529c0fcfe46f Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 9 Nov 2011 16:56:05 +0300 Subject: [PATCH] CommonSupertypes factored out equalTypes() moved to TypeUtils Lower bounds (stub implementation) introduced to type parameters --- .../jetbrains/jet/codegen/JetTypeMapper.java | 2 +- .../jet/lang/JetSemanticServices.java | 2 +- .../descriptors/TypeParameterDescriptor.java | 42 +- .../lang/resolve/ClassDescriptorResolver.java | 6 +- .../jet/lang/resolve/OverridingUtil.java | 2 +- .../jet/lang/resolve/TypeResolver.java | 4 +- .../jet/lang/resolve/calls/CallResolver.java | 9 +- .../calls/OverloadingConflictResolver.java | 13 +- .../calls/autocasts/DataFlowValueFactory.java | 5 +- .../jet/lang/types/CommonSupertypes.java | 262 +++++++++++ .../jet/lang/types/JetTypeChecker.java | 351 +-------------- .../jet/lang/types/TypeSubstitutor.java | 2 +- .../jetbrains/jet/lang/types/TypeUtils.java | 5 +- .../BasicExpressionTypingVisitor.java | 2 +- .../ControlStructureTypingVisitor.java | 14 +- .../expressions/ExpressionTypingServices.java | 2 +- .../expressions/ExpressionTypingUtils.java | 3 +- .../PatternMatchingTypingVisitor.java | 2 +- .../types/inference/ConstraintSystem.java | 409 +---------------- .../inference/ConstraintSystemSolution.java | 18 + .../EqualityBasedConstraintSystem.java | 55 +++ .../SubtypingOnlyConstraintSystem.java | 415 ++++++++++++++++++ .../jet/types/JetTypeCheckerTest.java | 2 +- 23 files changed, 832 insertions(+), 795 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/CommonSupertypes.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemSolution.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 8a767ebdb45..6b32d78a506 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -248,7 +248,7 @@ public class JetTypeMapper { } if (descriptor instanceof TypeParameterDescriptor) { - return mapType(((TypeParameterDescriptor) descriptor).getBoundsAsType(), kind); + return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); } throw new UnsupportedOperationException("Unknown type " + jetType); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java index ec95ba62e98..5a73728db37 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -25,7 +25,7 @@ public class JetSemanticServices { private JetSemanticServices(JetStandardLibrary standardLibrary) { this.standardLibrary = standardLibrary; - this.typeChecker = new JetTypeChecker(standardLibrary); + this.typeChecker = JetTypeChecker.INSTANCE; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java index 695686b10b0..536d0e11600 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java @@ -43,7 +43,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement private final int index; private final Variance variance; private final Set upperBounds; - private JetType boundsAsType; + private JetType upperBoundsAsType; private final TypeConstructor typeConstructor; private JetType defaultType; private final Set classObjectUpperBounds = Sets.newLinkedHashSet(); @@ -85,10 +85,35 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement upperBounds.add(bound); // TODO : Duplicates? } + @NotNull public Set getUpperBounds() { 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 getLowerBounds() { + return Collections.singleton(JetStandardClasses.getNothingType()); + } + + @NotNull + public JetType getLowerBoundsAsType() { + return JetStandardClasses.getNothingType(); + } + + @NotNull @Override public TypeConstructor getTypeConstructor() { @@ -100,19 +125,6 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement 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 @Override @Deprecated // Use the static method TypeParameterDescriptor.substitute() @@ -137,7 +149,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement new LazyScopeAdapter(new LazyValue() { @Override protected JetScope compute() { - return getBoundsAsType().getMemberScope(); + return getUpperBoundsAsType().getMemberScope(); } })); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index c5ded6ed64e..f5af5a3b92a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -379,7 +379,7 @@ public class ClassDescriptorResolver { parameter.addUpperBound(JetStandardClasses.getDefaultBound()); } - if (JetStandardClasses.isNothing(parameter.getBoundsAsType())) { + if (JetStandardClasses.isNothing(parameter.getUpperBoundsAsType())) { PsiElement nameIdentifier = typeParameters.get(parameter.getIndex()).getNameIdentifier(); if (nameIdentifier != null) { // 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); JetType inType = propertyDescriptor.getInType(); 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.report(WRONG_SETTER_PARAMETER_TYPE.on(setter, typeReference, inType)); } @@ -709,7 +709,7 @@ public class ClassDescriptorResolver { JetTypeReference returnTypeReference = getter.getReturnTypeReference(); if (returnTypeReference != null) { 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.report(WRONG_GETTER_RETURN_TYPE.on(getter, returnTypeReference, propertyDescriptor.getReturnType())); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index bc91949cc9b..53b95a441f4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -127,7 +127,7 @@ public class OverridingUtil { TypeParameterDescriptor superTypeParameter = superTypeParameters.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); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 0ca6b450603..012932b4653 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -181,13 +181,13 @@ public class TypeResolver { private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor) { if (checkBounds) { - return typeParameterDescriptor.getBoundsAsType().getMemberScope(); + return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope(); } else { return new LazyScopeAdapter(new LazyValue() { @Override protected JetScope compute() { - return typeParameterDescriptor.getBoundsAsType().getMemberScope(); + return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope(); } }); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 3817321a726..1d95508cfe9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; 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.resolve.*; 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.OperatorConventions; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; +import org.jetbrains.jet.lang.types.inference.ConstraintSystemSolution; +import org.jetbrains.jet.lang.types.inference.SubtypingOnlyConstraintSystem; import org.jetbrains.jet.lexer.JetTokens; import java.util.*; @@ -413,7 +414,7 @@ public class CallResolver { if (!candidate.getTypeParameters().isEmpty()) { // Type argument inference - ConstraintSystem constraintSystem = new ConstraintSystem(); + ConstraintSystem constraintSystem = new SubtypingOnlyConstraintSystem(); for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) { constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO } @@ -451,7 +452,7 @@ public class CallResolver { constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType); } - ConstraintSystem.Solution solution = constraintSystem.solve(); + ConstraintSystemSolution solution = constraintSystem.solve(); // solutions.put(candidate, solution); if (solution.isSuccessful()) { D substitute = (D) candidate.substitute(solution.getSubstitutor()); @@ -884,7 +885,7 @@ public class CallResolver { for (int i = 0; i < valueParameters.size(); i++) { ValueParameterDescriptor valueParameter = valueParameters.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; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index 4758dfd54af..aa0f1c3ad95 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -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.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import java.util.List; import java.util.Set; @@ -123,13 +124,13 @@ public class OverloadingConflictResolver { JetType _byte = standardLibrary.getByteType(); JetType _short = standardLibrary.getShortType(); - if (semanticServices.getTypeChecker().equalTypes(specific, _double) && semanticServices.getTypeChecker().equalTypes(general, _float)) return true; - if (semanticServices.getTypeChecker().equalTypes(specific, _int)) { - if (semanticServices.getTypeChecker().equalTypes(general, _long)) return true; - if (semanticServices.getTypeChecker().equalTypes(general, _byte)) return true; - if (semanticServices.getTypeChecker().equalTypes(general, _short)) return true; + if (TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float)) return true; + if (TypeUtils.equalTypes(specific, _int)) { + if (TypeUtils.equalTypes(general, _long)) return true; + if (TypeUtils.equalTypes(general, _byte)) 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; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index 4b7a7b77b4e..6c634b3f81c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.resolve.calls.autocasts; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.descriptors.*; 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.types.JetStandardClasses; 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; @@ -29,7 +28,7 @@ public class DataFlowValueFactory { JetConstantExpression constantExpression = (JetConstantExpression) expression; 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 result = getIdForStableIdentifier(expression, bindingContext, false); return new DataFlowValue(result.first == null ? expression : result.first, type, result.second, getImmanentNullability(type)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CommonSupertypes.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CommonSupertypes.java new file mode 100644 index 00000000000..b656e962bd5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CommonSupertypes.java @@ -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 types) { + Collection typeSet = new HashSet(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 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> commonSupertypes = computeCommonRawSupertypes(typeSet); + while (commonSupertypes.size() > 1) { + Set merge = new HashSet(); + for (Set 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> 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> computeCommonRawSupertypes(@NotNull Collection types) { + assert !types.isEmpty(); + + final Map> constructorToAllInstances = new HashMap>(); + Set commonSuperclasses = null; + + List order = null; + for (JetType type : types) { + Set visited = new HashSet(); + + order = dfs(type, visited, new DfsNodeHandler>() { + public LinkedList list = new LinkedList(); + + @Override + public void beforeChildren(JetType current) { + TypeConstructor constructor = current.getConstructor(); + + Set instances = constructorToAllInstances.get(constructor); + if (instances == null) { + instances = new HashSet(); + constructorToAllInstances.put(constructor, instances); + } + instances.add(current); + } + + @Override + public void afterChildren(JetType current) { + list.addFirst(current.getConstructor()); + } + + @Override + public List result() { + return list; + } + }); + + if (commonSuperclasses == null) { + commonSuperclasses = visited; + } + else { + commonSuperclasses.retainAll(visited); + } + } + assert order != null; + + Set notSource = new HashSet(); + Map> result = new HashMap>(); + 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 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 parameters = constructor.getParameters(); + List newProjections = new ArrayList(); + for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + TypeParameterDescriptor parameterDescriptor = parameters.get(i); + Set typeProjections = new HashSet(); + 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.emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB); // TODO : scope + } + + @NotNull + private static TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set typeProjections) { + if (typeProjections.size() == 1) { + return typeProjections.iterator().next(); + } + + Set ins = new HashSet(); + Set outs = new HashSet(); + + 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 markerSet) { + markerSet.add(typeConstructor); + for (JetType type : typeConstructor.getSupertypes()) { + markAll(type.getConstructor(), markerSet); + } + } + + private static R dfs(@NotNull JetType current, @NotNull Set visited, @NotNull DfsNodeHandler handler) { + doDfs(current, visited, handler); + return handler.result(); + } + + private static void doDfs(@NotNull JetType current, @NotNull Set visited, @NotNull DfsNodeHandler handler) { + if (!visited.add(current.getConstructor())) { + return; + } + handler.beforeChildren(current); +// Map 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 { + + public void beforeChildren(JetType current) { + + } + + public void afterChildren(JetType current) { + + } + + public R result() { + return null; + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 3b8ea6843e6..38ee84c2f52 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import java.util.*; @@ -15,316 +14,14 @@ import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE; */ public class JetTypeChecker { - public static final JetTypeChecker INSTANCE = new JetTypeChecker(null); + public static final JetTypeChecker INSTANCE = new JetTypeChecker(); - private final Map> conversionMap = new HashMap>(); - private final JetStandardLibrary standardLibrary; - - public JetTypeChecker(JetStandardLibrary standardLibrary) { - this.standardLibrary = standardLibrary; + private JetTypeChecker() { } - @NotNull - private Map> getConversionMap() { -// if (conversionMap.size() == 0) { -// 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(Arrays.asList(constructors))); -// } -// - @NotNull - public JetType commonSupertype(@NotNull JetType... types) { - return commonSupertype(Arrays.asList(types)); - } - - @NotNull - public JetType commonSupertype(@NotNull Collection types) { - Collection typeSet = new HashSet(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 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> commonSupertypes = computeCommonRawSupertypes(typeSet); - while (commonSupertypes.size() > 1) { - Set merge = new HashSet(); - for (Set 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> 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 Map> computeCommonRawSupertypes(@NotNull Collection types) { - assert !types.isEmpty(); - - final Map> constructorToAllInstances = new HashMap>(); - Set commonSuperclasses = null; - - List order = null; - for (JetType type : types) { - Set visited = new HashSet(); - - order = dfs(type, visited, new DfsNodeHandler>() { - public LinkedList list = new LinkedList(); - - @Override - public void beforeChildren(JetType current) { - TypeConstructor constructor = current.getConstructor(); - - Set instances = constructorToAllInstances.get(constructor); - if (instances == null) { - instances = new HashSet(); - constructorToAllInstances.put(constructor, instances); - } - instances.add(current); - } - - @Override - public void afterChildren(JetType current) { - list.addFirst(current.getConstructor()); - } - - @Override - public List result() { - return list; - } - }); - - if (commonSuperclasses == null) { - commonSuperclasses = visited; - } - else { - commonSuperclasses.retainAll(visited); - } - } - assert order != null; - - Set notSource = new HashSet(); - Map> result = new HashMap>(); - 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 JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set 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 parameters = constructor.getParameters(); - List newProjections = new ArrayList(); - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { - TypeParameterDescriptor parameterDescriptor = parameters.get(i); - Set typeProjections = new HashSet(); - 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.emptyList(), constructor, nullable, newProjections, JetStandardClasses.STUB); // TODO : scope - } - - @NotNull - private TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set typeProjections) { - if (typeProjections.size() == 1) { - return typeProjections.iterator().next(); - } - - Set ins = new HashSet(); - Set outs = new HashSet(); - - 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(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 void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set markerSet) { - markerSet.add(typeConstructor); - for (JetType type : typeConstructor.getSupertypes()) { - markAll(type.getConstructor(), markerSet); - } - } - - private R dfs(@NotNull JetType current, @NotNull Set visited, @NotNull DfsNodeHandler handler) { - doDfs(current, visited, handler); - return handler.result(); - } - - private void doDfs(@NotNull JetType current, @NotNull Set visited, @NotNull DfsNodeHandler handler) { - if (!visited.add(current.getConstructor())) { - return; - } - handler.beforeChildren(current); -// Map 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 convertibleTo = getConversionMap().get(actualConstructor); -// if (convertibleTo != null) { -// return convertibleTo.contains(constructor); -// } -// } - return false; + public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { +// return new TypeCheckingProcedure().run(subtype, supertype); + return new ExplicitInOutTypeCheckingProcedure().run(subtype, supertype); } // This method returns the supertype of the first parameter that has the same constructor @@ -344,13 +41,14 @@ public class JetTypeChecker { return null; } - public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { -// return new TypeCheckingProcedure().run(subtype, supertype); - return new ExplicitInOutTypeCheckingProcedure().run(subtype, supertype); + private static JetType getOutType(TypeParameterDescriptor parameter, TypeProjection argument) { + 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) { - return isSubtypeOf(a, b) && isSubtypeOf(b, a); + private static JetType getInType(TypeParameterDescriptor parameter, TypeProjection argument) { + boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE; + return isOutProjected ? JetStandardClasses.getNothingType() : argument.getType(); } private static class ExplicitInOutTypeCheckingProcedure { @@ -386,13 +84,12 @@ public class JetTypeChecker { List parameters = constructor.getParameters(); for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection subArgument = subArguments.get(i); - JetType subIn = getInType(parameter, subArgument); JetType subOut = getOutType(parameter, subArgument); TypeProjection superArgument = superArguments.get(i); - JetType superIn = getInType(parameter, superArgument); JetType superOut = getOutType(parameter, superArgument); @@ -402,16 +99,6 @@ public class JetTypeChecker { } return true; } - - private JetType getOutType(TypeParameterDescriptor parameter, TypeProjection subArgument) { - boolean isOutProjected = subArgument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE; - return isOutProjected ? parameter.getBoundsAsType() : subArgument.getType(); - } - - private JetType getInType(TypeParameterDescriptor parameter, TypeProjection subArgument) { - boolean isOutProjected = subArgument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE; - return isOutProjected ? JetStandardClasses.getNothingType() : subArgument.getType(); - } } public static abstract class AbstractTypeCheckingProcedure { @@ -590,19 +277,5 @@ public class JetTypeChecker { } } - private static class DfsNodeHandler { - - public void beforeChildren(JetType current) { - - } - - public void afterChildren(JetType current) { - - } - - public R result() { - return null; - } - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index d6a5094cacc..0093d9536df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -216,7 +216,7 @@ public class TypeSubstitutor { case OUT_VARIANCE: if (projectionKindValue == Variance.IN_VARIANCE) { effectiveProjectionKindValue = Variance.INVARIANT; - effectiveTypeValue = correspondingTypeParameter.getBoundsAsType(); + effectiveTypeValue = correspondingTypeParameter.getUpperBoundsAsType(); } else { effectiveTypeValue = typeValue; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 130e9b08eb1..cb6360ab21d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -352,7 +352,7 @@ public class TypeUtils { @NotNull 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 result) { @@ -424,4 +424,7 @@ public class TypeUtils { return false; } + public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { + return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index f7d692635d4..1939b0192d0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -712,7 +712,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } if (rightType != null) { 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()); } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index c2ca77a049e..4bf50a63007 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -14,15 +14,9 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope; 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.TransientReceiver; -import org.jetbrains.jet.lang.types.ErrorUtils; -import org.jetbrains.jet.lang.types.JetStandardClasses; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.lang.types.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; @@ -98,7 +92,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { result = thenType; } else { - result = context.semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType)); + result = CommonSupertypes.commonSupertype(Arrays.asList(thenType, elseType)); } boolean jumpInThen = thenType != null && JetStandardClasses.isNothing(thenType); @@ -361,7 +355,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { return null; } else { - return context.semanticServices.getTypeChecker().commonSupertype(types); + return CommonSupertypes.commonSupertype(types); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index f47a527d75b..93a98b4ddae 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -86,7 +86,7 @@ public class ExpressionTypingServices { Collection types = typeMap.values(); return types.isEmpty() ? JetStandardClasses.getNothingType() - : semanticServices.getTypeChecker().commonSupertype(types); + : CommonSupertypes.commonSupertype(types); } public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 129f63bbf09..f9cdac37fcb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -13,7 +13,6 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContextUtils; 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.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.types.JetStandardClasses; @@ -47,7 +46,7 @@ public class ExpressionTypingUtils { } 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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index 970198fe48d..6b8b8d0630c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -100,7 +100,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { } if (!expressionTypes.isEmpty()) { - return context.semanticServices.getTypeChecker().commonSupertype(expressionTypes); + return CommonSupertypes.commonSupertype(expressionTypes); } else if (expression.getEntries().isEmpty()) { // context.trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java index 175f6647891..20b47986c0b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java @@ -1,413 +1,18 @@ 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; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.Variance; /** * @author abreslav */ -public class ConstraintSystem { +public interface ConstraintSystem { + void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance); -// private static final Supplier> SET_SUPPLIER = new Supplier>() { -// @Override -// public Set 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 upperBounds = Sets.newHashSet(); - private final Set lowerBounds = Sets.newHashSet(); - - @NotNull - public Set getUpperBounds() { - return upperBounds; - } - - @NotNull - public Set 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 lowerBounds = getLowerBounds(); - if (!lowerBounds.isEmpty()) { - Set 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 upperBounds = getUpperBounds(); - Set types = getTypes(upperBounds); - JetType intersect = TypeUtils.intersect(typeChecker, types); - - value = new KnownType(intersect); - } - } - } - finally { - beingComputed = false; - } - } - - return value; - } - - private Set getTypes(Set lowerBounds) { - Set 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 knownTypes = Maps.newHashMap(); - private final Map unknownTypes = Maps.newHashMap(); - private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper); @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; - } - - 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 <: List - for (Map.Entry 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 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 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 visited) { - if (!visited.add(current)) { - return; - } - - for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) { - transitiveClosure(upperBound, visited); - Set 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 { - - 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); - } - -} \ No newline at end of file + ConstraintSystemSolution solve(); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemSolution.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemSolution.java new file mode 100644 index 00000000000..9a78a00adda --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemSolution.java @@ -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); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java new file mode 100644 index 00000000000..3a4b25cf0a4 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java @@ -0,0 +1,55 @@ +package org.jetbrains.jet.lang.types.inference; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.Variance; + +import java.util.List; +import java.util.Map; + +/** + * @author abreslav + */ +public class EqualityBasedConstraintSystem implements ConstraintSystem { + + private abstract class Constraint { + private final TypeParameterDescriptor typeParameterDescriptor; + + protected Constraint(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + this.typeParameterDescriptor = typeParameterDescriptor; + } + + @NotNull + public TypeParameterDescriptor getTypeParameterDescriptor() { + return typeParameterDescriptor; + } + } + + private class Unknown { + // T -> variance of its position + private final Map typeParameters = Maps.newHashMap(); + private final List constraints = Lists.newArrayList(); + + } + + private final Map unknowns = Maps.newHashMap(); + + @Override + public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { + throw new UnsupportedOperationException(); // TODO + } + + @Override + public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) { + throw new UnsupportedOperationException(); // TODO + } + + @NotNull + @Override + public ConstraintSystemSolution solve() { + throw new UnsupportedOperationException(); // TODO + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java new file mode 100644 index 00000000000..5ebe51309f8 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java @@ -0,0 +1,415 @@ +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 SubtypingOnlyConstraintSystem 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 upperBounds = Sets.newHashSet(); + private final Set lowerBounds = Sets.newHashSet(); + + @NotNull + public Set getUpperBounds() { + return upperBounds; + } + + @NotNull + public Set 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 lowerBounds = getLowerBounds(); + if (!lowerBounds.isEmpty()) { + Set 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 upperBounds = getUpperBounds(); + Set types = getTypes(upperBounds); + JetType intersect = TypeUtils.intersect(typeChecker, types); + + value = new KnownType(intersect); + } + } + } + finally { + beingComputed = false; + } + } + + return value; + } + + private Set getTypes(Set lowerBounds) { + Set 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 knownTypes = Maps.newHashMap(); + private final Map unknownTypes = Maps.newHashMap(); + private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + + @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; + } + + @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 <: List + for (Map.Entry 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 SubtypingConstraintExpander().run(jetType, knownBoundType.getType()); + if (!ok) { + return new Solution(true); + } + } + } + + // Lower bounds? + + } + + // Fill in upper bounds from type parameter bounds + for (Map.Entry 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 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 visited) { + if (!visited.add(current)) { + return; + } + + for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) { + transitiveClosure(upperBound, visited); + Set 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 class EqualityConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure { +// +// } + + private class SubtypingConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure { + + 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); + } + +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index aa914ef6bb3..0cd1450159b 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -471,7 +471,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { for (String type : types) { subtypes.add(makeType(type)); } - JetType result = semanticServices.getTypeChecker().commonSupertype(subtypes); + JetType result = CommonSupertypes.commonSupertype(subtypes); assertTrue(result + " != " + expected, result.equals(makeType(expected))); }