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