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.types;
018    
019    import com.google.common.base.Function;
020    import com.google.common.collect.Collections2;
021    import com.google.common.collect.Lists;
022    import com.google.common.collect.Maps;
023    import com.google.common.collect.Sets;
024    import com.intellij.openapi.util.Pair;
025    import com.intellij.util.Processor;
026    import com.intellij.util.containers.ContainerUtil;
027    import org.jetbrains.annotations.NotNull;
028    import org.jetbrains.annotations.Nullable;
029    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
030    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
031    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
032    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
033    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
034    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
035    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
036    import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstructor;
037    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
038    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
040    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
041    import org.jetbrains.jet.utils.DFS;
042    
043    import java.util.*;
044    
045    public class TypeUtils {
046        public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
047        public static final JetType CANT_INFER_TYPE_PARAMETER = ErrorUtils.createErrorTypeWithCustomDebugName("CANT_INFER_TYPE_PARAMETER");
048        public static final JetType PLACEHOLDER_FUNCTION_TYPE = ErrorUtils.createErrorTypeWithCustomDebugName("PLACEHOLDER_FUNCTION_TYPE");
049    
050        public static final JetType CANT_INFER_LAMBDA_PARAM_TYPE = ErrorUtils.createErrorType("Cannot be inferred");
051    
052        public static class SpecialType implements JetType {
053            private final String name;
054    
055            public SpecialType(String name) {
056                this.name = name;
057            }
058    
059            @NotNull
060            @Override
061            public TypeConstructor getConstructor() {
062                throw new IllegalStateException(name);
063            }
064    
065            @NotNull
066            @Override
067            public List<TypeProjection> getArguments() {
068                throw new IllegalStateException(name);
069            }
070    
071            @Override
072            public boolean isNullable() {
073                throw new IllegalStateException(name);
074            }
075    
076            @NotNull
077            @Override
078            public JetScope getMemberScope() {
079                throw new IllegalStateException(name);
080            }
081    
082            @Override
083            public boolean isError() {
084                return false;
085            }
086    
087            @NotNull
088            @Override
089            public List<AnnotationDescriptor> getAnnotations() {
090                throw new IllegalStateException(name);
091            }
092    
093            @Override
094            public String toString() {
095                return name;
096            }
097        }
098    
099        public static final JetType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
100        
101        public static final JetType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
102    
103        public static boolean noExpectedType(@NotNull JetType type) {
104            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
105        }
106    
107        @NotNull
108        public static JetType makeNullable(@NotNull JetType type) {
109            return makeNullableAsSpecified(type, true);
110        }
111    
112        @NotNull
113        public static JetType makeNotNullable(@NotNull JetType type) {
114            return makeNullableAsSpecified(type, false);
115        }
116    
117        @NotNull
118        public static JetType makeNullableAsSpecified(@NotNull JetType type, boolean nullable) {
119            if (type.isNullable() == nullable) {
120                return type;
121            }
122    
123            // Wrapping serves two purposes here
124            // 1. It's requires less memory than copying with a changed nullability flag: a copy has many fields, while a wrapper has only one
125            // 2. It preserves laziness of types
126    
127            // Unwrap to avoid long delegation call chains
128            if (type instanceof AbstractTypeWithKnownNullability) {
129                return makeNullableAsSpecified(((AbstractTypeWithKnownNullability) type).delegate, nullable);
130            }
131    
132            return nullable ? new NullableType(type) : new NotNullType(type);
133        }
134    
135        public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) {
136            return intersect(JetTypeChecker.INSTANCE, Sets.newLinkedHashSet(Lists.newArrayList(typeA, typeB))) == null;
137        }
138    
139        @Nullable
140        public static JetType intersect(@NotNull JetTypeChecker typeChecker, @NotNull Set<JetType> types) {
141            if (types.isEmpty()) {
142                return KotlinBuiltIns.getInstance().getNullableAnyType();
143            }
144    
145            if (types.size() == 1) {
146                return types.iterator().next();
147            }
148    
149            // Intersection of T1..Tn is an intersection of their non-null versions,
150            //   made nullable is they all were nullable
151            boolean allNullable = true;
152            boolean nothingTypePresent = false;
153            List<JetType> nullabilityStripped = Lists.newArrayList();
154            for (JetType type : types) {
155                nothingTypePresent |= KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type);
156                allNullable &= type.isNullable();
157                nullabilityStripped.add(makeNotNullable(type));
158            }
159            
160            if (nothingTypePresent) {
161                return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
162            }
163    
164            // Now we remove types that have subtypes in the list
165            List<JetType> resultingTypes = Lists.newArrayList();
166            outer:
167            for (JetType type : nullabilityStripped) {
168                if (!canHaveSubtypes(typeChecker, type)) {
169                    for (JetType other : nullabilityStripped) {
170                        // It makes sense to check for subtyping (other <: type), despite that
171                        // type is not supposed to be open, for there're enums
172                        if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
173                            return null;
174                        }
175                    }
176                    return makeNullableAsSpecified(type, allNullable);
177                }
178                else {
179                    for (JetType other : nullabilityStripped) {
180                        if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
181                            continue outer;
182                        }
183    
184                    }
185                }
186    
187                // Don't add type if it is already present, to avoid trivial type intersections in result
188                for (JetType other : resultingTypes) {
189                    if (typeChecker.equalTypes(other, type)) {
190                        continue outer;
191                    }
192                }
193                resultingTypes.add(type);
194            }
195            
196            if (resultingTypes.size() == 1) {
197                return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
198            }
199    
200    
201            List<AnnotationDescriptor> noAnnotations = Collections.<AnnotationDescriptor>emptyList();
202            TypeConstructor constructor = new IntersectionTypeConstructor(
203                    noAnnotations,
204                    resultingTypes);
205    
206            JetScope[] scopes = new JetScope[resultingTypes.size()];
207            int i = 0;
208            for (JetType type : resultingTypes) {
209                scopes[i] = type.getMemberScope();
210                i++;
211            }
212    
213            return new JetTypeImpl(
214                    noAnnotations,
215                    constructor,
216                    allNullable,
217                    Collections.<TypeProjection>emptyList(),
218                    new ChainedScope(null, scopes)); // TODO : check intersectibility, don't use a chanied scope
219        }
220    
221        private static class TypeUnifier {
222            private static class TypeParameterUsage {
223                private final TypeParameterDescriptor typeParameterDescriptor;
224                private final Variance howTheTypeParameterIsUsed;
225    
226                public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
227                    this.typeParameterDescriptor = typeParameterDescriptor;
228                    this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
229                }
230            }
231    
232            public static boolean mayBeEqual(@NotNull JetType type, @NotNull JetType other) {
233                return unify(type, other);
234            }
235    
236            private static boolean unify(JetType withParameters, JetType expected) {
237                // T -> how T is used
238                final Map<TypeParameterDescriptor, Variance> parameters = Maps.newHashMap();
239                Processor<TypeParameterUsage> processor = new Processor<TypeParameterUsage>() {
240                    @Override
241                    public boolean process(TypeParameterUsage parameterUsage) {
242                        Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
243                        if (howTheTypeIsUsedBefore == null) {
244                            howTheTypeIsUsedBefore = Variance.INVARIANT;
245                        }
246                        parameters.put(parameterUsage.typeParameterDescriptor,
247                                       parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
248                        return true;
249                    }
250                };
251                processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
252                processAllTypeParameters(expected, Variance.INVARIANT, processor);
253                ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
254                constraintSystem.registerTypeVariables(parameters);
255                constraintSystem.addSubtypeConstraint(withParameters, expected, ConstraintPosition.SPECIAL);
256    
257                return constraintSystem.getStatus().isSuccessful();
258            }
259    
260            private static void processAllTypeParameters(JetType type, Variance howThiTypeIsUsed, Processor<TypeParameterUsage> result) {
261                ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
262                if (descriptor instanceof TypeParameterDescriptor) {
263                    result.process(new TypeParameterUsage((TypeParameterDescriptor)descriptor, howThiTypeIsUsed));
264                }
265                for (TypeProjection projection : type.getArguments()) {
266                    processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result);
267                }
268            }
269        }
270    
271        public static boolean canHaveSubtypes(JetTypeChecker typeChecker, JetType type) {
272            if (type.isNullable()) {
273                return true;
274            }
275            if (!type.getConstructor().isFinal()) {
276                return true;
277            }
278    
279            List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
280            List<TypeProjection> arguments = type.getArguments();
281            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
282                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
283                TypeProjection typeProjection = arguments.get(i);
284                Variance projectionKind = typeProjection.getProjectionKind();
285                JetType argument = typeProjection.getType();
286    
287                switch (parameterDescriptor.getVariance()) {
288                    case INVARIANT:
289                        switch (projectionKind) {
290                            case INVARIANT:
291                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
292                                    return true;
293                                }
294                                break;
295                            case IN_VARIANCE:
296                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
297                                    return true;
298                                }
299                                break;
300                            case OUT_VARIANCE:
301                                if (canHaveSubtypes(typeChecker, argument)) {
302                                    return true;
303                                }
304                                break;
305                        }
306                        break;
307                    case IN_VARIANCE:
308                        if (projectionKind != Variance.OUT_VARIANCE) {
309                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
310                                return true;
311                            }
312                        }
313                        else {
314                            if (canHaveSubtypes(typeChecker, argument)) {
315                                return true;
316                            }
317                        }
318                        break;
319                    case OUT_VARIANCE:
320                        if (projectionKind != Variance.IN_VARIANCE) {
321                            if (canHaveSubtypes(typeChecker, argument)) {
322                                return true;
323                            }
324                        }
325                        else {
326                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
327                                return true;
328                            }
329                        }
330                        break;
331                }
332            }
333            return false;
334        }
335    
336        private static boolean lowerThanBound(JetTypeChecker typeChecker, JetType argument, TypeParameterDescriptor parameterDescriptor) {
337            for (JetType bound : parameterDescriptor.getUpperBounds()) {
338                if (typeChecker.isSubtypeOf(argument, bound)) {
339                    if (!argument.getConstructor().equals(bound.getConstructor())) {
340                        return true;
341                    }
342                }
343            }
344            return false;
345        }
346    
347        public static JetType makeNullableIfNeeded(JetType type, boolean nullable) {
348            if (nullable) {
349                return makeNullable(type);
350            }
351            return type;
352        }
353    
354        @NotNull
355        public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
356            if (ErrorUtils.isError(classDescriptor)) {
357                return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor);
358            }
359            TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
360            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
361            return new JetTypeImpl(
362                    Collections.<AnnotationDescriptor>emptyList(),
363                    typeConstructor,
364                    false,
365                    arguments,
366                    unsubstitutedMemberScope
367            );
368        }
369    
370        @NotNull
371        public static List<TypeProjection> getDefaultTypeProjections(List<TypeParameterDescriptor> parameters) {
372            List<TypeProjection> result = new ArrayList<TypeProjection>();
373            for (TypeParameterDescriptor parameterDescriptor : parameters) {
374                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
375            }
376            return result;
377        }
378    
379        @NotNull
380        public static List<JetType> getDefaultTypes(List<TypeParameterDescriptor> parameters) {
381            List<JetType> result = Lists.newArrayList();
382            for (TypeParameterDescriptor parameterDescriptor : parameters) {
383                result.add(parameterDescriptor.getDefaultType());
384            }
385            return result;
386        }
387    
388        private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection<JetType> result) {
389            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
390            for (JetType supertype : type.getConstructor().getSupertypes()) {
391                result.add(substitutor.substitute(supertype, Variance.INVARIANT));
392            }
393        }
394    
395        @NotNull
396        public static List<JetType> getImmediateSupertypes(@NotNull JetType type) {
397            List<JetType> result = Lists.newArrayList();
398            collectImmediateSupertypes(type, result);
399            return result;
400        }
401    
402        private static void collectAllSupertypes(@NotNull JetType type, @NotNull Set<JetType> result) {
403            List<JetType> immediateSupertypes = getImmediateSupertypes(type);
404            result.addAll(immediateSupertypes);
405            for (JetType supertype : immediateSupertypes) {
406                collectAllSupertypes(supertype, result);
407            }
408        }
409    
410    
411        @NotNull
412        public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
413            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
414            // the average number is lower
415            Set<JetType> result = new LinkedHashSet<JetType>(15);
416            collectAllSupertypes(type, result);
417            return result;
418        }
419    
420        public static boolean hasNullableLowerBound(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
421            for (JetType bound : typeParameterDescriptor.getLowerBounds()) {
422                if (bound.isNullable()) {
423                    return true;
424                }
425            }
426            return false;
427        }
428    
429        public static boolean hasNullableSuperType(@NotNull JetType type) {
430            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
431                // A class/trait cannot have a nullable supertype
432                return false;
433            }
434    
435            for (JetType supertype : getImmediateSupertypes(type)) {
436                if (supertype.isNullable()) return true;
437                if (hasNullableSuperType(supertype)) return true;
438            }
439            
440            return false;
441        }
442    
443        public static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
444            DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
445            if (declarationDescriptor1 == null) return false; // No class, classes are not equal
446            DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
447            if (declarationDescriptor2 == null) return false; // Class of type1 is not null
448            return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
449        }
450    
451        @Nullable
452        public static ClassDescriptor getClassDescriptor(@NotNull JetType type) {
453            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
454            if (declarationDescriptor instanceof ClassDescriptor) {
455                return (ClassDescriptor) declarationDescriptor;
456            }
457            return null;
458        }
459    
460        @NotNull
461        public static JetType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<JetType> typeArguments) {
462            List<TypeProjection> projections = ContainerUtil.map(typeArguments, new com.intellij.util.Function<JetType, TypeProjection>() {
463                @Override
464                public TypeProjection fun(JetType type) {
465                    return new TypeProjectionImpl(type);
466                }
467            });
468    
469            return substituteProjectionsForParameters(clazz, projections);
470        }
471    
472        @NotNull
473        public static JetType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
474            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
475            if (clazzTypeParameters.size() != projections.size()) {
476                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
477            }
478    
479            Map<TypeConstructor, TypeProjection> substitutions = Maps.newHashMap();
480    
481            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
482                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
483                substitutions.put(typeConstructor, projections.get(i));
484            }
485    
486            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
487        }
488    
489        private static void addAllClassDescriptors(@NotNull JetType type, @NotNull Set<ClassDescriptor> set) {
490            ClassDescriptor cd = getClassDescriptor(type);
491            if (cd != null) {
492                set.add(cd);
493            }
494            for (TypeProjection projection : type.getArguments()) {
495                addAllClassDescriptors(projection.getType(), set);
496            }
497        }
498    
499        @NotNull
500        public static List<ClassDescriptor> getAllClassDescriptors(@NotNull JetType type) {
501            Set<ClassDescriptor> classDescriptors = new HashSet<ClassDescriptor>();
502            addAllClassDescriptors(type, classDescriptors);
503            return new ArrayList<ClassDescriptor>(classDescriptors);
504        }
505    
506        public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
507            return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a);
508        }
509    
510        public static boolean typeConstructorUsedInType(@NotNull TypeConstructor key, @NotNull JetType value) {
511            if (value.getConstructor() == key) return true;
512            for (TypeProjection projection : value.getArguments()) {
513                if (typeConstructorUsedInType(key, projection.getType())) {
514                    return true;
515                }
516            }
517            return false;
518        }
519    
520        public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
521            return dependsOnTypeConstructors(type, Collections2
522                    .transform(typeParameters, new Function<TypeParameterDescriptor, TypeConstructor>() {
523                        @Override
524                        public TypeConstructor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
525                            assert typeParameterDescriptor != null;
526                            return typeParameterDescriptor.getTypeConstructor();
527                        }
528                    }));
529        }
530    
531        public static boolean dependsOnTypeConstructors(@NotNull JetType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
532            if (typeParameterConstructors.contains(type.getConstructor())) return true;
533            for (TypeProjection typeProjection : type.getArguments()) {
534                if (dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
535                    return true;
536                }
537            }
538            return false;
539        }
540    
541        public static boolean equalsOrContainsAsArgument(@Nullable JetType type, @NotNull JetType... possibleArgumentTypes) {
542            return equalsOrContainsAsArgument(type, Sets.newHashSet(possibleArgumentTypes));
543        }
544    
545        private static boolean equalsOrContainsAsArgument(@Nullable JetType type, @NotNull Set<JetType> possibleArgumentTypes) {
546            if (type == null) return false;
547            if (possibleArgumentTypes.contains(type)) return true;
548            if (type instanceof NamespaceType) return false;
549            for (TypeProjection projection : type.getArguments()) {
550                if (equalsOrContainsAsArgument(projection.getType(), possibleArgumentTypes)) return true;
551            }
552            return false;
553        }
554    
555        @NotNull
556        public static String getTypeNameAndStarProjectionsString(@NotNull String name, int size) {
557            StringBuilder builder = new StringBuilder(name);
558            builder.append("<");
559            for (int i = 0; i < size; i++) {
560                builder.append("*");
561                if (i == size - 1) break;
562                builder.append(", ");
563            }
564            builder.append(">");
565    
566            return builder.toString();
567        }
568    
569        @Nullable
570        public static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
571            if (numberLowerBounds.isEmpty()) return null;
572            assert !numberLowerBounds.isEmpty();
573            Set<JetType> intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds);
574            JetType primitiveNumberType = getDefaultPrimitiveNumberType(intersectionOfSupertypes);
575            if (primitiveNumberType != null) {
576                return primitiveNumberType;
577            }
578            return CommonSupertypes.commonSupertype(numberLowerBounds);
579        }
580    
581        @NotNull
582        private static Set<JetType> getIntersectionOfSupertypes(@NotNull Collection<JetType> types) {
583            Set<JetType> upperBounds = Sets.newHashSet();
584            for (JetType type : types) {
585                Set<JetType> supertypes = Sets.newHashSet(type.getConstructor().getSupertypes());
586                if (upperBounds.isEmpty()) {
587                    upperBounds.addAll(supertypes);
588                }
589                else {
590                    upperBounds = Sets.intersection(upperBounds, supertypes);
591                }
592            }
593            return upperBounds;
594        }
595    
596        @NotNull
597        public static JetType getDefaultPrimitiveNumberType(@NotNull NumberValueTypeConstructor numberValueTypeConstructor) {
598            JetType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
599            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
600                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
601            return type;
602        }
603    
604        @Nullable
605        private static JetType getDefaultPrimitiveNumberType(@NotNull Collection<JetType> supertypes) {
606            JetType doubleType = KotlinBuiltIns.getInstance().getDoubleType();
607            if (supertypes.contains(doubleType)) {
608                return doubleType;
609            }
610            JetType intType = KotlinBuiltIns.getInstance().getIntType();
611            if (supertypes.contains(intType)) {
612                return intType;
613            }
614            JetType longType = KotlinBuiltIns.getInstance().getLongType();
615            if (supertypes.contains(longType)) {
616                return longType;
617            }
618            return null;
619        }
620    
621        @NotNull
622        public static JetType getPrimitiveNumberType(
623                @NotNull NumberValueTypeConstructor numberValueTypeConstructor,
624                @NotNull JetType expectedType
625        ) {
626            if (noExpectedType(expectedType) || expectedType.isError()) {
627                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
628            }
629            for (JetType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
630                if (JetTypeChecker.INSTANCE.isSubtypeOf(primitiveNumberType, expectedType)) {
631                    return primitiveNumberType;
632                }
633            }
634            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
635        }
636    
637        @NotNull
638        public static Pair<Collection<JetType>, Collection<JetType>> filterNumberTypes(@NotNull Collection<JetType> types) {
639            Collection<JetType> numberTypes = Sets.newLinkedHashSet();
640            Collection<JetType> otherTypes = Sets.newLinkedHashSet();
641            for (JetType type : types) {
642                if (type.getConstructor() instanceof NumberValueTypeConstructor) {
643                    numberTypes.add(type);
644                }
645                else {
646                    otherTypes.add(type);
647                }
648            }
649            return Pair.create(otherTypes, numberTypes);
650        }
651    
652        public static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
653                @NotNull JetType type,
654                @NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances,
655                @NotNull final Set<TypeConstructor> visited
656        ) {
657            return DFS.dfs(
658                    Collections.singletonList(type),
659                    new DFS.Neighbors<JetType>() {
660                        @NotNull
661                        @Override
662                        public Iterable<JetType> getNeighbors(JetType current) {
663                            TypeSubstitutor substitutor = TypeSubstitutor.create(current);
664                            List<JetType> result = Lists.newArrayList();
665                            for (JetType supertype : current.getConstructor().getSupertypes()) {
666                                if (visited.contains(supertype.getConstructor())) {
667                                    continue;
668                                }
669                                result.add(substitutor.safeSubstitute(supertype, Variance.INVARIANT));
670                            }
671                            return result;
672                        }
673                    },
674                    new DFS.Visited<JetType>() {
675                        @Override
676                        public boolean checkAndMarkVisited(JetType current) {
677                            return visited.add(current.getConstructor());
678                        }
679                    },
680                    new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() {
681                        @Override
682                        public void beforeChildren(JetType current) {
683                            TypeConstructor constructor = current.getConstructor();
684    
685                            Set<JetType> instances = constructorToAllInstances.get(constructor);
686                            if (instances == null) {
687                                instances = new HashSet<JetType>();
688                                constructorToAllInstances.put(constructor, instances);
689                            }
690                            instances.add(current);
691                        }
692    
693                        @Override
694                        public void afterChildren(JetType current) {
695                            result.addFirst(current.getConstructor());
696                        }
697                    }
698            );
699        }
700    
701        public static TypeSubstitutor makeConstantSubstitutor(Collection<TypeParameterDescriptor> typeParameterDescriptors, JetType type) {
702            final Set<TypeConstructor> constructors = Sets.newHashSet();
703            for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
704                constructors.add(typeParameterDescriptor.getTypeConstructor());
705            }
706            final TypeProjection projection = new TypeProjectionImpl(type);
707    
708            return TypeSubstitutor.create(new TypeSubstitution() {
709                @Override
710                public TypeProjection get(TypeConstructor key) {
711                    if (constructors.contains(key)) {
712                        return projection;
713                    }
714                    return null;
715                }
716    
717                @Override
718                public boolean isEmpty() {
719                    return false;
720                }
721            });
722        }
723    
724        public static TypeSubstitutor makeSubstitutorForTypeParametersMap(
725               @NotNull final Map<TypeParameterDescriptor, TypeProjection> substitutionContext
726        ) {
727            return TypeSubstitutor.create(new TypeSubstitution() {
728                @Nullable
729                @Override
730                public TypeProjection get(TypeConstructor key) {
731                    DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
732                    if (declarationDescriptor instanceof TypeParameterDescriptor) {
733                        TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
734                        return substitutionContext.get(descriptor);
735                    }
736                    return null;
737                }
738    
739                @Override
740                public boolean isEmpty() {
741                    return substitutionContext.isEmpty();
742                }
743    
744                @Override
745                public String toString() {
746                    return substitutionContext.toString();
747                }
748            });
749        }
750    
751        private static abstract class AbstractTypeWithKnownNullability extends AbstractJetType {
752            private final JetType delegate;
753    
754            private AbstractTypeWithKnownNullability(@NotNull JetType delegate) {
755                this.delegate = delegate;
756            }
757    
758            @Override
759            @NotNull
760            public TypeConstructor getConstructor() {
761                return delegate.getConstructor();
762            }
763    
764            @Override
765            @NotNull
766            public List<TypeProjection> getArguments() {
767                return delegate.getArguments();
768            }
769    
770            @Override
771            public abstract boolean isNullable();
772    
773            @Override
774            @NotNull
775            public JetScope getMemberScope() {
776                return delegate.getMemberScope();
777            }
778    
779            @Override
780            public boolean isError() {
781                return delegate.isError();
782            }
783    
784            @Override
785            @NotNull
786            public List<AnnotationDescriptor> getAnnotations() {
787                return delegate.getAnnotations();
788            }
789        }
790    
791        private static class NullableType extends AbstractTypeWithKnownNullability {
792    
793            private NullableType(@NotNull JetType delegate) {
794                super(delegate);
795            }
796    
797            @Override
798            public boolean isNullable() {
799                return true;
800            }
801        }
802    
803        private static class NotNullType extends AbstractTypeWithKnownNullability {
804    
805            private NotNullType(@NotNull JetType delegate) {
806                super(delegate);
807            }
808    
809            @Override
810            public boolean isNullable() {
811                return false;
812            }
813        }
814    
815    }