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    }