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