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 com.google.common.collect.Lists;
020 import com.google.common.collect.Sets;
021 import com.intellij.openapi.util.Condition;
022 import com.intellij.openapi.util.Pair;
023 import com.intellij.util.containers.ContainerUtil;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
027 import org.jetbrains.jet.lang.types.*;
028 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
029
030 import java.util.Collection;
031 import java.util.Collections;
032 import java.util.Set;
033
034 public class TypeBoundsImpl implements TypeBounds {
035 public static enum BoundKind {
036 LOWER_BOUND, UPPER_BOUND, EXACT_BOUND
037 }
038
039 public static class Bound {
040 public final JetType type;
041 public final BoundKind kind;
042 public final ConstraintPosition position;
043
044 public Bound(@NotNull JetType type, @NotNull BoundKind kind, @NotNull ConstraintPosition position) {
045 this.type = type;
046 this.kind = kind;
047 this.position = position;
048 }
049 }
050
051 private final TypeParameterDescriptor typeVariable;
052 private final Variance varianceOfPosition;
053 private final Set<Bound> bounds = Sets.newLinkedHashSet();
054
055 private Collection<JetType> resultValues;
056
057 public TypeBoundsImpl(
058 @NotNull TypeParameterDescriptor typeVariable,
059 @NotNull Variance varianceOfPosition
060 ) {
061 this.typeVariable = typeVariable;
062 this.varianceOfPosition = varianceOfPosition;
063 }
064
065 @NotNull
066 @Override
067 public Variance getVarianceOfPosition() {
068 return varianceOfPosition;
069 }
070
071 public void addBound(@NotNull BoundKind kind, @NotNull JetType type, @NotNull ConstraintPosition position) {
072 resultValues = null;
073 bounds.add(new Bound(type, kind, position));
074 }
075
076 @Override
077 public boolean isEmpty() {
078 return getValues().isEmpty();
079 }
080
081 @NotNull
082 public Collection<Bound> getBounds() {
083 return bounds;
084 }
085
086 @NotNull
087 private static Set<JetType> filterBounds(
088 @NotNull Collection<Bound> bounds,
089 @NotNull BoundKind kind
090 ) {
091 return filterBounds(bounds, kind, null);
092 }
093
094 @NotNull
095 private static Set<JetType> filterBounds(
096 @NotNull Collection<Bound> bounds,
097 @NotNull BoundKind kind,
098 @Nullable Collection<JetType> errorValues
099 ) {
100 Set<JetType> result = Sets.newLinkedHashSet();
101 for (Bound bound : bounds) {
102 if (bound.kind == kind) {
103 if (!ErrorUtils.containsErrorType(bound.type)) {
104 result.add(bound.type);
105 }
106 else if (errorValues != null) {
107 errorValues.add(bound.type);
108 }
109 }
110 }
111 return result;
112 }
113
114 /*package*/ TypeBoundsImpl copy() {
115 TypeBoundsImpl typeBounds = new TypeBoundsImpl(typeVariable, varianceOfPosition);
116 typeBounds.bounds.addAll(bounds);
117 typeBounds.resultValues = resultValues;
118 return typeBounds;
119 }
120
121 @NotNull
122 public TypeBoundsImpl filter(@NotNull final Condition<ConstraintPosition> condition) {
123 TypeBoundsImpl result = new TypeBoundsImpl(typeVariable, varianceOfPosition);
124 result.bounds.addAll(ContainerUtil.filter(bounds, new Condition<Bound>() {
125 @Override
126 public boolean value(Bound bound) {
127 return condition.value(bound.position);
128 }
129 }));
130 return result;
131 }
132
133 @Nullable
134 @Override
135 public JetType getValue() {
136 Collection<JetType> values = getValues();
137 if (values.size() == 1) {
138 return values.iterator().next();
139 }
140 return null;
141 }
142
143 @NotNull
144 @Override
145 public Collection<JetType> getValues() {
146 if (resultValues == null) {
147 resultValues = computeValues();
148 }
149 return resultValues;
150 }
151
152 @NotNull
153 private Collection<JetType> computeValues() {
154 Set<JetType> values = Sets.newLinkedHashSet();
155 if (bounds.isEmpty()) {
156 return Collections.emptyList();
157 }
158 boolean hasStrongBound = ContainerUtil.exists(bounds, new Condition<Bound>() {
159 @Override
160 public boolean value(Bound bound) {
161 return bound.position.isStrong();
162 }
163 });
164 if (!hasStrongBound) {
165 return Collections.emptyList();
166 }
167
168 Set<JetType> exactBounds = filterBounds(bounds, BoundKind.EXACT_BOUND, values);
169 if (exactBounds.size() == 1) {
170 JetType exactBound = exactBounds.iterator().next();
171 if (tryPossibleAnswer(exactBound)) {
172 return Collections.singleton(exactBound);
173 }
174 }
175 values.addAll(exactBounds);
176
177 Pair<Collection<JetType>, Collection<JetType>> pair =
178 TypeUtils.filterNumberTypes(filterBounds(bounds, BoundKind.LOWER_BOUND, values));
179 Collection<JetType> generalLowerBounds = pair.getFirst();
180 Collection<JetType> numberLowerBounds = pair.getSecond();
181
182 JetType superTypeOfLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(generalLowerBounds);
183 if (tryPossibleAnswer(superTypeOfLowerBounds)) {
184 return Collections.singleton(superTypeOfLowerBounds);
185 }
186 ContainerUtil.addIfNotNull(superTypeOfLowerBounds, values);
187
188 //todo
189 //fun <T> foo(t: T, consumer: Consumer<T>): T
190 //foo(1, c: Consumer<Any>) - infer Int, not Any here
191
192 JetType superTypeOfNumberLowerBounds = TypeUtils.commonSupertypeForNumberTypes(numberLowerBounds);
193 if (tryPossibleAnswer(superTypeOfNumberLowerBounds)) {
194 return Collections.singleton(superTypeOfNumberLowerBounds);
195 }
196 ContainerUtil.addIfNotNull(superTypeOfNumberLowerBounds, values);
197
198 if (superTypeOfLowerBounds != null && superTypeOfNumberLowerBounds != null) {
199 JetType superTypeOfAllLowerBounds = CommonSupertypes.commonSupertypeForNonDenotableTypes(
200 Lists.newArrayList(superTypeOfLowerBounds, superTypeOfNumberLowerBounds));
201 if (tryPossibleAnswer(superTypeOfAllLowerBounds)) {
202 return Collections.singleton(superTypeOfAllLowerBounds);
203 }
204 }
205
206 Set<JetType> upperBounds = filterBounds(bounds, BoundKind.UPPER_BOUND, values);
207 JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
208 if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) {
209 if (tryPossibleAnswer(intersectionOfUpperBounds)) {
210 return Collections.singleton(intersectionOfUpperBounds);
211 }
212 }
213
214 values.addAll(filterBounds(bounds, BoundKind.UPPER_BOUND));
215
216 return values;
217 }
218
219 private boolean tryPossibleAnswer(@Nullable JetType possibleAnswer) {
220 if (possibleAnswer == null) return false;
221 if (!possibleAnswer.getConstructor().isDenotable()) return false;
222
223 for (Bound bound : bounds) {
224 switch (bound.kind) {
225 case LOWER_BOUND:
226 if (!JetTypeChecker.INSTANCE.isSubtypeOf(bound.type, possibleAnswer)) {
227 return false;
228 }
229 break;
230
231 case UPPER_BOUND:
232 if (!JetTypeChecker.INSTANCE.isSubtypeOf(possibleAnswer, bound.type)) {
233 return false;
234 }
235 break;
236
237 case EXACT_BOUND:
238 if (!JetTypeChecker.INSTANCE.equalTypes(bound.type, possibleAnswer)) {
239 return false;
240 }
241 break;
242 }
243 }
244 return true;
245 }
246 }