diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java deleted file mode 100644 index 66e9634f034..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve.calls.inference; - -import com.google.common.collect.Lists; -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.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.checker.JetTypeChecker; -import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; - -import java.util.*; - -/** - * @author svtk - */ -public class ConstraintSystemImpl implements ConstraintSystem { - - public static ConstraintType varianceToConstraintType(Variance variance) { - if (variance == Variance.INVARIANT) { - return ConstraintType.EQUAL; - } - if (variance == Variance.OUT_VARIANCE) { - return ConstraintType.SUB_TYPE; - } - return ConstraintType.SUPER_TYPE; - } - - private final Map typeParameterBounds = Maps.newLinkedHashMap(); - private final TypeSubstitutor typeSubstitutor; - private final Collection errorConstraintPositions; - private boolean typeConstructorMismatch; - - public ConstraintSystemImpl() { - this(false, Lists.newArrayList()); - } - - public ConstraintSystemImpl(boolean typeConstructorMismatch, Collection errorConstraintPositions) { - this.typeConstructorMismatch = typeConstructorMismatch; - this.errorConstraintPositions = errorConstraintPositions; - this.typeSubstitutor = TypeSubstitutor.create(new TypeSubstitution() { - @Override - public TypeProjection get(TypeConstructor key) { - DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor(); - if (declarationDescriptor instanceof TypeParameterDescriptor) { - TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor; - - JetType value = getValue(descriptor); - if (value != null && !dependsOnTypeParameter(value, DONT_CARE.getConstructor())) { - return new TypeProjection(value); - } - return new TypeProjection(DONT_CARE); - } - return null; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public String toString() { - return typeParameterBounds.toString(); - } - }); - } - - @Override - public boolean hasTypeConstructorMismatch() { - return typeConstructorMismatch; - } - - @NotNull - @Override - public Collection getErrorConstraintPositions() { - return errorConstraintPositions; - } - - @Override - public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { - typeParameterBounds.put(typeParameterDescriptor, new TypeBounds(positionVariance)); - } - - public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull TypeBounds typeBounds) { - typeParameterBounds.put(typeParameterDescriptor, typeBounds); - } - - @Override - public void addSubtypingConstraint(@NotNull JetType exactType, @NotNull JetType expectedType, @NotNull ConstraintPosition constraintPosition) { - addConstraint(ConstraintType.SUB_TYPE, exactType, expectedType, constraintPosition); - } - - private static boolean dependsOnTypeParameter(JetType type, TypeConstructor typeParameter) { - if (type.getConstructor() == typeParameter) return true; - for (TypeProjection typeProjection : type.getArguments()) { - if (dependsOnTypeParameter(typeProjection.getType(), typeParameter)) { - return true; - } - } - return false; - } - - @Override - public void addConstraint(@NotNull ConstraintType constraintType, @NotNull JetType exactType, @NotNull JetType expectedType, - @NotNull ConstraintPosition constraintPosition) { - if (exactType == DONT_CARE || expectedType == DONT_CARE || exactType == TypeUtils.NO_EXPECTED_TYPE - || expectedType == TypeUtils.NO_EXPECTED_TYPE) return; - - DeclarationDescriptor expectedTypeDescriptor = expectedType.getConstructor().getDeclarationDescriptor(); - DeclarationDescriptor exactTypeDescriptor = exactType.getConstructor().getDeclarationDescriptor(); - - if (expectedTypeDescriptor instanceof TypeParameterDescriptor) { - if (dependsOnTypeParameter(exactType, DONT_CARE.getConstructor())) return; - if (expectedType.isNullable()) { - exactType = TypeUtils.makeNotNullable(exactType); - } - TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) expectedTypeDescriptor; - if (constraintType == ConstraintType.SUB_TYPE) { - typeParameterBounds.get(typeParameter).addLowerBound(exactType); - } - else if (constraintType == ConstraintType.SUPER_TYPE) { - typeParameterBounds.get(typeParameter).addUpperBound(exactType); - } - else { - typeParameterBounds.get(typeParameter).setExactValue(exactType); - } - return; - } - - if (exactTypeDescriptor instanceof ClassDescriptor && expectedTypeDescriptor instanceof ClassDescriptor) { - if (constraintType != ConstraintType.SUPER_TYPE) { - JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(exactType, expectedType); - if (correspondingSupertype != null) { - exactType = correspondingSupertype; - } - } - else { - JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(expectedType, exactType); - if (correspondingSupertype != null) { - expectedType = correspondingSupertype; - } - } - - if (exactType.getConstructor().getParameters().size() != expectedType.getConstructor().getParameters().size()) { - errorConstraintPositions.add(constraintPosition); - typeConstructorMismatch = true; - return; - } - - ClassDescriptor subClass = (ClassDescriptor) exactType.getConstructor().getDeclarationDescriptor(); - ClassDescriptor superClass = (ClassDescriptor) expectedType.getConstructor().getDeclarationDescriptor(); - if (DescriptorUtils.isSubclass(subClass, superClass)) { - List subArguments = exactType.getArguments(); - List superArguments = expectedType.getArguments(); - List superParameters = expectedType.getConstructor().getParameters(); - for (int i = 0; i < superArguments.size(); i++) { - addConstraint(varianceToConstraintType(superParameters.get(i).getVariance()), subArguments.get(i).getType(), superArguments.get(i).getType(), - constraintPosition); - } - return; - } - } - typeConstructorMismatch = true; - errorConstraintPositions.add(constraintPosition); - } - - private boolean checkConstraints(TypeParameterDescriptor typeParameterDescriptor) { - //todo refactor - TypeBounds typeBounds = typeParameterBounds.get(typeParameterDescriptor); - if (typeBounds == null || typeBounds.isEmpty()) return true; - JetType exactType = null; - if (typeBounds.getExactValues().size() > 1) { - return false; - } - if (typeBounds.getExactValues().size() == 1) { - exactType = typeBounds.getExactValues().iterator().next(); - } - JetType superTypeOfLowerBounds = null; - if (exactType == null && !typeBounds.getLowerBounds().isEmpty()) { - superTypeOfLowerBounds = CommonSupertypes.commonSupertype(typeBounds.getLowerBounds()); - } - JetType subTypeOfUpperBounds = null; - if (exactType == null && superTypeOfLowerBounds == null && !typeBounds.getUpperBounds().isEmpty()) { - subTypeOfUpperBounds = typeBounds.getUpperBounds().iterator().next(); //todo - } - JetType type = exactType != null ? exactType : superTypeOfLowerBounds != null ? superTypeOfLowerBounds : subTypeOfUpperBounds; - if (type == null) { - return false; - } - - if (subTypeOfUpperBounds != null) return true; - for (JetType upperType : typeBounds.getUpperBounds()) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(type, upperType)) { - return false; - } - } - if (superTypeOfLowerBounds != null) return true; - for (JetType lowerType : typeBounds.getLowerBounds()) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(lowerType, type)) { - return false; - } - } - return true; - } - - @Nullable - public JetType getValue(TypeParameterDescriptor typeParameter) { - //todo all checks - TypeBounds typeBounds = typeParameterBounds.get(typeParameter); - //todo variance dependance - if (typeBounds == null) { - //todo assert typeBounds != null; - return null; - } - if (typeBounds.isEmpty()) return null; - Set exactValues = typeBounds.getExactValues(); - if (!exactValues.isEmpty()) { - return exactValues.iterator().next(); - } - if (!typeBounds.getLowerBounds().isEmpty()) { - return CommonSupertypes.commonSupertype(typeBounds.getLowerBounds()); - } - if (!typeBounds.getUpperBounds().isEmpty()) { - return typeBounds.getUpperBounds().iterator().next(); - } - return null; - } - - @NotNull - public JetType getSafeValue(TypeParameterDescriptor typeParameter) { - JetType type = getValue(typeParameter); - if (type != null) { - return type; - } - //todo may be error type - return typeParameter.getUpperBoundsAsType(); - } - - @NotNull - public Collection getValues(TypeParameterDescriptor typeParameter) { - TypeBounds typeBounds = typeParameterBounds.get(typeParameter); - Set values = Sets.newLinkedHashSet(); - if (typeBounds != null && !typeBounds.isEmpty()) { - values.addAll(typeBounds.getExactValues()); - if (!typeBounds.getLowerBounds().isEmpty()) { - JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertype(typeBounds.getLowerBounds()); - if (values.isEmpty()) { - values.add(superTypeOfLowerBounds); - } - for (JetType value : values) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(superTypeOfLowerBounds, value)) { - values.add(superTypeOfLowerBounds); - break; - } - } - } - if (!typeBounds.getUpperBounds().isEmpty()) { - //todo subTypeOfUpperBounds - JetType subTypeOfUpperBounds = typeBounds.getUpperBounds().iterator().next(); //todo - if (values.isEmpty()) { - values.add(subTypeOfUpperBounds); - } - for (JetType value : values) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(value, subTypeOfUpperBounds)) { - values.add(subTypeOfUpperBounds); - break; - } - } - } - } - return values; - } - - @Override - @Nullable - public TypeParameterDescriptor getFirstConflictingParameter() { - for (TypeParameterDescriptor typeParameter : typeParameterBounds.keySet()) { - Collection values = getValues(typeParameter); - if (!values.isEmpty()) { - return typeParameter; - } - } - return null; - } - - @NotNull - @Override - public Collection getSubstitutors() { - TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(); - if (firstConflictingParameter == null) return Collections.emptyList(); - - Collection conflictingTypes = getValues(firstConflictingParameter); - - ArrayList> substitutionContexts = Lists.newArrayList(); - for (JetType type : conflictingTypes) { - Map context = Maps.newLinkedHashMap(); - context.put(firstConflictingParameter.getTypeConstructor(), new TypeProjection(type)); - substitutionContexts.add(context); - } - - for (TypeParameterDescriptor typeParameter : typeParameterBounds.keySet()) { - if (typeParameter == firstConflictingParameter) continue; - - JetType safeType = getSafeValue(typeParameter); - for (Map context : substitutionContexts) { - TypeProjection typeProjection = new TypeProjection(safeType); - context.put(typeParameter.getTypeConstructor(), typeProjection); - } - } - Collection typeSubstitutors = Lists.newArrayList(); - for (Map context : substitutionContexts) { - typeSubstitutors.add(TypeSubstitutor.create(context)); - } - return typeSubstitutors; - } - - @Override - @NotNull - public TypeBounds getTypeBounds(TypeParameterDescriptor typeParameterDescriptor) { - return typeParameterBounds.get(typeParameterDescriptor); - } - - @Override - public Map getTypeBoundsMap() { - return typeParameterBounds; - } - - @Override - public boolean isSuccessful() { - return !hasTypeConstructorMismatch() && !hasUnknownParameters() && !hasConflictingParameters(); - } - - @Override - public boolean hasContradiction() { - return hasTypeConstructorMismatch() || hasConflictingParameters(); - } - - @Override - public boolean hasConflictingParameters() { - for (TypeParameterDescriptor typeParameter : typeParameterBounds.keySet()) { - if (getValues(typeParameter).size() > 1) return true; - //if (!checkConstraints(typeParameter)) return true; - } - return false; - } - - @Override - public boolean hasUnknownParameters() { - for (TypeBounds bounds : typeParameterBounds.values()) { - if (bounds.isEmpty()) { - return true; - } - } - return false; - } - - @NotNull - @Override - public TypeSubstitutor getSubstitutor() { - return typeSubstitutor; - } - - public boolean upperBoundsAreSatisfied() { - for (TypeParameterDescriptor typeParameter : typeParameterBounds.keySet()) { - JetType type = getValue(typeParameter); - JetType upperBound = typeParameter.getUpperBoundsAsType(); - JetType substitute = getSubstitutor().substitute(upperBound, Variance.INVARIANT); - - if (type != null) { - if (substitute == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitute)) { - return false; - } - } - } - return true; - } - - @Override - public boolean checkUpperBound(@NotNull TypeParameterDescriptor typeParameter) { - assert typeParameterBounds.containsKey(typeParameter); - JetType type = getValue(typeParameter); - JetType upperBound = typeParameter.getUpperBoundsAsType(); - JetType substitute = getSubstitutor().substitute(upperBound, Variance.INVARIANT); - - if (type != null) { - if (substitute == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitute)) { - return false; - } - } - return true; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsBuilderImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsBuilderImpl.java new file mode 100644 index 00000000000..fbca107cbbf --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsBuilderImpl.java @@ -0,0 +1,271 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls.inference; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; + +import java.util.*; + +/** + * @author svtk + */ +public class ConstraintsBuilderImpl implements ConstraintsBuilder { + + public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE"); + + enum ConstraintType { + SUB_TYPE, SUPER_TYPE, EQUAL + } + + public static ConstraintType varianceToConstraintType(Variance variance) { + if (variance == Variance.INVARIANT) { + return ConstraintType.EQUAL; + } + if (variance == Variance.OUT_VARIANCE) { + return ConstraintType.SUB_TYPE; + } + return ConstraintType.SUPER_TYPE; + } + + private final Map typeParameterConstraints = Maps.newLinkedHashMap(); + private final TypeSubstitutor typeSubstitutor; + private final Collection errorConstraintPositions; + private boolean typeConstructorMismatch; + + public ConstraintsBuilderImpl() { + this(false, Lists.newArrayList()); + } + + public ConstraintsBuilderImpl(boolean typeConstructorMismatch, Collection errorConstraintPositions) { + this.typeConstructorMismatch = typeConstructorMismatch; + this.errorConstraintPositions = errorConstraintPositions; + this.typeSubstitutor = TypeSubstitutor.create(new TypeSubstitution() { + @Override + public TypeProjection get(TypeConstructor key) { + DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor(); + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor; + + JetType value = getValue(descriptor); + if (value != null && !TypeUtils.dependsOnTypeParameterConstructors(value, Collections.singleton( + DONT_CARE.getConstructor()))) { + return new TypeProjection(value); + } + return new TypeProjection(DONT_CARE); + } + return null; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public String toString() { + return typeParameterConstraints.toString(); + } + }); + } + + @Override + public boolean hasTypeConstructorMismatch() { + return typeConstructorMismatch; + } + + @NotNull + @Override + public Collection getTypeConstructorMismatchConstraintPositions() { + return errorConstraintPositions; + } + + @Override + public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { + typeParameterConstraints.put(typeParameterDescriptor, new TypeConstraintsImpl(positionVariance)); + } + + //todo remove + public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull TypeConstraints typeConstraints) { + typeParameterConstraints.put(typeParameterDescriptor, (TypeConstraintsImpl) typeConstraints); + } + + @Override + public void addSubtypingConstraint(@NotNull JetType subjectType, @NotNull JetType constrainingType, @NotNull ConstraintPosition constraintPosition) { + addConstraint(ConstraintType.SUB_TYPE, subjectType, constrainingType, constraintPosition); + } + + @Override + public void addSupertypeConstraint(@NotNull JetType subjectType, @NotNull JetType constrainingType, @NotNull ConstraintPosition constraintPosition) { + addConstraint(ConstraintType.SUPER_TYPE, subjectType, constrainingType, constraintPosition); + } + + public void addConstraint(@NotNull ConstraintType constraintType, @NotNull JetType exactType, @NotNull JetType expectedType, + @NotNull ConstraintPosition constraintPosition) { + if (exactType == DONT_CARE || expectedType == DONT_CARE || exactType == TypeUtils.NO_EXPECTED_TYPE + || expectedType == TypeUtils.NO_EXPECTED_TYPE) { + return; + } + + DeclarationDescriptor expectedTypeDescriptor = expectedType.getConstructor().getDeclarationDescriptor(); + DeclarationDescriptor exactTypeDescriptor = exactType.getConstructor().getDeclarationDescriptor(); + + if (expectedTypeDescriptor instanceof TypeParameterDescriptor) { + if (TypeUtils.dependsOnTypeParameterConstructors(exactType, Collections.singleton(DONT_CARE.getConstructor()))) return; + if (expectedType.isNullable()) { + exactType = TypeUtils.makeNotNullable(exactType); + } + TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) expectedTypeDescriptor; + if (constraintType == ConstraintType.SUB_TYPE) { + typeParameterConstraints.get(typeParameter).addLowerConstraint(exactType); + } + else if (constraintType == ConstraintType.SUPER_TYPE) { + typeParameterConstraints.get(typeParameter).addUpperConstraint(exactType); + } + else { + typeParameterConstraints.get(typeParameter).addEqualConstraint(exactType); + } + return; + } + + if (exactTypeDescriptor instanceof ClassDescriptor && expectedTypeDescriptor instanceof ClassDescriptor) { + if (constraintType != ConstraintType.SUPER_TYPE) { + JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(exactType, expectedType); + if (correspondingSupertype != null) { + exactType = correspondingSupertype; + } + } + else { + JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(expectedType, exactType); + if (correspondingSupertype != null) { + expectedType = correspondingSupertype; + } + } + + if (exactType.getConstructor().getParameters().size() != expectedType.getConstructor().getParameters().size()) { + errorConstraintPositions.add(constraintPosition); + typeConstructorMismatch = true; + return; + } + + ClassDescriptor subClass = (ClassDescriptor) exactType.getConstructor().getDeclarationDescriptor(); + ClassDescriptor superClass = (ClassDescriptor) expectedType.getConstructor().getDeclarationDescriptor(); + if (DescriptorUtils.isSubclass(subClass, superClass)) { + List subArguments = exactType.getArguments(); + List superArguments = expectedType.getArguments(); + List superParameters = expectedType.getConstructor().getParameters(); + for (int i = 0; i < superArguments.size(); i++) { + addConstraint(varianceToConstraintType(superParameters.get(i).getVariance()), subArguments.get(i).getType(), superArguments.get(i).getType(), + constraintPosition); + } + return; + } + } + typeConstructorMismatch = true; + errorConstraintPositions.add(constraintPosition); + } + + @Nullable + public JetType getValue(@NotNull TypeParameterDescriptor typeParameter) { + //todo all checks + TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter); + //todo variance dependance + if (typeConstraints == null) { + //todo assert typeConstraints != null; + return null; + } + if (typeConstraints.getLowerConstraint() != null) { + return typeConstraints.getLowerConstraint(); + } + + if (typeConstraints.getUpperConstraint() != null) { + return typeConstraints.getUpperConstraint(); + } + return null; + } + + @NotNull + @Override + public Set getTypeParameters() { + return typeParameterConstraints.keySet(); + } + + @Override + @Nullable + public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + return typeParameterConstraints.get(typeParameterDescriptor); + } + + @Override + public boolean isSuccessful() { + return !hasTypeConstructorMismatch() && !hasUnknownParameters() && !hasConflictingParameters(); + } + + @Override + public boolean hasContradiction() { + return hasTypeConstructorMismatch() || hasConflictingParameters(); + } + + @Override + public boolean hasConflictingParameters() { + for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) { + TypeConstraints typeConstraints = getTypeConstraints(typeParameter); + if (typeConstraints != null && !typeConstraints.isSuccessful()) return true; + } + return false; + } + + @Override + public boolean hasUnknownParameters() { + for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) { + if (constraints.isEmpty()) { + return true; + } + } + return false; + } + + @NotNull + @Override + public TypeSubstitutor getSubstitutor() { + return typeSubstitutor; + } + + public boolean upperBoundsAreSatisfied() { + for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) { + JetType type = getValue(typeParameter); + JetType upperBound = typeParameter.getUpperBoundsAsType(); + JetType substitute = getSubstitutor().substitute(upperBound, Variance.INVARIANT); + + if (type != null) { + if (substitute == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitute)) { + return false; + } + } + } + return true; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java new file mode 100644 index 00000000000..c4ba3893aad --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls.inference; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * @author svtk + */ +public class ConstraintsUtil { + + @Nullable + public static TypeParameterDescriptor getFirstConflictingParameter(@NotNull ConstraintsBuilder constraintsBuilder) { + for (TypeParameterDescriptor typeParameter : constraintsBuilder.getTypeParameters()) { + TypeConstraints constraints = constraintsBuilder.getTypeConstraints(typeParameter); + if (!constraints.getConflicts().isEmpty()) { + return typeParameter; + } + } + return null; + } + + @NotNull + public static Collection getSubstitutorsForConflictingParameters(@NotNull ConstraintsBuilder constraintsBuilder) { + TypeParameterDescriptor firstConflictingParameter = getFirstConflictingParameter(constraintsBuilder); + if (firstConflictingParameter == null) return Collections.emptyList(); + + Collection conflictingTypes = constraintsBuilder.getTypeConstraints(firstConflictingParameter).getConflicts(); + + ArrayList> substitutionContexts = Lists.newArrayList(); + for (JetType type : conflictingTypes) { + Map context = Maps.newLinkedHashMap(); + context.put(firstConflictingParameter.getTypeConstructor(), new TypeProjection(type)); + substitutionContexts.add(context); + } + + for (TypeParameterDescriptor typeParameter : constraintsBuilder.getTypeParameters()) { + if (typeParameter == firstConflictingParameter) continue; + + JetType safeType = getSafeValue(constraintsBuilder, typeParameter); + for (Map context : substitutionContexts) { + TypeProjection typeProjection = new TypeProjection(safeType); + context.put(typeParameter.getTypeConstructor(), typeProjection); + } + } + Collection typeSubstitutors = Lists.newArrayList(); + for (Map context : substitutionContexts) { + typeSubstitutors.add(TypeSubstitutor.create(context)); + } + return typeSubstitutors; + } + + @NotNull + public static JetType getSafeValue(@NotNull ConstraintsBuilder constraintsBuilder, @NotNull TypeParameterDescriptor typeParameter) { + JetType type = constraintsBuilder.getValue(typeParameter); + if (type != null) { + return type; + } + //todo may be error type + return typeParameter.getUpperBoundsAsType(); + } + + public static boolean checkUpperBoundIsSatisfied(@NotNull ConstraintsBuilder constraintsBuilder, + @NotNull TypeParameterDescriptor typeParameter) { + assert constraintsBuilder.getTypeConstraints(typeParameter) != null; + JetType type = constraintsBuilder.getValue(typeParameter); + JetType upperBound = typeParameter.getUpperBoundsAsType(); + JetType substitute = constraintsBuilder.getSubstitutor().substitute(upperBound, Variance.INVARIANT); + + if (type != null) { + if (substitute == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitute)) { + return false; + } + } + return true; + } +}