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.KotlinPackage;
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.JetScope;
030    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
031    import org.jetbrains.kotlin.utils.DFS;
032    import org.jetbrains.kotlin.utils.UtilsPackage;
033    
034    import java.util.*;
035    
036    public class TypeUtils {
037        public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
038        public static final JetType PLACEHOLDER_FUNCTION_TYPE = ErrorUtils.createErrorTypeWithCustomDebugName("PLACEHOLDER_FUNCTION_TYPE");
039    
040        public static final JetType CANT_INFER_FUNCTION_PARAM_TYPE = ErrorUtils.createErrorType("Cannot be inferred");
041    
042        public static class SpecialType implements JetType {
043            private final String name;
044    
045            public SpecialType(String name) {
046                this.name = name;
047            }
048    
049            @NotNull
050            @Override
051            public TypeConstructor getConstructor() {
052                throw new IllegalStateException(name);
053            }
054    
055            @NotNull
056            @Override
057            public List<TypeProjection> getArguments() {
058                throw new IllegalStateException(name);
059            }
060    
061            @NotNull
062            @Override
063            public TypeSubstitution getSubstitution() {
064                throw new IllegalStateException(name);
065            }
066    
067            @Override
068            public boolean isMarkedNullable() {
069                throw new IllegalStateException(name);
070            }
071    
072            @NotNull
073            @Override
074            public JetScope getMemberScope() {
075                throw new IllegalStateException(name);
076            }
077    
078            @Override
079            public boolean isError() {
080                return false;
081            }
082    
083            @NotNull
084            @Override
085            public Annotations getAnnotations() {
086                throw new IllegalStateException(name);
087            }
088    
089            @Nullable
090            @Override
091            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
092                return null;
093            }
094    
095            @NotNull
096            @Override
097            public TypeCapabilities getCapabilities() {
098                return TypeCapabilities.NONE.INSTANCE$;
099            }
100    
101            @Override
102            public String toString() {
103                return name;
104            }
105        }
106    
107        public static final JetType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
108    
109        public static final JetType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
110    
111        public static boolean noExpectedType(@NotNull JetType type) {
112            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
113        }
114    
115        public static boolean isDontCarePlaceholder(@Nullable JetType type) {
116            return type != null && type.getConstructor() == DONT_CARE.getConstructor();
117        }
118    
119        @NotNull
120        public static JetType makeNullable(@NotNull JetType type) {
121            return makeNullableAsSpecified(type, true);
122        }
123    
124        @NotNull
125        public static JetType makeNotNullable(@NotNull JetType type) {
126            return makeNullableAsSpecified(type, false);
127        }
128    
129        @NotNull
130        public static JetType makeNullableAsSpecified(@NotNull JetType type, boolean nullable) {
131            NullAwareness nullAwareness = type.getCapability(NullAwareness.class);
132            if (nullAwareness != null) {
133                return nullAwareness.makeNullableAsSpecified(nullable);
134            }
135    
136            // Wrapping serves two purposes here
137            // 1. It's requires less memory than copying with a changed nullability flag: a copy has many fields, while a wrapper has only one
138            // 2. It preserves laziness of types
139    
140            // Unwrap to avoid long delegation call chains
141            if (type instanceof AbstractTypeWithKnownNullability) {
142                return makeNullableAsSpecified(((AbstractTypeWithKnownNullability) type).delegate, nullable);
143            }
144    
145            // checking to preserve laziness
146            if (!(type instanceof LazyType) && type.isMarkedNullable() == nullable) {
147                return type;
148            }
149    
150            return nullable ? new NullableType(type) : new NotNullType(type);
151        }
152    
153        @NotNull
154        public static JetType makeNullableIfNeeded(@NotNull JetType type, boolean nullable) {
155            if (nullable) {
156                return makeNullable(type);
157            }
158            return type;
159        }
160    
161        public static boolean canHaveSubtypes(JetTypeChecker typeChecker, @NotNull JetType type) {
162            if (type.isMarkedNullable()) {
163                return true;
164            }
165            if (!type.getConstructor().isFinal()) {
166                return true;
167            }
168    
169            List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
170            List<TypeProjection> arguments = type.getArguments();
171            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
172                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
173                TypeProjection typeProjection = arguments.get(i);
174                Variance projectionKind = typeProjection.getProjectionKind();
175                JetType argument = typeProjection.getType();
176    
177                switch (parameterDescriptor.getVariance()) {
178                    case INVARIANT:
179                        switch (projectionKind) {
180                            case INVARIANT:
181                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
182                                    return true;
183                                }
184                                break;
185                            case IN_VARIANCE:
186                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
187                                    return true;
188                                }
189                                break;
190                            case OUT_VARIANCE:
191                                if (canHaveSubtypes(typeChecker, argument)) {
192                                    return true;
193                                }
194                                break;
195                        }
196                        break;
197                    case IN_VARIANCE:
198                        if (projectionKind != Variance.OUT_VARIANCE) {
199                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
200                                return true;
201                            }
202                        }
203                        else {
204                            if (canHaveSubtypes(typeChecker, argument)) {
205                                return true;
206                            }
207                        }
208                        break;
209                    case OUT_VARIANCE:
210                        if (projectionKind != Variance.IN_VARIANCE) {
211                            if (canHaveSubtypes(typeChecker, argument)) {
212                                return true;
213                            }
214                        }
215                        else {
216                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
217                                return true;
218                            }
219                        }
220                        break;
221                }
222            }
223            return false;
224        }
225    
226        private static boolean lowerThanBound(JetTypeChecker typeChecker, JetType argument, TypeParameterDescriptor parameterDescriptor) {
227            for (JetType bound : parameterDescriptor.getUpperBounds()) {
228                if (typeChecker.isSubtypeOf(argument, bound)) {
229                    if (!argument.getConstructor().equals(bound.getConstructor())) {
230                        return true;
231                    }
232                }
233            }
234            return false;
235        }
236    
237        @NotNull
238        public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
239            if (ErrorUtils.isError(classDescriptor)) {
240                return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor);
241            }
242            TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
243            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
244            return JetTypeImpl.create(
245                    Annotations.EMPTY,
246                    typeConstructor,
247                    false,
248                    arguments,
249                    unsubstitutedMemberScope
250            );
251        }
252    
253        @NotNull
254        public static List<TypeProjection> getDefaultTypeProjections(@NotNull List<TypeParameterDescriptor> parameters) {
255            List<TypeProjection> result = new ArrayList<TypeProjection>(parameters.size());
256            for (TypeParameterDescriptor parameterDescriptor : parameters) {
257                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
258            }
259            return UtilsPackage.toReadOnlyList(result);
260        }
261    
262        @NotNull
263        public static List<JetType> getImmediateSupertypes(@NotNull JetType type) {
264            boolean isNullable = type.isMarkedNullable();
265            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
266            Collection<JetType> originalSupertypes = type.getConstructor().getSupertypes();
267            List<JetType> result = new ArrayList<JetType>(originalSupertypes.size());
268            for (JetType supertype : originalSupertypes) {
269                JetType substitutedType = substitutor.substitute(supertype, Variance.INVARIANT);
270                if (substitutedType != null) {
271                    result.add(makeNullableIfNeeded(substitutedType, isNullable));
272                }
273            }
274            return result;
275        }
276    
277        private static void collectAllSupertypes(@NotNull JetType type, @NotNull Set<JetType> result) {
278            List<JetType> immediateSupertypes = getImmediateSupertypes(type);
279            result.addAll(immediateSupertypes);
280            for (JetType supertype : immediateSupertypes) {
281                collectAllSupertypes(supertype, result);
282            }
283        }
284    
285    
286        @NotNull
287        public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
288            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
289            // the average number is lower
290            Set<JetType> result = new LinkedHashSet<JetType>(15);
291            collectAllSupertypes(type, result);
292            return result;
293        }
294    
295        public static boolean hasNullableLowerBound(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
296            for (JetType bound : typeParameterDescriptor.getLowerBounds()) {
297                if (bound.isMarkedNullable()) {
298                    return true;
299                }
300            }
301            return false;
302        }
303    
304        /**
305         * A work-around of the generic nullability problem in the type checker
306         * Semantics should be the same as `!isSubtype(T, Any)`
307         * @return true if a value of this type can be null
308         */
309        public static boolean isNullableType(@NotNull JetType type) {
310            if (type.isMarkedNullable()) {
311                return true;
312            }
313            if (TypesPackage.isFlexible(type) && isNullableType(TypesPackage.flexibility(type).getUpperBound())) {
314                return true;
315            }
316            if (isTypeParameter(type)) {
317                return hasNullableSuperType(type);
318            }
319            return false;
320        }
321    
322        /**
323         * Differs from `isNullableType` only by treating type parameters: acceptsNullable(T) <=> T has nullable lower bound
324         * Semantics should be the same as `isSubtype(Nothing?, T)`
325         * @return true if `null` can be assigned to storage of this type
326         */
327        public static boolean acceptsNullable(@NotNull JetType type) {
328            if (type.isMarkedNullable()) {
329                return true;
330            }
331            if (TypesPackage.isFlexible(type) && acceptsNullable(TypesPackage.flexibility(type).getUpperBound())) {
332                return true;
333            }
334            if (isTypeParameter(type)) {
335                return hasNullableLowerBound((TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor());
336            }
337            return false;
338        }
339    
340        public static boolean hasNullableSuperType(@NotNull JetType type) {
341            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
342                // A class/trait cannot have a nullable supertype
343                return false;
344            }
345    
346            for (JetType supertype : getImmediateSupertypes(type)) {
347                if (supertype.isMarkedNullable()) return true;
348                if (hasNullableSuperType(supertype)) return true;
349            }
350    
351            return false;
352        }
353    
354        @Nullable
355        public static ClassDescriptor getClassDescriptor(@NotNull JetType type) {
356            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
357            if (declarationDescriptor instanceof ClassDescriptor) {
358                return (ClassDescriptor) declarationDescriptor;
359            }
360            return null;
361        }
362    
363        @NotNull
364        public static JetType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<JetType> typeArguments) {
365            List<TypeProjection> projections = KotlinPackage.map(typeArguments, new Function1<JetType, TypeProjection>() {
366                @Override
367                public TypeProjection invoke(JetType type) {
368                    return new TypeProjectionImpl(type);
369                }
370            });
371    
372            return substituteProjectionsForParameters(clazz, projections);
373        }
374    
375        @NotNull
376        public static JetType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
377            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
378            if (clazzTypeParameters.size() != projections.size()) {
379                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
380            }
381    
382            Map<TypeConstructor, TypeProjection> substitutions = UtilsPackage.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 JetType a, @NotNull JetType b) {
393            return JetTypeChecker.DEFAULT.isSubtypeOf(a, b) && JetTypeChecker.DEFAULT.isSubtypeOf(b, a);
394        }
395    
396        public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
397            return dependsOnTypeConstructors(type, KotlinPackage.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 JetType 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 containsSpecialType(@Nullable JetType type, @NotNull final JetType specialType) {
419            return containsSpecialType(type, new Function1<JetType, Boolean>() {
420                @Override
421                public Boolean invoke(JetType type) {
422                    return specialType.equals(type);
423                }
424            });
425        }
426    
427        public static boolean containsSpecialType(
428                @Nullable JetType type,
429                @NotNull Function1<JetType, 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                    && (containsSpecialType(flexibility.getLowerBound(), isSpecialType) || containsSpecialType(flexibility.getUpperBound(), isSpecialType))) {
436                return true;
437            }
438            for (TypeProjection projection : type.getArguments()) {
439                if (!projection.isStarProjection() && containsSpecialType(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        @Nullable
450        public static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
451            if (numberLowerBounds.isEmpty()) return null;
452            Set<JetType> intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds);
453            JetType primitiveNumberType = getDefaultPrimitiveNumberType(intersectionOfSupertypes);
454            if (primitiveNumberType != null) {
455                return primitiveNumberType;
456            }
457            return CommonSupertypes.commonSupertype(numberLowerBounds);
458        }
459    
460        @NotNull
461        private static Set<JetType> getIntersectionOfSupertypes(@NotNull Collection<JetType> types) {
462            Set<JetType> upperBounds = new HashSet<JetType>();
463            for (JetType type : types) {
464                Collection<JetType> supertypes = type.getConstructor().getSupertypes();
465                if (upperBounds.isEmpty()) {
466                    upperBounds.addAll(supertypes);
467                }
468                else {
469                    upperBounds.retainAll(supertypes);
470                }
471            }
472            return upperBounds;
473        }
474    
475        @NotNull
476        public static JetType getDefaultPrimitiveNumberType(@NotNull IntegerValueTypeConstructor numberValueTypeConstructor) {
477            JetType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
478            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
479                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
480            return type;
481        }
482    
483        @Nullable
484        private static JetType getDefaultPrimitiveNumberType(@NotNull Collection<JetType> supertypes) {
485            JetType doubleType = KotlinBuiltIns.getInstance().getDoubleType();
486            if (supertypes.contains(doubleType)) {
487                return doubleType;
488            }
489            JetType intType = KotlinBuiltIns.getInstance().getIntType();
490            if (supertypes.contains(intType)) {
491                return intType;
492            }
493            JetType longType = KotlinBuiltIns.getInstance().getLongType();
494            if (supertypes.contains(longType)) {
495                return longType;
496            }
497            return null;
498        }
499    
500        @NotNull
501        public static JetType getPrimitiveNumberType(
502                @NotNull IntegerValueTypeConstructor numberValueTypeConstructor,
503                @NotNull JetType expectedType
504        ) {
505            if (noExpectedType(expectedType) || expectedType.isError()) {
506                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
507            }
508            for (JetType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
509                if (JetTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
510                    return primitiveNumberType;
511                }
512            }
513            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
514        }
515    
516        public static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
517                @NotNull JetType type,
518                @NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances,
519                @NotNull final Set<TypeConstructor> visited
520        ) {
521            return DFS.dfs(
522                    Collections.singletonList(type),
523                    new DFS.Neighbors<JetType>() {
524                        @NotNull
525                        @Override
526                        public Iterable<JetType> getNeighbors(JetType current) {
527                            TypeSubstitutor substitutor = TypeSubstitutor.create(current);
528                            Collection<JetType> supertypes = current.getConstructor().getSupertypes();
529                            List<JetType> result = new ArrayList<JetType>(supertypes.size());
530                            for (JetType supertype : supertypes) {
531                                if (visited.contains(supertype.getConstructor())) {
532                                    continue;
533                                }
534                                result.add(substitutor.safeSubstitute(supertype, Variance.INVARIANT));
535                            }
536                            return result;
537                        }
538                    },
539                    new DFS.Visited<JetType>() {
540                        @Override
541                        public boolean checkAndMarkVisited(JetType current) {
542                            return visited.add(current.getConstructor());
543                        }
544                    },
545                    new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() {
546                        @Override
547                        public boolean beforeChildren(JetType current) {
548                            TypeConstructor constructor = current.getConstructor();
549    
550                            Set<JetType> instances = constructorToAllInstances.get(constructor);
551                            if (instances == null) {
552                                instances = new HashSet<JetType>();
553                                constructorToAllInstances.put(constructor, instances);
554                            }
555                            instances.add(current);
556    
557                            return true;
558                        }
559    
560                        @Override
561                        public void afterChildren(JetType current) {
562                            result.addFirst(current.getConstructor());
563                        }
564                    }
565            );
566        }
567    
568        public static TypeSubstitutor makeConstantSubstitutor(Collection<TypeParameterDescriptor> typeParameterDescriptors, JetType type) {
569            final Set<TypeConstructor> constructors = UtilsPackage.newHashSetWithExpectedSize(typeParameterDescriptors.size());
570            for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
571                constructors.add(typeParameterDescriptor.getTypeConstructor());
572            }
573            final TypeProjection projection = new TypeProjectionImpl(type);
574    
575            return TypeSubstitutor.create(new TypeConstructorSubstitution() {
576                @Override
577                public TypeProjection get(@NotNull TypeConstructor key) {
578                    if (constructors.contains(key)) {
579                        return projection;
580                    }
581                    return null;
582                }
583    
584                @Override
585                public boolean isEmpty() {
586                    return false;
587                }
588            });
589        }
590    
591        public static boolean isTypeParameter(@NotNull JetType type) {
592            return getTypeParameterDescriptorOrNull(type) != null;
593        }
594    
595        public static boolean isNonReifiedTypeParemeter(@NotNull JetType type) {
596            TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type);
597            return typeParameterDescriptor != null && !typeParameterDescriptor.isReified();
598        }
599    
600        @Nullable
601        public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull JetType type) {
602            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
603                return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor();
604            }
605            return null;
606        }
607    
608        private static abstract class AbstractTypeWithKnownNullability extends AbstractJetType {
609            private final JetType delegate;
610    
611            private AbstractTypeWithKnownNullability(@NotNull JetType delegate) {
612                this.delegate = delegate;
613            }
614    
615            @Override
616            @NotNull
617            public TypeConstructor getConstructor() {
618                return delegate.getConstructor();
619            }
620    
621            @Override
622            @NotNull
623            public List<TypeProjection> getArguments() {
624                return delegate.getArguments();
625            }
626    
627            @Override
628            public abstract boolean isMarkedNullable();
629    
630            @Override
631            @NotNull
632            public JetScope getMemberScope() {
633                return delegate.getMemberScope();
634            }
635    
636            @Override
637            public boolean isError() {
638                return delegate.isError();
639            }
640    
641            @Override
642            @NotNull
643            public Annotations getAnnotations() {
644                return delegate.getAnnotations();
645            }
646    
647            @NotNull
648            @Override
649            public TypeSubstitution getSubstitution() {
650                return delegate.getSubstitution();
651            }
652    
653            @Nullable
654            @Override
655            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
656                return delegate.getCapability(capabilityClass);
657            }
658    
659            @NotNull
660            @Override
661            public TypeCapabilities getCapabilities() {
662                return delegate.getCapabilities();
663            }
664        }
665    
666        private static class NullableType extends AbstractTypeWithKnownNullability {
667    
668            private NullableType(@NotNull JetType delegate) {
669                super(delegate);
670            }
671    
672            @Override
673            public boolean isMarkedNullable() {
674                return true;
675            }
676        }
677    
678        private static class NotNullType extends AbstractTypeWithKnownNullability {
679    
680            private NotNullType(@NotNull JetType delegate) {
681                super(delegate);
682            }
683    
684            @Override
685            public boolean isMarkedNullable() {
686                return false;
687            }
688        }
689    
690    }