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.ClassifierDescriptor;
026    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
027    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
028    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
029    import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
030    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
031    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
032    
033    import java.util.*;
034    
035    public class TypeUtils {
036        public static final SimpleType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
037        public static final SimpleType CANT_INFER_FUNCTION_PARAM_TYPE = ErrorUtils.createErrorType("Cannot be inferred");
038    
039        public static class SpecialType extends DelegatingSimpleType {
040            private final String name;
041    
042            public SpecialType(String name) {
043                this.name = name;
044            }
045    
046            @NotNull
047            @Override
048            protected SimpleType getDelegate() {
049                throw new IllegalStateException(name);
050            }
051    
052            @Override
053            public boolean isError() {
054                return false;
055            }
056    
057            @NotNull
058            @Override
059            public SimpleType replaceAnnotations(@NotNull Annotations newAnnotations) {
060                throw new IllegalStateException(name);
061            }
062    
063            @NotNull
064            @Override
065            public SimpleType makeNullableAsSpecified(boolean newNullability) {
066                throw new IllegalStateException(name);
067            }
068    
069            @Override
070            public String toString() {
071                return name;
072            }
073        }
074    
075        @NotNull
076        public static final SimpleType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
077    
078        public static final SimpleType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
079    
080        public static boolean noExpectedType(@NotNull KotlinType type) {
081            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
082        }
083    
084        public static boolean isDontCarePlaceholder(@Nullable KotlinType type) {
085            return type != null && type.getConstructor() == DONT_CARE.getConstructor();
086        }
087    
088        @NotNull
089        public static KotlinType makeNullable(@NotNull KotlinType type) {
090            return makeNullableAsSpecified(type, true);
091        }
092    
093        @NotNull
094        public static KotlinType makeNotNullable(@NotNull KotlinType type) {
095            return makeNullableAsSpecified(type, false);
096        }
097    
098        @NotNull
099        public static KotlinType makeNullableAsSpecified(@NotNull KotlinType type, boolean nullable) {
100            return type.unwrap().makeNullableAsSpecified(nullable);
101        }
102    
103        @NotNull
104        public static SimpleType makeNullableIfNeeded(@NotNull SimpleType type, boolean nullable) {
105            if (nullable) {
106                return type.makeNullableAsSpecified(true);
107            }
108            return type;
109        }
110    
111        @NotNull
112        public static KotlinType makeNullableIfNeeded(@NotNull KotlinType type, boolean nullable) {
113            if (nullable) {
114                return makeNullable(type);
115            }
116            return type;
117        }
118    
119        public static boolean canHaveSubtypes(KotlinTypeChecker typeChecker, @NotNull KotlinType type) {
120            if (type.isMarkedNullable()) {
121                return true;
122            }
123            if (!type.getConstructor().isFinal()) {
124                return true;
125            }
126    
127            List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
128            List<TypeProjection> arguments = type.getArguments();
129            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
130                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
131                TypeProjection typeProjection = arguments.get(i);
132                if (typeProjection.isStarProjection()) return true;
133    
134                Variance projectionKind = typeProjection.getProjectionKind();
135                KotlinType argument = typeProjection.getType();
136    
137                switch (parameterDescriptor.getVariance()) {
138                    case INVARIANT:
139                        switch (projectionKind) {
140                            case INVARIANT:
141                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
142                                    return true;
143                                }
144                                break;
145                            case IN_VARIANCE:
146                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
147                                    return true;
148                                }
149                                break;
150                            case OUT_VARIANCE:
151                                if (canHaveSubtypes(typeChecker, argument)) {
152                                    return true;
153                                }
154                                break;
155                        }
156                        break;
157                    case IN_VARIANCE:
158                        if (projectionKind != Variance.OUT_VARIANCE) {
159                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
160                                return true;
161                            }
162                        }
163                        else {
164                            if (canHaveSubtypes(typeChecker, argument)) {
165                                return true;
166                            }
167                        }
168                        break;
169                    case OUT_VARIANCE:
170                        if (projectionKind != Variance.IN_VARIANCE) {
171                            if (canHaveSubtypes(typeChecker, argument)) {
172                                return true;
173                            }
174                        }
175                        else {
176                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
177                                return true;
178                            }
179                        }
180                        break;
181                }
182            }
183            return false;
184        }
185    
186        private static boolean lowerThanBound(KotlinTypeChecker typeChecker, KotlinType argument, TypeParameterDescriptor parameterDescriptor) {
187            for (KotlinType bound : parameterDescriptor.getUpperBounds()) {
188                if (typeChecker.isSubtypeOf(argument, bound)) {
189                    if (!argument.getConstructor().equals(bound.getConstructor())) {
190                        return true;
191                    }
192                }
193            }
194            return false;
195        }
196    
197        @NotNull
198        public static SimpleType makeUnsubstitutedType(ClassifierDescriptor classifierDescriptor, MemberScope unsubstitutedMemberScope) {
199            if (ErrorUtils.isError(classifierDescriptor)) {
200                return ErrorUtils.createErrorType("Unsubstituted type for " + classifierDescriptor);
201            }
202            TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
203            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
204            return KotlinTypeFactory.simpleType(
205                    Annotations.Companion.getEMPTY(),
206                    typeConstructor,
207                    arguments,
208                    false,
209                    unsubstitutedMemberScope
210            );
211        }
212    
213        @NotNull
214        public static List<TypeProjection> getDefaultTypeProjections(@NotNull List<TypeParameterDescriptor> parameters) {
215            List<TypeProjection> result = new ArrayList<TypeProjection>(parameters.size());
216            for (TypeParameterDescriptor parameterDescriptor : parameters) {
217                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
218            }
219            return org.jetbrains.kotlin.utils.CollectionsKt.toReadOnlyList(result);
220        }
221    
222        @NotNull
223        public static List<KotlinType> getImmediateSupertypes(@NotNull KotlinType type) {
224            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
225            Collection<KotlinType> originalSupertypes = type.getConstructor().getSupertypes();
226            List<KotlinType> result = new ArrayList<KotlinType>(originalSupertypes.size());
227            for (KotlinType supertype : originalSupertypes) {
228                KotlinType substitutedType = createSubstitutedSupertype(type, supertype, substitutor);
229                if (substitutedType != null) {
230                    result.add(substitutedType);
231                }
232            }
233            return result;
234        }
235    
236        @Nullable
237        public static KotlinType createSubstitutedSupertype(
238                @NotNull KotlinType subType,
239                @NotNull KotlinType superType,
240                @NotNull TypeSubstitutor substitutor
241        ) {
242            KotlinType substitutedType = substitutor.substitute(superType, Variance.INVARIANT);
243            if (substitutedType != null) {
244                return makeNullableIfNeeded(substitutedType, subType.isMarkedNullable());
245            }
246            return null;
247        }
248    
249        private static void collectAllSupertypes(@NotNull KotlinType type, @NotNull Set<KotlinType> result) {
250            List<KotlinType> immediateSupertypes = getImmediateSupertypes(type);
251            result.addAll(immediateSupertypes);
252            for (KotlinType supertype : immediateSupertypes) {
253                collectAllSupertypes(supertype, result);
254            }
255        }
256    
257    
258        @NotNull
259        public static Set<KotlinType> getAllSupertypes(@NotNull KotlinType type) {
260            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
261            // the average number is lower
262            Set<KotlinType> result = new LinkedHashSet<KotlinType>(15);
263            collectAllSupertypes(type, result);
264            return result;
265        }
266    
267        /**
268         * A work-around of the generic nullability problem in the type checker
269         * Semantics should be the same as `!isSubtype(T, Any)`
270         * @return true if a value of this type can be null
271         */
272        public static boolean isNullableType(@NotNull KotlinType type) {
273            if (type.isMarkedNullable()) {
274                return true;
275            }
276            if (FlexibleTypesKt.isFlexible(type) && isNullableType(FlexibleTypesKt.asFlexibleType(type).getUpperBound())) {
277                return true;
278            }
279            if (isTypeParameter(type)) {
280                return hasNullableSuperType(type);
281            }
282            return false;
283        }
284    
285        /**
286         * Differs from `isNullableType` only by treating type parameters: acceptsNullable(T) <=> T has nullable lower bound
287         * Semantics should be the same as `isSubtype(Nothing?, T)`
288         * @return true if `null` can be assigned to storage of this type
289         */
290        public static boolean acceptsNullable(@NotNull KotlinType type) {
291            if (type.isMarkedNullable()) {
292                return true;
293            }
294            if (FlexibleTypesKt.isFlexible(type) && acceptsNullable(FlexibleTypesKt.asFlexibleType(type).getUpperBound())) {
295                return true;
296            }
297            return false;
298        }
299    
300        public static boolean hasNullableSuperType(@NotNull KotlinType type) {
301            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
302                // A class/trait cannot have a nullable supertype
303                return false;
304            }
305    
306            for (KotlinType supertype : getImmediateSupertypes(type)) {
307                if (isNullableType(supertype)) return true;
308            }
309    
310            return false;
311        }
312    
313        @Nullable
314        public static ClassDescriptor getClassDescriptor(@NotNull KotlinType type) {
315            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
316            if (declarationDescriptor instanceof ClassDescriptor) {
317                return (ClassDescriptor) declarationDescriptor;
318            }
319            return null;
320        }
321    
322        @NotNull
323        public static KotlinType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<KotlinType> typeArguments) {
324            List<TypeProjection> projections = CollectionsKt.map(typeArguments, new Function1<KotlinType, TypeProjection>() {
325                @Override
326                public TypeProjection invoke(KotlinType type) {
327                    return new TypeProjectionImpl(type);
328                }
329            });
330    
331            return substituteProjectionsForParameters(clazz, projections);
332        }
333    
334        @NotNull
335        public static KotlinType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
336            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
337            if (clazzTypeParameters.size() != projections.size()) {
338                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
339            }
340    
341            Map<TypeConstructor, TypeProjection> substitutions = org.jetbrains.kotlin.utils.CollectionsKt
342                    .newHashMapWithExpectedSize(clazzTypeParameters.size());
343    
344            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
345                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
346                substitutions.put(typeConstructor, projections.get(i));
347            }
348    
349            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
350        }
351    
352        public static boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b) {
353            return KotlinTypeChecker.DEFAULT.isSubtypeOf(a, b) && KotlinTypeChecker.DEFAULT.isSubtypeOf(b, a);
354        }
355    
356        public static boolean dependsOnTypeParameters(@NotNull KotlinType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
357            return dependsOnTypeConstructors(type, CollectionsKt.map(
358                    typeParameters,
359                    new Function1<TypeParameterDescriptor, TypeConstructor>() {
360                        @Override
361                        public TypeConstructor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
362                            return typeParameterDescriptor.getTypeConstructor();
363                        }
364                    }
365            ));
366        }
367    
368        public static boolean dependsOnTypeConstructors(@NotNull KotlinType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
369            if (typeParameterConstructors.contains(type.getConstructor())) return true;
370            for (TypeProjection typeProjection : type.getArguments()) {
371                if (!typeProjection.isStarProjection() && dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
372                    return true;
373                }
374            }
375            return false;
376        }
377    
378        public static boolean contains(@Nullable KotlinType type, @NotNull final KotlinType specialType) {
379            return contains(type, new Function1<UnwrappedType, Boolean>() {
380                @Override
381                public Boolean invoke(UnwrappedType type) {
382                    return specialType.equals(type);
383                }
384            });
385        }
386    
387        public static boolean contains(
388                @Nullable KotlinType type,
389                @NotNull Function1<UnwrappedType, Boolean> isSpecialType
390        ) {
391            if (type == null) return false;
392    
393            UnwrappedType unwrappedType = type.unwrap();
394            if (isSpecialType.invoke(unwrappedType)) return true;
395    
396            FlexibleType flexibleType = unwrappedType instanceof FlexibleType ? (FlexibleType) unwrappedType : null;
397            if (flexibleType != null
398                && (contains(flexibleType.getLowerBound(), isSpecialType) || contains(flexibleType.getUpperBound(), isSpecialType))) {
399                return true;
400            }
401            for (TypeProjection projection : type.getArguments()) {
402                if (!projection.isStarProjection() && contains(projection.getType(), isSpecialType)) return true;
403            }
404            return false;
405        }
406    
407        @NotNull
408        public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
409            return new StarProjectionImpl(parameterDescriptor);
410        }
411    
412        @NotNull
413        public static KotlinType getDefaultPrimitiveNumberType(@NotNull IntegerValueTypeConstructor numberValueTypeConstructor) {
414            KotlinType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
415            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
416                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
417            return type;
418        }
419    
420        @Nullable
421        public static KotlinType getDefaultPrimitiveNumberType(@NotNull Collection<KotlinType> supertypes) {
422            if (supertypes.isEmpty()) {
423                return null;
424            }
425    
426            KotlinBuiltIns builtIns = supertypes.iterator().next().getConstructor().getBuiltIns();
427            KotlinType doubleType = builtIns.getDoubleType();
428            if (supertypes.contains(doubleType)) {
429                return doubleType;
430            }
431            KotlinType intType = builtIns.getIntType();
432            if (supertypes.contains(intType)) {
433                return intType;
434            }
435            KotlinType longType = builtIns.getLongType();
436            if (supertypes.contains(longType)) {
437                return longType;
438            }
439            return null;
440        }
441    
442        @NotNull
443        public static KotlinType getPrimitiveNumberType(
444                @NotNull IntegerValueTypeConstructor numberValueTypeConstructor,
445                @NotNull KotlinType expectedType
446        ) {
447            if (noExpectedType(expectedType) || expectedType.isError()) {
448                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
449            }
450            for (KotlinType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
451                if (KotlinTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
452                    return primitiveNumberType;
453                }
454            }
455            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
456        }
457    
458        public static boolean isTypeParameter(@NotNull KotlinType type) {
459            return getTypeParameterDescriptorOrNull(type) != null;
460        }
461    
462        public static boolean isReifiedTypeParameter(@NotNull KotlinType type) {
463            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
464            return typeParameterDescriptor != null && typeParameterDescriptor.isReified();
465        }
466    
467        public static boolean isNonReifiedTypeParameter(@NotNull KotlinType type) {
468            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
469            return typeParameterDescriptor != null && !typeParameterDescriptor.isReified();
470        }
471    
472        @Nullable
473        public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull KotlinType type) {
474            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
475                return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor();
476            }
477            return null;
478        }
479    }