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.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            NullAwareness nullAwareness = type.getCapability(NullAwareness.class);
129            if (nullAwareness != null) {
130                return nullAwareness.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                Variance projectionKind = typeProjection.getProjectionKind();
172                KotlinType argument = typeProjection.getType();
173    
174                switch (parameterDescriptor.getVariance()) {
175                    case INVARIANT:
176                        switch (projectionKind) {
177                            case INVARIANT:
178                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
179                                    return true;
180                                }
181                                break;
182                            case IN_VARIANCE:
183                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
184                                    return true;
185                                }
186                                break;
187                            case OUT_VARIANCE:
188                                if (canHaveSubtypes(typeChecker, argument)) {
189                                    return true;
190                                }
191                                break;
192                        }
193                        break;
194                    case IN_VARIANCE:
195                        if (projectionKind != Variance.OUT_VARIANCE) {
196                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
197                                return true;
198                            }
199                        }
200                        else {
201                            if (canHaveSubtypes(typeChecker, argument)) {
202                                return true;
203                            }
204                        }
205                        break;
206                    case OUT_VARIANCE:
207                        if (projectionKind != Variance.IN_VARIANCE) {
208                            if (canHaveSubtypes(typeChecker, argument)) {
209                                return true;
210                            }
211                        }
212                        else {
213                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
214                                return true;
215                            }
216                        }
217                        break;
218                }
219            }
220            return false;
221        }
222    
223        private static boolean lowerThanBound(KotlinTypeChecker typeChecker, KotlinType argument, TypeParameterDescriptor parameterDescriptor) {
224            for (KotlinType bound : parameterDescriptor.getUpperBounds()) {
225                if (typeChecker.isSubtypeOf(argument, bound)) {
226                    if (!argument.getConstructor().equals(bound.getConstructor())) {
227                        return true;
228                    }
229                }
230            }
231            return false;
232        }
233    
234        @NotNull
235        public static KotlinType makeUnsubstitutedType(ClassDescriptor classDescriptor, MemberScope unsubstitutedMemberScope) {
236            if (ErrorUtils.isError(classDescriptor)) {
237                return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor);
238            }
239            TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
240            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
241            return KotlinTypeImpl.create(
242                    Annotations.Companion.getEMPTY(),
243                    typeConstructor,
244                    false,
245                    arguments,
246                    unsubstitutedMemberScope
247            );
248        }
249    
250        @NotNull
251        public static List<TypeProjection> getDefaultTypeProjections(@NotNull List<TypeParameterDescriptor> parameters) {
252            List<TypeProjection> result = new ArrayList<TypeProjection>(parameters.size());
253            for (TypeParameterDescriptor parameterDescriptor : parameters) {
254                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
255            }
256            return org.jetbrains.kotlin.utils.CollectionsKt.toReadOnlyList(result);
257        }
258    
259        @NotNull
260        public static List<KotlinType> getImmediateSupertypes(@NotNull KotlinType type) {
261            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
262            Collection<KotlinType> originalSupertypes = type.getConstructor().getSupertypes();
263            List<KotlinType> result = new ArrayList<KotlinType>(originalSupertypes.size());
264            for (KotlinType supertype : originalSupertypes) {
265                KotlinType substitutedType = createSubstitutedSupertype(type, supertype, substitutor);
266                if (substitutedType != null) {
267                    result.add(substitutedType);
268                }
269            }
270            return result;
271        }
272    
273        @Nullable
274        public static KotlinType createSubstitutedSupertype(
275                @NotNull KotlinType subType,
276                @NotNull KotlinType superType,
277                @NotNull TypeSubstitutor substitutor
278        ) {
279            KotlinType substitutedType = substitutor.substitute(superType, Variance.INVARIANT);
280            if (substitutedType != null) {
281                return makeNullableIfNeeded(substitutedType, subType.isMarkedNullable());
282            }
283            return null;
284        }
285    
286        private static void collectAllSupertypes(@NotNull KotlinType type, @NotNull Set<KotlinType> result) {
287            List<KotlinType> immediateSupertypes = getImmediateSupertypes(type);
288            result.addAll(immediateSupertypes);
289            for (KotlinType supertype : immediateSupertypes) {
290                collectAllSupertypes(supertype, result);
291            }
292        }
293    
294    
295        @NotNull
296        public static Set<KotlinType> getAllSupertypes(@NotNull KotlinType type) {
297            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
298            // the average number is lower
299            Set<KotlinType> result = new LinkedHashSet<KotlinType>(15);
300            collectAllSupertypes(type, result);
301            return result;
302        }
303    
304        public static boolean hasNullableLowerBound(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
305            for (KotlinType bound : typeParameterDescriptor.getLowerBounds()) {
306                if (bound.isMarkedNullable()) {
307                    return true;
308                }
309            }
310            return false;
311        }
312    
313        /**
314         * A work-around of the generic nullability problem in the type checker
315         * Semantics should be the same as `!isSubtype(T, Any)`
316         * @return true if a value of this type can be null
317         */
318        public static boolean isNullableType(@NotNull KotlinType type) {
319            if (type.isMarkedNullable()) {
320                return true;
321            }
322            if (FlexibleTypesKt.isFlexible(type) && isNullableType(FlexibleTypesKt.flexibility(type).getUpperBound())) {
323                return true;
324            }
325            if (isTypeParameter(type)) {
326                return hasNullableSuperType(type);
327            }
328            return false;
329        }
330    
331        /**
332         * Differs from `isNullableType` only by treating type parameters: acceptsNullable(T) <=> T has nullable lower bound
333         * Semantics should be the same as `isSubtype(Nothing?, T)`
334         * @return true if `null` can be assigned to storage of this type
335         */
336        public static boolean acceptsNullable(@NotNull KotlinType type) {
337            if (type.isMarkedNullable()) {
338                return true;
339            }
340            if (FlexibleTypesKt.isFlexible(type) && acceptsNullable(FlexibleTypesKt.flexibility(type).getUpperBound())) {
341                return true;
342            }
343            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
344            return typeParameterDescriptor != null && hasNullableLowerBound(typeParameterDescriptor);
345        }
346    
347        public static boolean hasNullableSuperType(@NotNull KotlinType type) {
348            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
349                // A class/trait cannot have a nullable supertype
350                return false;
351            }
352    
353            for (KotlinType supertype : getImmediateSupertypes(type)) {
354                if (supertype.isMarkedNullable()) return true;
355                if (hasNullableSuperType(supertype)) return true;
356            }
357    
358            return false;
359        }
360    
361        @Nullable
362        public static ClassDescriptor getClassDescriptor(@NotNull KotlinType type) {
363            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
364            if (declarationDescriptor instanceof ClassDescriptor) {
365                return (ClassDescriptor) declarationDescriptor;
366            }
367            return null;
368        }
369    
370        @NotNull
371        public static KotlinType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<KotlinType> typeArguments) {
372            List<TypeProjection> projections = CollectionsKt.map(typeArguments, new Function1<KotlinType, TypeProjection>() {
373                @Override
374                public TypeProjection invoke(KotlinType type) {
375                    return new TypeProjectionImpl(type);
376                }
377            });
378    
379            return substituteProjectionsForParameters(clazz, projections);
380        }
381    
382        @NotNull
383        public static KotlinType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
384            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
385            if (clazzTypeParameters.size() != projections.size()) {
386                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
387            }
388    
389            Map<TypeConstructor, TypeProjection> substitutions = org.jetbrains.kotlin.utils.CollectionsKt
390                    .newHashMapWithExpectedSize(clazzTypeParameters.size());
391    
392            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
393                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
394                substitutions.put(typeConstructor, projections.get(i));
395            }
396    
397            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
398        }
399    
400        public static boolean equalTypes(@NotNull KotlinType a, @NotNull KotlinType b) {
401            return KotlinTypeChecker.DEFAULT.isSubtypeOf(a, b) && KotlinTypeChecker.DEFAULT.isSubtypeOf(b, a);
402        }
403    
404        public static boolean dependsOnTypeParameters(@NotNull KotlinType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
405            return dependsOnTypeConstructors(type, CollectionsKt.map(
406                    typeParameters,
407                    new Function1<TypeParameterDescriptor, TypeConstructor>() {
408                        @Override
409                        public TypeConstructor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
410                            return typeParameterDescriptor.getTypeConstructor();
411                        }
412                    }
413            ));
414        }
415    
416        public static boolean dependsOnTypeConstructors(@NotNull KotlinType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
417            if (typeParameterConstructors.contains(type.getConstructor())) return true;
418            for (TypeProjection typeProjection : type.getArguments()) {
419                if (!typeProjection.isStarProjection() && dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
420                    return true;
421                }
422            }
423            return false;
424        }
425    
426        public static boolean containsSpecialType(@Nullable KotlinType type, @NotNull final KotlinType specialType) {
427            return containsSpecialType(type, new Function1<KotlinType, Boolean>() {
428                @Override
429                public Boolean invoke(KotlinType type) {
430                    return specialType.equals(type);
431                }
432            });
433        }
434    
435        public static boolean containsSpecialType(
436                @Nullable KotlinType type,
437                @NotNull Function1<KotlinType, Boolean> isSpecialType
438        ) {
439            if (type == null) return false;
440            if (isSpecialType.invoke(type)) return true;
441            Flexibility flexibility = type.getCapability(Flexibility.class);
442            if (flexibility != null
443                    && (containsSpecialType(flexibility.getLowerBound(), isSpecialType) || containsSpecialType(flexibility.getUpperBound(), isSpecialType))) {
444                return true;
445            }
446            for (TypeProjection projection : type.getArguments()) {
447                if (!projection.isStarProjection() && containsSpecialType(projection.getType(), isSpecialType)) return true;
448            }
449            return false;
450        }
451    
452        @NotNull
453        public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
454            return new StarProjectionImpl(parameterDescriptor);
455        }
456    
457        @NotNull
458        public static KotlinType getDefaultPrimitiveNumberType(@NotNull IntegerValueTypeConstructor numberValueTypeConstructor) {
459            KotlinType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
460            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
461                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
462            return type;
463        }
464    
465        @Nullable
466        public static KotlinType getDefaultPrimitiveNumberType(@NotNull Collection<KotlinType> supertypes) {
467            if (supertypes.isEmpty()) {
468                return null;
469            }
470    
471            KotlinBuiltIns builtIns = supertypes.iterator().next().getConstructor().getBuiltIns();
472            KotlinType doubleType = builtIns.getDoubleType();
473            if (supertypes.contains(doubleType)) {
474                return doubleType;
475            }
476            KotlinType intType = builtIns.getIntType();
477            if (supertypes.contains(intType)) {
478                return intType;
479            }
480            KotlinType longType = builtIns.getLongType();
481            if (supertypes.contains(longType)) {
482                return longType;
483            }
484            return null;
485        }
486    
487        @NotNull
488        public static KotlinType getPrimitiveNumberType(
489                @NotNull IntegerValueTypeConstructor numberValueTypeConstructor,
490                @NotNull KotlinType expectedType
491        ) {
492            if (noExpectedType(expectedType) || expectedType.isError()) {
493                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
494            }
495            for (KotlinType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
496                if (KotlinTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
497                    return primitiveNumberType;
498                }
499            }
500            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
501        }
502    
503        public static boolean isTypeParameter(@NotNull KotlinType type) {
504            return getTypeParameterDescriptorOrNull(type) != null;
505        }
506    
507        public static boolean isNonReifiedTypeParemeter(@NotNull KotlinType type) {
508            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
509            return typeParameterDescriptor != null && !typeParameterDescriptor.isReified();
510        }
511    
512        public static boolean isReifiedTypeParameter(@NotNull KotlinType type) {
513            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
514            return typeParameterDescriptor != null && typeParameterDescriptor.isReified();
515        }
516    
517        @Nullable
518        public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull KotlinType type) {
519            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
520                return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor();
521            }
522            return null;
523        }
524    
525        private static abstract class AbstractTypeWithKnownNullability extends AbstractKotlinType {
526            private final KotlinType delegate;
527    
528            private AbstractTypeWithKnownNullability(@NotNull KotlinType delegate) {
529                this.delegate = delegate;
530            }
531    
532            @Override
533            @NotNull
534            public TypeConstructor getConstructor() {
535                return delegate.getConstructor();
536            }
537    
538            @Override
539            @NotNull
540            public List<TypeProjection> getArguments() {
541                return delegate.getArguments();
542            }
543    
544            @Override
545            public abstract boolean isMarkedNullable();
546    
547            @Override
548            @NotNull
549            public MemberScope getMemberScope() {
550                return delegate.getMemberScope();
551            }
552    
553            @Override
554            public boolean isError() {
555                return delegate.isError();
556            }
557    
558            @Override
559            @NotNull
560            public Annotations getAnnotations() {
561                return delegate.getAnnotations();
562            }
563    
564            @NotNull
565            @Override
566            public TypeSubstitution getSubstitution() {
567                return delegate.getSubstitution();
568            }
569    
570            @Nullable
571            @Override
572            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
573                return delegate.getCapability(capabilityClass);
574            }
575    
576            @NotNull
577            @Override
578            public TypeCapabilities getCapabilities() {
579                return delegate.getCapabilities();
580            }
581        }
582    
583        private static class NullableType extends AbstractTypeWithKnownNullability {
584    
585            private NullableType(@NotNull KotlinType delegate) {
586                super(delegate);
587            }
588    
589            @Override
590            public boolean isMarkedNullable() {
591                return true;
592            }
593        }
594    
595        private static class NotNullType extends AbstractTypeWithKnownNullability {
596    
597            private NotNullType(@NotNull KotlinType delegate) {
598                super(delegate);
599            }
600    
601            @Override
602            public boolean isMarkedNullable() {
603                return false;
604            }
605        }
606    
607    }