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