001    /*
002     * Copyright 2010-2015 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.kotlin.types;
018    
019    import kotlin.collections.CollectionsKt;
020    import kotlin.jvm.functions.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024    import org.jetbrains.kotlin.descriptors.ClassDescriptor;
025    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
026    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
027    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
028    import org.jetbrains.kotlin.resolve.calls.inference.CapturedType;
029    import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructor;
030    import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
031    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
032    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
033    import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
034    
035    import java.util.*;
036    
037    public class TypeUtils {
038        public static final KotlinType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
039        public static final KotlinType CANT_INFER_FUNCTION_PARAM_TYPE = ErrorUtils.createErrorType("Cannot be inferred");
040    
041        public static class SpecialType implements KotlinType {
042            private final String name;
043    
044            public SpecialType(String name) {
045                this.name = name;
046            }
047    
048            @NotNull
049            @Override
050            public TypeConstructor getConstructor() {
051                throw new IllegalStateException(name);
052            }
053    
054            @NotNull
055            @Override
056            public List<TypeProjection> getArguments() {
057                throw new IllegalStateException(name);
058            }
059    
060            @NotNull
061            @Override
062            public TypeSubstitution getSubstitution() {
063                throw new IllegalStateException(name);
064            }
065    
066            @Override
067            public boolean isMarkedNullable() {
068                throw new IllegalStateException(name);
069            }
070    
071            @NotNull
072            @Override
073            public MemberScope getMemberScope() {
074                throw new IllegalStateException(name);
075            }
076    
077            @Override
078            public boolean isError() {
079                return false;
080            }
081    
082            @NotNull
083            @Override
084            public Annotations getAnnotations() {
085                throw new IllegalStateException(name);
086            }
087    
088            @Nullable
089            @Override
090            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
091                return null;
092            }
093    
094            @NotNull
095            @Override
096            public TypeCapabilities getCapabilities() {
097                return TypeCapabilities.NONE.INSTANCE;
098            }
099    
100            @Override
101            public String toString() {
102                return name;
103            }
104        }
105    
106        @NotNull
107        public static final KotlinType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
108    
109        public static final KotlinType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
110    
111        public static boolean noExpectedType(@NotNull KotlinType type) {
112            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
113        }
114    
115        public static boolean isDontCarePlaceholder(@Nullable KotlinType type) {
116            return type != null && type.getConstructor() == DONT_CARE.getConstructor();
117        }
118    
119        @NotNull
120        public static KotlinType makeNullable(@NotNull KotlinType type) {
121            return makeNullableAsSpecified(type, true);
122        }
123    
124        @NotNull
125        public static KotlinType makeNotNullable(@NotNull KotlinType type) {
126            return makeNullableAsSpecified(type, false);
127        }
128    
129        @NotNull
130        public static KotlinType makeNullableAsSpecified(@NotNull KotlinType type, boolean nullable) {
131            NullAwareness nullAwareness = type.getCapability(NullAwareness.class);
132            if (nullAwareness != null) {
133                return nullAwareness.makeNullableAsSpecified(nullable);
134            }
135    
136            // Wrapping serves two purposes here
137            // 1. It's requires less memory than copying with a changed nullability flag: a copy has many fields, while a wrapper has only one
138            // 2. It preserves laziness of types
139    
140            // Unwrap to avoid long delegation call chains
141            if (type instanceof AbstractTypeWithKnownNullability) {
142                return makeNullableAsSpecified(((AbstractTypeWithKnownNullability) type).delegate, nullable);
143            }
144    
145            // checking to preserve laziness
146            if (!(type instanceof LazyType) && type.isMarkedNullable() == nullable) {
147                return type;
148            }
149    
150            return nullable ? new NullableType(type) : new NotNullType(type);
151        }
152    
153        @NotNull
154        public static KotlinType makeNullableIfNeeded(@NotNull KotlinType type, boolean nullable) {
155            if (nullable) {
156                return makeNullable(type);
157            }
158            return type;
159        }
160    
161        public static boolean canHaveSubtypes(KotlinTypeChecker typeChecker, @NotNull KotlinType type) {
162            if (type.isMarkedNullable()) {
163                return true;
164            }
165            if (!type.getConstructor().isFinal()) {
166                return true;
167            }
168    
169            List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
170            List<TypeProjection> arguments = type.getArguments();
171            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
172                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
173                TypeProjection typeProjection = arguments.get(i);
174                Variance projectionKind = typeProjection.getProjectionKind();
175                KotlinType argument = typeProjection.getType();
176    
177                switch (parameterDescriptor.getVariance()) {
178                    case INVARIANT:
179                        switch (projectionKind) {
180                            case INVARIANT:
181                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
182                                    return true;
183                                }
184                                break;
185                            case IN_VARIANCE:
186                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
187                                    return true;
188                                }
189                                break;
190                            case OUT_VARIANCE:
191                                if (canHaveSubtypes(typeChecker, argument)) {
192                                    return true;
193                                }
194                                break;
195                        }
196                        break;
197                    case IN_VARIANCE:
198                        if (projectionKind != Variance.OUT_VARIANCE) {
199                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
200                                return true;
201                            }
202                        }
203                        else {
204                            if (canHaveSubtypes(typeChecker, argument)) {
205                                return true;
206                            }
207                        }
208                        break;
209                    case OUT_VARIANCE:
210                        if (projectionKind != Variance.IN_VARIANCE) {
211                            if (canHaveSubtypes(typeChecker, argument)) {
212                                return true;
213                            }
214                        }
215                        else {
216                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
217                                return true;
218                            }
219                        }
220                        break;
221                }
222            }
223            return false;
224        }
225    
226        private static boolean lowerThanBound(KotlinTypeChecker typeChecker, KotlinType argument, TypeParameterDescriptor parameterDescriptor) {
227            for (KotlinType bound : parameterDescriptor.getUpperBounds()) {
228                if (typeChecker.isSubtypeOf(argument, bound)) {
229                    if (!argument.getConstructor().equals(bound.getConstructor())) {
230                        return true;
231                    }
232                }
233            }
234            return false;
235        }
236    
237        @NotNull
238        public static KotlinType makeUnsubstitutedType(ClassDescriptor classDescriptor, MemberScope unsubstitutedMemberScope) {
239            if (ErrorUtils.isError(classDescriptor)) {
240                return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor);
241            }
242            TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
243            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
244            return KotlinTypeImpl.create(
245                    Annotations.Companion.getEMPTY(),
246                    typeConstructor,
247                    false,
248                    arguments,
249                    unsubstitutedMemberScope
250            );
251        }
252    
253        @NotNull
254        public static List<TypeProjection> getDefaultTypeProjections(@NotNull List<TypeParameterDescriptor> parameters) {
255            List<TypeProjection> result = new ArrayList<TypeProjection>(parameters.size());
256            for (TypeParameterDescriptor parameterDescriptor : parameters) {
257                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
258            }
259            return org.jetbrains.kotlin.utils.CollectionsKt.toReadOnlyList(result);
260        }
261    
262        @NotNull
263        public static List<KotlinType> getImmediateSupertypes(@NotNull KotlinType type) {
264            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
265            Collection<KotlinType> originalSupertypes = type.getConstructor().getSupertypes();
266            List<KotlinType> result = new ArrayList<KotlinType>(originalSupertypes.size());
267            for (KotlinType supertype : originalSupertypes) {
268                KotlinType substitutedType = createSubstitutedSupertype(type, supertype, substitutor);
269                if (substitutedType != null) {
270                    result.add(substitutedType);
271                }
272            }
273            return result;
274        }
275    
276        @Nullable
277        public static KotlinType createSubstitutedSupertype(
278                @NotNull KotlinType subType,
279                @NotNull KotlinType superType,
280                @NotNull TypeSubstitutor substitutor
281        ) {
282            KotlinType substitutedType = substitutor.substitute(superType, Variance.INVARIANT);
283            if (substitutedType != null) {
284                return makeNullableIfNeeded(substitutedType, subType.isMarkedNullable());
285            }
286            return null;
287        }
288    
289        private static void collectAllSupertypes(@NotNull KotlinType type, @NotNull Set<KotlinType> result) {
290            List<KotlinType> immediateSupertypes = getImmediateSupertypes(type);
291            result.addAll(immediateSupertypes);
292            for (KotlinType supertype : immediateSupertypes) {
293                collectAllSupertypes(supertype, result);
294            }
295        }
296    
297    
298        @NotNull
299        public static Set<KotlinType> getAllSupertypes(@NotNull KotlinType type) {
300            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
301            // the average number is lower
302            Set<KotlinType> result = new LinkedHashSet<KotlinType>(15);
303            collectAllSupertypes(type, result);
304            return result;
305        }
306    
307        /**
308         * A work-around of the generic nullability problem in the type checker
309         * Semantics should be the same as `!isSubtype(T, Any)`
310         * @return true if a value of this type can be null
311         */
312        public static boolean isNullableType(@NotNull KotlinType type) {
313            if (type.isMarkedNullable()) {
314                return true;
315            }
316            if (FlexibleTypesKt.isFlexible(type) && isNullableType(FlexibleTypesKt.flexibility(type).getUpperBound())) {
317                return true;
318            }
319            if (isTypeParameter(type)) {
320                return hasNullableSuperType(type);
321            }
322            return false;
323        }
324    
325        /**
326         * Differs from `isNullableType` only by treating type parameters: acceptsNullable(T) <=> T has nullable lower bound
327         * Semantics should be the same as `isSubtype(Nothing?, T)`
328         * @return true if `null` can be assigned to storage of this type
329         */
330        public static boolean acceptsNullable(@NotNull KotlinType type) {
331            if (type.isMarkedNullable()) {
332                return true;
333            }
334            if (FlexibleTypesKt.isFlexible(type) && acceptsNullable(FlexibleTypesKt.flexibility(type).getUpperBound())) {
335                return true;
336            }
337            return false;
338        }
339    
340        public static boolean hasNullableSuperType(@NotNull KotlinType type) {
341            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
342                // A class/trait cannot have a nullable supertype
343                return false;
344            }
345    
346            for (KotlinType supertype : getImmediateSupertypes(type)) {
347                if (supertype.isMarkedNullable()) return true;
348                if (hasNullableSuperType(supertype)) return true;
349            }
350    
351            return false;
352        }
353    
354        @Nullable
355        public static ClassDescriptor getClassDescriptor(@NotNull KotlinType type) {
356            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
357            if (declarationDescriptor instanceof ClassDescriptor) {
358                return (ClassDescriptor) declarationDescriptor;
359            }
360            return null;
361        }
362    
363        @NotNull
364        public static KotlinType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<KotlinType> typeArguments) {
365            List<TypeProjection> projections = CollectionsKt.map(typeArguments, new Function1<KotlinType, TypeProjection>() {
366                @Override
367                public TypeProjection invoke(KotlinType type) {
368                    return new TypeProjectionImpl(type);
369                }
370            });
371    
372            return substituteProjectionsForParameters(clazz, projections);
373        }
374    
375        @NotNull
376        public static KotlinType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
377            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
378            if (clazzTypeParameters.size() != projections.size()) {
379                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
380            }
381    
382            Map<TypeConstructor, TypeProjection> substitutions = org.jetbrains.kotlin.utils.CollectionsKt
383                    .newHashMapWithExpectedSize(clazzTypeParameters.size());
384    
385            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
386                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
387                substitutions.put(typeConstructor, projections.get(i));
388            }
389    
390            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
391        }
392    
393        public static boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b) {
394            return KotlinTypeChecker.DEFAULT.isSubtypeOf(a, b) && KotlinTypeChecker.DEFAULT.isSubtypeOf(b, a);
395        }
396    
397        public static boolean dependsOnTypeParameters(@NotNull KotlinType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
398            return dependsOnTypeConstructors(type, CollectionsKt.map(
399                    typeParameters,
400                    new Function1<TypeParameterDescriptor, TypeConstructor>() {
401                        @Override
402                        public TypeConstructor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
403                            return typeParameterDescriptor.getTypeConstructor();
404                        }
405                    }
406            ));
407        }
408    
409        public static boolean dependsOnTypeConstructors(@NotNull KotlinType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
410            if (typeParameterConstructors.contains(type.getConstructor())) return true;
411            for (TypeProjection typeProjection : type.getArguments()) {
412                if (!typeProjection.isStarProjection() && dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
413                    return true;
414                }
415            }
416            return false;
417        }
418    
419        public static boolean contains(@Nullable KotlinType type, @NotNull final KotlinType specialType) {
420            return contains(type, new Function1<KotlinType, Boolean>() {
421                @Override
422                public Boolean invoke(KotlinType type) {
423                    return specialType.equals(type);
424                }
425            });
426        }
427    
428        public static boolean contains(
429                @Nullable KotlinType type,
430                @NotNull Function1<KotlinType, Boolean> isSpecialType
431        ) {
432            if (type == null) return false;
433            if (isSpecialType.invoke(type)) return true;
434            Flexibility flexibility = type.getCapability(Flexibility.class);
435            if (flexibility != null
436                    && (contains(flexibility.getLowerBound(), isSpecialType) || contains(flexibility.getUpperBound(), isSpecialType))) {
437                return true;
438            }
439            for (TypeProjection projection : type.getArguments()) {
440                if (!projection.isStarProjection() && contains(projection.getType(), isSpecialType)) return true;
441            }
442            return false;
443        }
444    
445        @NotNull
446        public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
447            return new StarProjectionImpl(parameterDescriptor);
448        }
449    
450        @NotNull
451        public static KotlinType getDefaultPrimitiveNumberType(@NotNull IntegerValueTypeConstructor numberValueTypeConstructor) {
452            KotlinType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
453            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
454                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
455            return type;
456        }
457    
458        @Nullable
459        public static KotlinType getDefaultPrimitiveNumberType(@NotNull Collection<KotlinType> supertypes) {
460            if (supertypes.isEmpty()) {
461                return null;
462            }
463    
464            KotlinBuiltIns builtIns = supertypes.iterator().next().getConstructor().getBuiltIns();
465            KotlinType doubleType = builtIns.getDoubleType();
466            if (supertypes.contains(doubleType)) {
467                return doubleType;
468            }
469            KotlinType intType = builtIns.getIntType();
470            if (supertypes.contains(intType)) {
471                return intType;
472            }
473            KotlinType longType = builtIns.getLongType();
474            if (supertypes.contains(longType)) {
475                return longType;
476            }
477            return null;
478        }
479    
480        @NotNull
481        public static KotlinType getPrimitiveNumberType(
482                @NotNull IntegerValueTypeConstructor numberValueTypeConstructor,
483                @NotNull KotlinType expectedType
484        ) {
485            if (noExpectedType(expectedType) || expectedType.isError()) {
486                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
487            }
488            for (KotlinType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
489                if (KotlinTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
490                    return primitiveNumberType;
491                }
492            }
493            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
494        }
495    
496        public static boolean isTypeParameter(@NotNull KotlinType type) {
497            return getTypeParameterDescriptorOrNull(type) != null;
498        }
499    
500        public static boolean isNonReifiedTypeParemeter(@NotNull KotlinType type) {
501            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
502            return typeParameterDescriptor != null && !typeParameterDescriptor.isReified();
503        }
504    
505        public static boolean isReifiedTypeParameter(@NotNull KotlinType type) {
506            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
507            return typeParameterDescriptor != null && typeParameterDescriptor.isReified();
508        }
509    
510        @NotNull
511        public static KotlinType uncaptureTypeForInlineMapping(@NotNull KotlinType type) {
512            TypeConstructor constructor = type.getConstructor();
513            if (constructor instanceof CapturedTypeConstructor) {
514                TypeProjection projection = ((CapturedTypeConstructor) constructor).getTypeProjection();
515                if (Variance.IN_VARIANCE == projection.getProjectionKind()) {
516                    //in variance could be captured only for <T> or <T: Any?> declarations
517                    return TypeUtilsKt.getBuiltIns(type).getNullableAnyType();
518                }
519                return uncaptureTypeForInlineMapping(projection.getType());
520            }
521            return type;
522        }
523        @Nullable
524        public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull KotlinType type) {
525            assert !(type instanceof CapturedType) : "Type should be non-captured " + type;
526            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
527                return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor();
528            }
529            return null;
530        }
531    
532        private static abstract class AbstractTypeWithKnownNullability extends AbstractKotlinType {
533            private final KotlinType delegate;
534    
535            private AbstractTypeWithKnownNullability(@NotNull KotlinType delegate) {
536                this.delegate = delegate;
537            }
538    
539            @Override
540            @NotNull
541            public TypeConstructor getConstructor() {
542                return delegate.getConstructor();
543            }
544    
545            @Override
546            @NotNull
547            public List<TypeProjection> getArguments() {
548                return delegate.getArguments();
549            }
550    
551            @Override
552            public abstract boolean isMarkedNullable();
553    
554            @Override
555            @NotNull
556            public MemberScope getMemberScope() {
557                return delegate.getMemberScope();
558            }
559    
560            @Override
561            public boolean isError() {
562                return delegate.isError();
563            }
564    
565            @Override
566            @NotNull
567            public Annotations getAnnotations() {
568                return delegate.getAnnotations();
569            }
570    
571            @NotNull
572            @Override
573            public TypeSubstitution getSubstitution() {
574                return delegate.getSubstitution();
575            }
576    
577            @Nullable
578            @Override
579            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
580                return delegate.getCapability(capabilityClass);
581            }
582    
583            @NotNull
584            @Override
585            public TypeCapabilities getCapabilities() {
586                return delegate.getCapabilities();
587            }
588        }
589    
590        private static class NullableType extends AbstractTypeWithKnownNullability {
591    
592            private NullableType(@NotNull KotlinType delegate) {
593                super(delegate);
594            }
595    
596            @Override
597            public boolean isMarkedNullable() {
598                return true;
599            }
600        }
601    
602        private static class NotNullType extends AbstractTypeWithKnownNullability {
603    
604            private NotNullType(@NotNull KotlinType delegate) {
605                super(delegate);
606            }
607    
608            @Override
609            public boolean isMarkedNullable() {
610                return false;
611            }
612        }
613    
614    }