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 }