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.*;
030    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
031    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener;
032    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
033    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemWithPriorities;
034    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType;
035    import org.jetbrains.jet.lang.resolve.constants.NumberValueTypeConstructor;
036    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
037    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
039    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040    
041    import java.util.*;
042    
043    public class TypeUtils {
044        public static class SpecialType implements JetType {
045            private final String name;
046    
047            public SpecialType(String name) {
048                this.name = name;
049            }
050    
051            @NotNull
052            @Override
053            public TypeConstructor getConstructor() {
054                throw new IllegalStateException(name);
055            }
056    
057            @NotNull
058            @Override
059            public List<TypeProjection> getArguments() {
060                throw new IllegalStateException(name);
061            }
062    
063            @Override
064            public boolean isNullable() {
065                throw new IllegalStateException(name);
066            }
067    
068            @NotNull
069            @Override
070            public JetScope getMemberScope() {
071                throw new IllegalStateException(name);
072            }
073    
074            @Override
075            public List<AnnotationDescriptor> getAnnotations() {
076                throw new IllegalStateException(name);
077            }
078    
079            @Override
080            public String toString() {
081                return name;
082            }
083        }
084    
085        public static final JetType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
086        
087        public static final JetType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
088    
089        public static boolean noExpectedType(@NotNull JetType type) {
090            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
091        }
092    
093        @NotNull
094        public static JetType makeNullable(@NotNull JetType type) {
095            return makeNullableAsSpecified(type, true);
096        }
097    
098        @NotNull
099        public static JetType makeNotNullable(@NotNull JetType type) {
100            return makeNullableAsSpecified(type, false);
101        }
102    
103        @NotNull
104        public static JetType makeNullableAsSpecified(@NotNull JetType type, boolean nullable) {
105            if (type.isNullable() == nullable) {
106                return type;
107            }
108            if (ErrorUtils.isErrorType(type)) {
109                return type;
110            }
111            return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), nullable, type.getArguments(), type.getMemberScope());
112        }
113    
114        public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) {
115            return intersect(JetTypeChecker.INSTANCE, Sets.newLinkedHashSet(Lists.newArrayList(typeA, typeB))) == null;
116        }
117    
118        @Nullable
119        public static JetType intersect(@NotNull JetTypeChecker typeChecker, @NotNull Set<JetType> types) {
120            if (types.isEmpty()) {
121                return KotlinBuiltIns.getInstance().getNullableAnyType();
122            }
123    
124            if (types.size() == 1) {
125                return types.iterator().next();
126            }
127    
128            // Intersection of T1..Tn is an intersection of their non-null versions,
129            //   made nullable is they all were nullable
130            boolean allNullable = true;
131            boolean nothingTypePresent = false;
132            List<JetType> nullabilityStripped = Lists.newArrayList();
133            for (JetType type : types) {
134                nothingTypePresent |= KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type);
135                allNullable &= type.isNullable();
136                nullabilityStripped.add(makeNotNullable(type));
137            }
138            
139            if (nothingTypePresent) {
140                return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
141            }
142    
143            // Now we remove types that have subtypes in the list
144            List<JetType> resultingTypes = Lists.newArrayList();
145            outer:
146            for (JetType type : nullabilityStripped) {
147                if (!canHaveSubtypes(typeChecker, type)) {
148                    for (JetType other : nullabilityStripped) {
149                        // It makes sense to check for subtyping (other <: type), despite that
150                        // type is not supposed to be open, for there're enums
151                        if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
152                            return null;
153                        }
154                    }
155                    return makeNullableAsSpecified(type, allNullable);
156                }
157                else {
158                    for (JetType other : nullabilityStripped) {
159                        if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
160                            continue outer;
161                        }
162    
163                    }
164                }
165    
166                // Don't add type if it is already present, to avoid trivial type intersections in result
167                for (JetType other : resultingTypes) {
168                    if (typeChecker.equalTypes(other, type)) {
169                        continue outer;
170                    }
171                }
172                resultingTypes.add(type);
173            }
174            
175            if (resultingTypes.size() == 1) {
176                return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
177            }
178    
179    
180            List<AnnotationDescriptor> noAnnotations = Collections.<AnnotationDescriptor>emptyList();
181            TypeConstructor constructor = new IntersectionTypeConstructor(
182                    noAnnotations,
183                    resultingTypes);
184    
185            JetScope[] scopes = new JetScope[resultingTypes.size()];
186            int i = 0;
187            for (JetType type : resultingTypes) {
188                scopes[i] = type.getMemberScope();
189                i++;
190            }
191    
192            return new JetTypeImpl(
193                    noAnnotations,
194                    constructor,
195                    allNullable,
196                    Collections.<TypeProjection>emptyList(),
197                    new ChainedScope(null, scopes)); // TODO : check intersectibility, don't use a chanied scope
198        }
199    
200        @NotNull
201        public static String toString(@NotNull JetType type) {
202            List<TypeProjection> arguments = type.getArguments();
203            return type.getConstructor() + (arguments.isEmpty() ? "" : "<" + argumentsToString(arguments) + ">") + (type.isNullable() ? "?" : "");
204        }
205    
206        private static StringBuilder argumentsToString(List<TypeProjection> arguments) {
207            StringBuilder stringBuilder = new StringBuilder();
208            for (Iterator<TypeProjection> iterator = arguments.iterator(); iterator.hasNext();) {
209                TypeProjection argument = iterator.next();
210                stringBuilder.append(argument);
211                if (iterator.hasNext()) {
212                    stringBuilder.append(", ");
213                }
214            }
215            return stringBuilder;
216        }
217    
218        private static class TypeUnifier {
219            private static class TypeParameterUsage {
220                private final TypeParameterDescriptor typeParameterDescriptor;
221                private final Variance howTheTypeParameterIsUsed;
222    
223                public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
224                    this.typeParameterDescriptor = typeParameterDescriptor;
225                    this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
226                }
227            }
228    
229            public static boolean mayBeEqual(@NotNull JetType type, @NotNull JetType other) {
230                return unify(type, other);
231            }
232    
233            private static boolean unify(JetType withParameters, JetType expected) {
234                ConstraintSystemWithPriorities constraintSystem = new ConstraintSystemWithPriorities(ConstraintResolutionListener.DO_NOTHING);
235                // T -> how T is used
236                final Map<TypeParameterDescriptor, Variance> parameters = Maps.newHashMap();
237                Processor<TypeParameterUsage> processor = new Processor<TypeParameterUsage>() {
238                    @Override
239                    public boolean process(TypeParameterUsage parameterUsage) {
240                        Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
241                        if (howTheTypeIsUsedBefore == null) {
242                            howTheTypeIsUsedBefore = Variance.INVARIANT;
243                        }
244                        parameters.put(parameterUsage.typeParameterDescriptor,
245                                       parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
246                        return true;
247                    }
248                };
249                processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
250                processAllTypeParameters(expected, Variance.INVARIANT, processor);
251                for (Map.Entry<TypeParameterDescriptor, Variance> entry : parameters.entrySet()) {
252                    constraintSystem.registerTypeVariable(entry.getKey(), entry.getValue());
253                }
254                constraintSystem.addSubtypingConstraint(ConstraintType.VALUE_ARGUMENT.assertSubtyping(withParameters, expected));
255    
256                ConstraintSystemSolution solution = constraintSystem.solve();
257                return solution.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().isSealed()) {
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            return makeUnsubstitutedType(classDescriptor.getTypeConstructor(), unsubstitutedMemberScope);
357        }
358    
359        @NotNull
360        public static JetType makeUnsubstitutedType(TypeConstructor typeConstructor, JetScope unsubstitutedMemberScope) {
361            if (ErrorUtils.isError(typeConstructor)) {
362                return ErrorUtils.createErrorType("Unsubstituted type for " + typeConstructor);
363            }
364            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
365            return new JetTypeImpl(
366                    Collections.<AnnotationDescriptor>emptyList(),
367                    typeConstructor,
368                    false,
369                    arguments,
370                    unsubstitutedMemberScope
371            );
372        }
373    
374        @NotNull
375        public static List<TypeProjection> getDefaultTypeProjections(List<TypeParameterDescriptor> parameters) {
376            List<TypeProjection> result = new ArrayList<TypeProjection>();
377            for (TypeParameterDescriptor parameterDescriptor : parameters) {
378                result.add(new TypeProjection(parameterDescriptor.getDefaultType()));
379            }
380            return result;
381        }
382    
383        @NotNull
384        public static List<JetType> getDefaultTypes(List<TypeParameterDescriptor> parameters) {
385            List<JetType> result = Lists.newArrayList();
386            for (TypeParameterDescriptor parameterDescriptor : parameters) {
387                result.add(parameterDescriptor.getDefaultType());
388            }
389            return result;
390        }
391    
392        private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection<JetType> result) {
393            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
394            for (JetType supertype : type.getConstructor().getSupertypes()) {
395                result.add(substitutor.substitute(supertype, Variance.INVARIANT));
396            }
397        }
398    
399        @NotNull
400        public static List<JetType> getImmediateSupertypes(@NotNull JetType type) {
401            List<JetType> result = Lists.newArrayList();
402            collectImmediateSupertypes(type, result);
403            return result;
404        }
405    
406        private static void collectAllSupertypes(@NotNull JetType type, @NotNull Set<JetType> result) {
407            List<JetType> immediateSupertypes = getImmediateSupertypes(type);
408            result.addAll(immediateSupertypes);
409            for (JetType supertype : immediateSupertypes) {
410                collectAllSupertypes(supertype, result);
411            }
412        }
413    
414    
415        @NotNull
416        public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
417            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
418            // the average number is lower
419            Set<JetType> result = new LinkedHashSet<JetType>(15);
420            collectAllSupertypes(type, result);
421            return result;
422        }
423    
424        public static boolean hasNullableLowerBound(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
425            for (JetType bound : typeParameterDescriptor.getLowerBounds()) {
426                if (bound.isNullable()) {
427                    return true;
428                }
429            }
430            return false;
431        }
432    
433        public static boolean hasNullableSuperType(@NotNull JetType type) {
434            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
435                // A class/trait cannot have a nullable supertype
436                return false;
437            }
438    
439            for (JetType supertype : getImmediateSupertypes(type)) {
440                if (supertype.isNullable()) return true;
441                if (hasNullableSuperType(supertype)) return true;
442            }
443            
444            return false;
445        }
446    
447        public static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
448            DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
449            if (declarationDescriptor1 == null) return false; // No class, classes are not equal
450            DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
451            if (declarationDescriptor2 == null) return false; // Class of type1 is not null
452            return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
453        }
454    
455        @Nullable
456        public static ClassDescriptor getClassDescriptor(@NotNull JetType type) {
457            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
458            if (declarationDescriptor instanceof ClassDescriptor) {
459                return (ClassDescriptor) declarationDescriptor;
460            }
461            return null;
462        }
463    
464        @NotNull
465        public static JetType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<JetType> typeArguments) {
466            List<TypeProjection> projections = ContainerUtil.map(typeArguments, new com.intellij.util.Function<JetType, TypeProjection>() {
467                @Override
468                public TypeProjection fun(JetType type) {
469                    return new TypeProjection(type);
470                }
471            });
472    
473            return substituteProjectionsForParameters(clazz, projections);
474        }
475    
476        @NotNull
477        public static JetType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
478            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
479            if (clazzTypeParameters.size() != projections.size()) {
480                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
481            }
482    
483            Map<TypeConstructor, TypeProjection> substitutions = Maps.newHashMap();
484    
485            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
486                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
487                substitutions.put(typeConstructor, projections.get(i));
488            }
489    
490            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
491        }
492    
493        private static void addAllClassDescriptors(@NotNull JetType type, @NotNull Set<ClassDescriptor> set) {
494            ClassDescriptor cd = getClassDescriptor(type);
495            if (cd != null) {
496                set.add(cd);
497            }
498            for (TypeProjection projection : type.getArguments()) {
499                addAllClassDescriptors(projection.getType(), set);
500            }
501        }
502    
503        @NotNull
504        public static List<ClassDescriptor> getAllClassDescriptors(@NotNull JetType type) {
505            Set<ClassDescriptor> classDescriptors = new HashSet<ClassDescriptor>();
506            addAllClassDescriptors(type, classDescriptors);
507            return new ArrayList<ClassDescriptor>(classDescriptors);
508        }
509    
510        public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
511            return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a);
512        }
513    
514        public static boolean typeConstructorUsedInType(@NotNull TypeConstructor key, @NotNull JetType value) {
515            if (value.getConstructor() == key) return true;
516            for (TypeProjection projection : value.getArguments()) {
517                if (typeConstructorUsedInType(key, projection.getType())) {
518                    return true;
519                }
520            }
521            return false;
522        }
523    
524        public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
525            return dependsOnTypeConstructors(type, Collections2
526                    .transform(typeParameters, new Function<TypeParameterDescriptor, TypeConstructor>() {
527                        @Override
528                        public TypeConstructor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
529                            assert typeParameterDescriptor != null;
530                            return typeParameterDescriptor.getTypeConstructor();
531                        }
532                    }));
533        }
534    
535        public static boolean dependsOnTypeConstructors(@NotNull JetType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
536            if (typeParameterConstructors.contains(type.getConstructor())) return true;
537            for (TypeProjection typeProjection : type.getArguments()) {
538                if (dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
539                    return true;
540                }
541            }
542            return false;
543        }
544    
545        public static boolean equalsOrContainsAsArgument(@Nullable JetType type, @NotNull JetType... possibleArgumentTypes) {
546            return equalsOrContainsAsArgument(type, Sets.newHashSet(possibleArgumentTypes));
547        }
548    
549        private static boolean equalsOrContainsAsArgument(@Nullable JetType type, @NotNull Set<JetType> possibleArgumentTypes) {
550            if (type == null) return false;
551            if (possibleArgumentTypes.contains(type)) return true;
552            if (type instanceof NamespaceType) return false;
553            for (TypeProjection projection : type.getArguments()) {
554                if (equalsOrContainsAsArgument(projection.getType(), possibleArgumentTypes)) return true;
555            }
556            return false;
557        }
558    
559        @NotNull
560        public static String getTypeNameAndStarProjectionsString(@NotNull String name, int size) {
561            StringBuilder builder = new StringBuilder(name);
562            builder.append("<");
563            for (int i = 0; i < size; i++) {
564                builder.append("*");
565                if (i == size - 1) break;
566                builder.append(", ");
567            }
568            builder.append(">");
569    
570            return builder.toString();
571        }
572    
573        @NotNull
574        public static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
575            assert !numberLowerBounds.isEmpty();
576            Set<JetType> intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds);
577            JetType primitiveNumberType = getDefaultPrimitiveNumberType(intersectionOfSupertypes);
578            if (primitiveNumberType != null) {
579                return primitiveNumberType;
580            }
581            return CommonSupertypes.commonSupertype(numberLowerBounds);
582        }
583    
584        @NotNull
585        private static Set<JetType> getIntersectionOfSupertypes(@NotNull Collection<JetType> types) {
586            Set<JetType> upperBounds = Sets.newHashSet();
587            for (JetType type : types) {
588                Set<JetType> supertypes = Sets.newHashSet(type.getConstructor().getSupertypes());
589                if (upperBounds.isEmpty()) {
590                    upperBounds.addAll(supertypes);
591                }
592                else {
593                    upperBounds = Sets.intersection(upperBounds, supertypes);
594                }
595            }
596            return upperBounds;
597        }
598    
599        @NotNull
600        public static JetType getDefaultPrimitiveNumberType(@NotNull NumberValueTypeConstructor numberValueTypeConstructor) {
601            JetType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
602            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
603                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
604            return type;
605        }
606    
607        @Nullable
608        private static JetType getDefaultPrimitiveNumberType(@NotNull Collection<JetType> supertypes) {
609            JetType doubleType = KotlinBuiltIns.getInstance().getDoubleType();
610            if (supertypes.contains(doubleType)) {
611                return doubleType;
612            }
613            JetType intType = KotlinBuiltIns.getInstance().getIntType();
614            if (supertypes.contains(intType)) {
615                return intType;
616            }
617            JetType longType = KotlinBuiltIns.getInstance().getLongType();
618            if (supertypes.contains(longType)) {
619                return longType;
620            }
621            return null;
622        }
623    
624        @NotNull
625        public static JetType getPrimitiveNumberType(
626                @NotNull NumberValueTypeConstructor numberValueTypeConstructor,
627                @NotNull JetType expectedType
628        ) {
629            if (noExpectedType(expectedType) || ErrorUtils.isErrorType(expectedType)) {
630                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
631            }
632            for (JetType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
633                if (JetTypeChecker.INSTANCE.isSubtypeOf(primitiveNumberType, expectedType)) {
634                    return primitiveNumberType;
635                }
636            }
637            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
638        }
639    
640        @NotNull
641        public static Pair<Collection<JetType>, Collection<JetType>> filterNumberTypes(@NotNull Collection<JetType> types) {
642            Collection<JetType> numberTypes = Sets.newLinkedHashSet();
643            Collection<JetType> otherTypes = Sets.newLinkedHashSet();
644            for (JetType type : types) {
645                if (type.getConstructor() instanceof NumberValueTypeConstructor) {
646                    numberTypes.add(type);
647                }
648                else {
649                    otherTypes.add(type);
650                }
651            }
652            return Pair.create(otherTypes, numberTypes);
653        }
654    }