001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve.calls.inference;
018
019 import kotlin.Function1;
020 import kotlin.KotlinPackage;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
024 import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
025 import org.jetbrains.jet.lang.types.*;
026 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
027 import org.jetbrains.jet.utils.UtilsPackage;
028
029 import java.util.*;
030
031 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND;
032
033 public class TypeBoundsImpl implements TypeBounds {
034 private final TypeParameterDescriptor typeVariable;
035 private final Variance varianceOfPosition;
036 private final Set<Bound> bounds = new LinkedHashSet<Bound>();
037
038 private Collection<JetType> resultValues;
039
040 public TypeBoundsImpl(
041 @NotNull TypeParameterDescriptor typeVariable,
042 @NotNull Variance varianceOfPosition
043 ) {
044 this.typeVariable = typeVariable;
045 this.varianceOfPosition = varianceOfPosition;
046 }
047
048 @NotNull
049 @Override
050 public Variance getVarianceOfPosition() {
051 return varianceOfPosition;
052 }
053
054 public void addBound(@NotNull BoundKind kind, @NotNull JetType type, @NotNull ConstraintPosition position) {
055 resultValues = null;
056 bounds.add(new Bound(type, kind, position));
057 }
058
059 @Override
060 public boolean isEmpty() {
061 return getValues().isEmpty();
062 }
063
064 @NotNull
065 @Override
066 public TypeParameterDescriptor getTypeVariable() {
067 return typeVariable;
068 }
069
070 @Override
071 @NotNull
072 public Collection<Bound> getBounds() {
073 return bounds;
074 }
075
076 @NotNull
077 private static Set<JetType> filterBounds(
078 @NotNull Collection<Bound> bounds,
079 @NotNull BoundKind kind
080 ) {
081 return filterBounds(bounds, kind, null);
082 }
083
084 @NotNull
085 private static Set<JetType> filterBounds(
086 @NotNull Collection<Bound> bounds,
087 @NotNull BoundKind kind,
088 @Nullable Collection<JetType> errorValues
089 ) {
090 Set<JetType> result = new LinkedHashSet<JetType>();
091 for (Bound bound : bounds) {
092 if (bound.kind == kind) {
093 if (!ErrorUtils.containsErrorType(bound.type)) {
094 result.add(bound.type);
095 }
096 else if (errorValues != null) {
097 errorValues.add(bound.type);
098 }
099 }
100 }
101 return result;
102 }
103
104 /*package*/ TypeBoundsImpl copy() {
105 TypeBoundsImpl typeBounds = new TypeBoundsImpl(typeVariable, varianceOfPosition);
106 typeBounds.bounds.addAll(bounds);
107 typeBounds.resultValues = resultValues;
108 return typeBounds;
109 }
110
111 @NotNull
112 public TypeBoundsImpl filter(@NotNull final Function1<ConstraintPosition, Boolean> condition) {
113 TypeBoundsImpl result = new TypeBoundsImpl(typeVariable, varianceOfPosition);
114 result.bounds.addAll(KotlinPackage.filter(bounds, new Function1<Bound, Boolean>() {
115 @Override
116 public Boolean invoke(Bound bound) {
117 return condition.invoke(bound.position);
118 }
119 }));
120 return result;
121 }
122
123 @Nullable
124 @Override
125 public JetType getValue() {
126 Collection<JetType> values = getValues();
127 if (values.size() == 1) {
128 return values.iterator().next();
129 }
130 return null;
131 }
132
133 @NotNull
134 @Override
135 public Collection<JetType> getValues() {
136 if (resultValues == null) {
137 resultValues = computeValues();
138 }
139 return resultValues;
140 }
141
142 @NotNull
143 private Collection<JetType> computeValues() {
144 Set<JetType> values = new LinkedHashSet<JetType>();
145 if (bounds.isEmpty()) {
146 return Collections.emptyList();
147 }
148 boolean hasStrongBound = KotlinPackage.any(bounds, new Function1<Bound, Boolean>() {
149 @Override
150 public Boolean invoke(Bound bound) {
151 return bound.position.isStrong();
152 }
153 });
154 if (!hasStrongBound) {
155 return Collections.emptyList();
156 }
157
158 Set<JetType> exactBounds = filterBounds(bounds, BoundKind.EXACT_BOUND, values);
159 JetType bestFit = TypesPackage.singleBestRepresentative(exactBounds);
160 if (bestFit != null) {
161 if (tryPossibleAnswer(bestFit)) {
162 return Collections.singleton(bestFit);
163 }
164 }
165 values.addAll(exactBounds);
166
167 Collection<JetType> numberLowerBounds = new LinkedHashSet<JetType>();
168 Collection<JetType> generalLowerBounds = new LinkedHashSet<JetType>();
169 filterNumberTypes(filterBounds(bounds, LOWER_BOUND, values), numberLowerBounds, generalLowerBounds);
170
171 JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
172 if (tryPossibleAnswer(superTypeOfLowerBounds)) {
173 return Collections.singleton(superTypeOfLowerBounds);
174 }
175 UtilsPackage.addIfNotNull(values, superTypeOfLowerBounds);
176
177 //todo
178 //fun <T> foo(t: T, consumer: Consumer<T>): T
179 //foo(1, c: Consumer<Any>) - infer Int, not Any here
180
181 JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
182 if (tryPossibleAnswer(superTypeOfNumberLowerBounds)) {
183 return Collections.singleton(superTypeOfNumberLowerBounds);
184 }
185 UtilsPackage.addIfNotNull(values, superTypeOfNumberLowerBounds);
186
187 if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
188 JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
189 Arrays.asList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds)
190 );
191 if (tryPossibleAnswer(superTypeOfAllLowerBounds)) {
192 return Collections.singleton(superTypeOfAllLowerBounds);
193 }
194 }
195
196 Set<JetType> upperBounds = filterBounds(bounds, BoundKind.UPPER_BOUND, values);
197 JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds);
198 if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) {
199 if (tryPossibleAnswer(intersectionOfUpperBounds)) {
200 return Collections.singleton(intersectionOfUpperBounds);
201 }
202 }
203
204 values.addAll(filterBounds(bounds, BoundKind.UPPER_BOUND));
205
206 return values;
207 }
208
209 private static void filterNumberTypes(
210 @NotNull Collection<JetType> types,
211 @NotNull Collection<JetType> numberTypes,
212 @NotNull Collection<JetType> otherTypes
213 ) {
214 for (JetType type : types) {
215 if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
216 numberTypes.add(type);
217 }
218 else {
219 otherTypes.add(type);
220 }
221 }
222 }
223
224 private boolean tryPossibleAnswer(@Nullable JetType possibleAnswer) {
225 if (possibleAnswer == null) return false;
226 if (!possibleAnswer.getConstructor().isDenotable()) return false;
227
228 for (Bound bound : bounds) {
229 switch (bound.kind) {
230 case LOWER_BOUND:
231 if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.type, possibleAnswer)) {
232 return false;
233 }
234 break;
235
236 case UPPER_BOUND:
237 if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.type)) {
238 return false;
239 }
240 break;
241
242 case EXACT_BOUND:
243 if (!JetTypeChecker.DEFAULT.equalTypes(bound.type, possibleAnswer)) {
244 return false;
245 }
246 break;
247 }
248 }
249 return true;
250 }
251 }