001    /*
002     * Copyright 2010-2013 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.jet.lang.types;
018    
019    import kotlin.Function1;
020    import kotlin.KotlinPackage;
021    import kotlin.Unit;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
025    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
026    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
027    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
028    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
029    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
030    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
031    import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
032    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
033    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
035    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036    import org.jetbrains.jet.utils.DFS;
037    import org.jetbrains.jet.utils.UtilsPackage;
038    
039    import java.util.*;
040    
041    public class TypeUtils {
042        public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
043        public static final JetType PLACEHOLDER_FUNCTION_TYPE = ErrorUtils.createErrorTypeWithCustomDebugName("PLACEHOLDER_FUNCTION_TYPE");
044    
045        public static final JetType CANT_INFER_LAMBDA_PARAM_TYPE = ErrorUtils.createErrorType("Cannot be inferred");
046    
047        public static class SpecialType implements JetType {
048            private final String name;
049    
050            public SpecialType(String name) {
051                this.name = name;
052            }
053    
054            @NotNull
055            @Override
056            public TypeConstructor getConstructor() {
057                throw new IllegalStateException(name);
058            }
059    
060            @NotNull
061            @Override
062            public List<TypeProjection> getArguments() {
063                throw new IllegalStateException(name);
064            }
065    
066            @Override
067            public boolean isNullable() {
068                throw new IllegalStateException(name);
069            }
070    
071            @NotNull
072            @Override
073            public JetScope getMemberScope() {
074                throw new IllegalStateException(name);
075            }
076    
077            @Override
078            public boolean isError() {
079                return false;
080            }
081    
082            @NotNull
083            @Override
084            public Annotations getAnnotations() {
085                throw new IllegalStateException(name);
086            }
087    
088            @Nullable
089            @Override
090            public <T extends TypeCapability> T getCapability(@NotNull Class<T> capabilityClass) {
091                return null;
092            }
093    
094            @Override
095            public String toString() {
096                return name;
097            }
098        }
099    
100        public static final JetType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
101        
102        public static final JetType UNIT_EXPECTED_TYPE = new SpecialType("UNIT_EXPECTED_TYPE");
103    
104        public static boolean noExpectedType(@NotNull JetType type) {
105            return type == NO_EXPECTED_TYPE || type == UNIT_EXPECTED_TYPE;
106        }
107    
108        @NotNull
109        public static JetType makeNullable(@NotNull JetType type) {
110            return makeNullableAsSpecified(type, true);
111        }
112    
113        @NotNull
114        public static JetType makeNotNullable(@NotNull JetType type) {
115            return makeNullableAsSpecified(type, false);
116        }
117    
118        @NotNull
119        public static JetType makeNullableAsSpecified(@NotNull JetType type, boolean nullable) {
120            NullAwareness nullAwareness = type.getCapability(NullAwareness.class);
121            if (nullAwareness != null) {
122                return nullAwareness.makeNullableAsSpecified(nullable);
123            }
124    
125            // Wrapping serves two purposes here
126            // 1. It's requires less memory than copying with a changed nullability flag: a copy has many fields, while a wrapper has only one
127            // 2. It preserves laziness of types
128    
129            // Unwrap to avoid long delegation call chains
130            if (type instanceof AbstractTypeWithKnownNullability) {
131                return makeNullableAsSpecified(((AbstractTypeWithKnownNullability) type).delegate, nullable);
132            }
133    
134            // checking to preserve laziness
135            if (!(type instanceof LazyType) && type.isNullable() == nullable) {
136                return type;
137            }
138    
139            return nullable ? new NullableType(type) : new NotNullType(type);
140        }
141    
142        @NotNull
143        public static JetType makeNullableIfNeeded(@NotNull JetType type, boolean nullable) {
144            if (nullable) {
145                return makeNullable(type);
146            }
147            return type;
148        }
149    
150        public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) {
151            return intersect(JetTypeChecker.DEFAULT, new LinkedHashSet<JetType>(Arrays.asList(typeA, typeB))) == null;
152        }
153    
154        @Nullable
155        public static JetType intersect(@NotNull JetTypeChecker typeChecker, @NotNull Set<JetType> types) {
156            if (types.isEmpty()) {
157                return KotlinBuiltIns.getInstance().getNullableAnyType();
158            }
159    
160            if (types.size() == 1) {
161                return types.iterator().next();
162            }
163    
164            // Intersection of T1..Tn is an intersection of their non-null versions,
165            //   made nullable is they all were nullable
166            boolean allNullable = true;
167            boolean nothingTypePresent = false;
168            List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
169            for (JetType type : types) {
170                nothingTypePresent |= KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type);
171                allNullable &= type.isNullable();
172                nullabilityStripped.add(makeNotNullable(type));
173            }
174            
175            if (nothingTypePresent) {
176                return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
177            }
178    
179            // Now we remove types that have subtypes in the list
180            List<JetType> resultingTypes = new ArrayList<JetType>();
181            outer:
182            for (JetType type : nullabilityStripped) {
183                if (!canHaveSubtypes(typeChecker, type)) {
184                    for (JetType other : nullabilityStripped) {
185                        // It makes sense to check for subtyping (other <: type), despite that
186                        // type is not supposed to be open, for there're enums
187                        if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
188                            return null;
189                        }
190                    }
191                    return makeNullableAsSpecified(type, allNullable);
192                }
193                else {
194                    for (JetType other : nullabilityStripped) {
195                        if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
196                            continue outer;
197                        }
198    
199                    }
200                }
201    
202                // Don't add type if it is already present, to avoid trivial type intersections in result
203                for (JetType other : resultingTypes) {
204                    if (typeChecker.equalTypes(other, type)) {
205                        continue outer;
206                    }
207                }
208                resultingTypes.add(type);
209            }
210            
211            if (resultingTypes.size() == 1) {
212                return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
213            }
214    
215    
216            TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
217    
218            JetScope[] scopes = new JetScope[resultingTypes.size()];
219            int i = 0;
220            for (JetType type : resultingTypes) {
221                scopes[i] = type.getMemberScope();
222                i++;
223            }
224    
225            return new JetTypeImpl(
226                    Annotations.EMPTY,
227                    constructor,
228                    allNullable,
229                    Collections.<TypeProjection>emptyList(),
230                    new ChainedScope(null, "member scope for intersection type " + constructor, scopes)); // TODO : check intersectibility, don't use a chanied scope
231        }
232    
233        private static class TypeUnifier {
234            private static class TypeParameterUsage {
235                private final TypeParameterDescriptor typeParameterDescriptor;
236                private final Variance howTheTypeParameterIsUsed;
237    
238                public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
239                    this.typeParameterDescriptor = typeParameterDescriptor;
240                    this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
241                }
242            }
243    
244            public static boolean mayBeEqual(@NotNull JetType type, @NotNull JetType other) {
245                return unify(type, other);
246            }
247    
248            private static boolean unify(JetType withParameters, JetType expected) {
249                // T -> how T is used
250                final Map<TypeParameterDescriptor, Variance> parameters = new HashMap<TypeParameterDescriptor, Variance>();
251                Function1<TypeParameterUsage, Unit> processor = new Function1<TypeParameterUsage, Unit>() {
252                    @Override
253                    public Unit invoke(TypeParameterUsage parameterUsage) {
254                        Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
255                        if (howTheTypeIsUsedBefore == null) {
256                            howTheTypeIsUsedBefore = Variance.INVARIANT;
257                        }
258                        parameters.put(parameterUsage.typeParameterDescriptor,
259                                       parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
260                        return Unit.INSTANCE$;
261                    }
262                };
263                processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
264                processAllTypeParameters(expected, Variance.INVARIANT, processor);
265                ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
266                constraintSystem.registerTypeVariables(parameters);
267                constraintSystem.addSubtypeConstraint(withParameters, expected, ConstraintPosition.SPECIAL);
268    
269                return constraintSystem.getStatus().isSuccessful();
270            }
271    
272            private static void processAllTypeParameters(JetType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
273                ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
274                if (descriptor instanceof TypeParameterDescriptor) {
275                    result.invoke(new TypeParameterUsage((TypeParameterDescriptor) descriptor, howThisTypeIsUsed));
276                }
277                for (TypeProjection projection : type.getArguments()) {
278                    processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result);
279                }
280            }
281        }
282    
283        public static boolean canHaveSubtypes(JetTypeChecker typeChecker, JetType type) {
284            if (type.isNullable()) {
285                return true;
286            }
287            if (!type.getConstructor().isFinal()) {
288                return true;
289            }
290    
291            List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
292            List<TypeProjection> arguments = type.getArguments();
293            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
294                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
295                TypeProjection typeProjection = arguments.get(i);
296                Variance projectionKind = typeProjection.getProjectionKind();
297                JetType argument = typeProjection.getType();
298    
299                switch (parameterDescriptor.getVariance()) {
300                    case INVARIANT:
301                        switch (projectionKind) {
302                            case INVARIANT:
303                                if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
304                                    return true;
305                                }
306                                break;
307                            case IN_VARIANCE:
308                                if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
309                                    return true;
310                                }
311                                break;
312                            case OUT_VARIANCE:
313                                if (canHaveSubtypes(typeChecker, argument)) {
314                                    return true;
315                                }
316                                break;
317                        }
318                        break;
319                    case IN_VARIANCE:
320                        if (projectionKind != Variance.OUT_VARIANCE) {
321                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
322                                return true;
323                            }
324                        }
325                        else {
326                            if (canHaveSubtypes(typeChecker, argument)) {
327                                return true;
328                            }
329                        }
330                        break;
331                    case OUT_VARIANCE:
332                        if (projectionKind != Variance.IN_VARIANCE) {
333                            if (canHaveSubtypes(typeChecker, argument)) {
334                                return true;
335                            }
336                        }
337                        else {
338                            if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
339                                return true;
340                            }
341                        }
342                        break;
343                }
344            }
345            return false;
346        }
347    
348        private static boolean lowerThanBound(JetTypeChecker typeChecker, JetType argument, TypeParameterDescriptor parameterDescriptor) {
349            for (JetType bound : parameterDescriptor.getUpperBounds()) {
350                if (typeChecker.isSubtypeOf(argument, bound)) {
351                    if (!argument.getConstructor().equals(bound.getConstructor())) {
352                        return true;
353                    }
354                }
355            }
356            return false;
357        }
358    
359        @NotNull
360        public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
361            if (ErrorUtils.isError(classDescriptor)) {
362                return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor);
363            }
364            TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
365            List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters());
366            return new JetTypeImpl(
367                    Annotations.EMPTY,
368                    typeConstructor,
369                    false,
370                    arguments,
371                    unsubstitutedMemberScope
372            );
373        }
374    
375        @NotNull
376        public static List<TypeProjection> getDefaultTypeProjections(List<TypeParameterDescriptor> parameters) {
377            List<TypeProjection> result = new ArrayList<TypeProjection>();
378            for (TypeParameterDescriptor parameterDescriptor : parameters) {
379                result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType()));
380            }
381            return result;
382        }
383    
384        @NotNull
385        public static List<JetType> getImmediateSupertypes(@NotNull JetType type) {
386            boolean isNullable = type.isNullable();
387            TypeSubstitutor substitutor = TypeSubstitutor.create(type);
388            Collection<JetType> originalSupertypes = type.getConstructor().getSupertypes();
389            List<JetType> result = new ArrayList<JetType>(originalSupertypes.size());
390            for (JetType supertype : originalSupertypes) {
391                JetType substitutedType = substitutor.substitute(supertype, Variance.INVARIANT);
392                if (substitutedType != null) {
393                    result.add(makeNullableIfNeeded(substitutedType, isNullable));
394                }
395            }
396            return result;
397        }
398    
399        private static void collectAllSupertypes(@NotNull JetType type, @NotNull Set<JetType> result) {
400            List<JetType> immediateSupertypes = getImmediateSupertypes(type);
401            result.addAll(immediateSupertypes);
402            for (JetType supertype : immediateSupertypes) {
403                collectAllSupertypes(supertype, result);
404            }
405        }
406    
407    
408        @NotNull
409        public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
410            // 15 is obtained by experimentation: JDK classes like ArrayList tend to have so many supertypes,
411            // the average number is lower
412            Set<JetType> result = new LinkedHashSet<JetType>(15);
413            collectAllSupertypes(type, result);
414            return result;
415        }
416    
417        public static boolean hasNullableLowerBound(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
418            for (JetType bound : typeParameterDescriptor.getLowerBounds()) {
419                if (bound.isNullable()) {
420                    return true;
421                }
422            }
423            return false;
424        }
425    
426        /**
427         * A work-around of the generic nullability problem in the type checker
428         * @return true if a value of this type can be null
429         */
430        public static boolean isNullableType(@NotNull JetType type) {
431            if (type.isNullable()) {
432                return true;
433            }
434            if (TypesPackage.isFlexible(type) && isNullableType(TypesPackage.flexibility(type).getUpperBound())) {
435                return true;
436            }
437            if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
438                return hasNullableSuperType(type);
439            }
440            return false;
441        }
442    
443        public static boolean hasNullableSuperType(@NotNull JetType type) {
444            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
445                // A class/trait cannot have a nullable supertype
446                return false;
447            }
448    
449            for (JetType supertype : getImmediateSupertypes(type)) {
450                if (supertype.isNullable()) return true;
451                if (hasNullableSuperType(supertype)) return true;
452            }
453            
454            return false;
455        }
456    
457        @Nullable
458        public static ClassDescriptor getClassDescriptor(@NotNull JetType type) {
459            DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
460            if (declarationDescriptor instanceof ClassDescriptor) {
461                return (ClassDescriptor) declarationDescriptor;
462            }
463            return null;
464        }
465    
466        @NotNull
467        public static JetType substituteParameters(@NotNull ClassDescriptor clazz, @NotNull List<JetType> typeArguments) {
468            List<TypeProjection> projections = KotlinPackage.map(typeArguments, new Function1<JetType, TypeProjection>() {
469                @Override
470                public TypeProjection invoke(JetType type) {
471                    return new TypeProjectionImpl(type);
472                }
473            });
474    
475            return substituteProjectionsForParameters(clazz, projections);
476        }
477    
478        @NotNull
479        public static JetType substituteProjectionsForParameters(@NotNull ClassDescriptor clazz, @NotNull List<TypeProjection> projections) {
480            List<TypeParameterDescriptor> clazzTypeParameters = clazz.getTypeConstructor().getParameters();
481            if (clazzTypeParameters.size() != projections.size()) {
482                throw new IllegalArgumentException("type parameter counts do not match: " + clazz + ", " + projections);
483            }
484    
485            Map<TypeConstructor, TypeProjection> substitutions = UtilsPackage.newHashMapWithExpectedSize(clazzTypeParameters.size());
486    
487            for (int i = 0; i < clazzTypeParameters.size(); ++i) {
488                TypeConstructor typeConstructor = clazzTypeParameters.get(i).getTypeConstructor();
489                substitutions.put(typeConstructor, projections.get(i));
490            }
491    
492            return TypeSubstitutor.create(substitutions).substitute(clazz.getDefaultType(), Variance.INVARIANT);
493        }
494    
495        public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
496            return JetTypeChecker.DEFAULT.isSubtypeOf(a, b) && JetTypeChecker.DEFAULT.isSubtypeOf(b, a);
497        }
498    
499        public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection<TypeParameterDescriptor> typeParameters) {
500            return dependsOnTypeConstructors(type, KotlinPackage.map(
501                    typeParameters,
502                    new Function1<TypeParameterDescriptor, TypeConstructor>() {
503                        @Override
504                        public TypeConstructor invoke(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
505                            return typeParameterDescriptor.getTypeConstructor();
506                        }
507                    }
508            ));
509        }
510    
511        public static boolean dependsOnTypeConstructors(@NotNull JetType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) {
512            if (typeParameterConstructors.contains(type.getConstructor())) return true;
513            for (TypeProjection typeProjection : type.getArguments()) {
514                if (dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) {
515                    return true;
516                }
517            }
518            return false;
519        }
520    
521        public static boolean containsSpecialType(@Nullable JetType type, @NotNull final JetType specialType) {
522            return containsSpecialType(type, new Function1<JetType, Boolean>() {
523                @Override
524                public Boolean invoke(JetType type) {
525                    return specialType.equals(type);
526                }
527            });
528        }
529    
530        public static boolean containsSpecialType(
531                @Nullable JetType type,
532                @NotNull Function1<JetType, Boolean> isSpecialType
533        ) {
534            if (type == null) return false;
535            if (isSpecialType.invoke(type)) return true;
536            for (TypeProjection projection : type.getArguments()) {
537                if (containsSpecialType(projection.getType(), isSpecialType)) return true;
538            }
539            return false;
540        }
541    
542        @NotNull
543        public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
544            return new TypeProjectionImpl(parameterDescriptor.getVariance() == Variance.OUT_VARIANCE
545                                          ? Variance.INVARIANT
546                                          : Variance.OUT_VARIANCE, parameterDescriptor.getUpperBoundsAsType());
547        }
548    
549        @Nullable
550        public static JetType commonSupertypeForNumberTypes(@NotNull Collection<JetType> numberLowerBounds) {
551            if (numberLowerBounds.isEmpty()) return null;
552            Set<JetType> intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds);
553            JetType primitiveNumberType = getDefaultPrimitiveNumberType(intersectionOfSupertypes);
554            if (primitiveNumberType != null) {
555                return primitiveNumberType;
556            }
557            return CommonSupertypes.commonSupertype(numberLowerBounds);
558        }
559    
560        @NotNull
561        private static Set<JetType> getIntersectionOfSupertypes(@NotNull Collection<JetType> types) {
562            Set<JetType> upperBounds = new HashSet<JetType>();
563            for (JetType type : types) {
564                Collection<JetType> supertypes = type.getConstructor().getSupertypes();
565                if (upperBounds.isEmpty()) {
566                    upperBounds.addAll(supertypes);
567                }
568                else {
569                    upperBounds.retainAll(supertypes);
570                }
571            }
572            return upperBounds;
573        }
574    
575        @NotNull
576        public static JetType getDefaultPrimitiveNumberType(@NotNull IntegerValueTypeConstructor numberValueTypeConstructor) {
577            JetType type = getDefaultPrimitiveNumberType(numberValueTypeConstructor.getSupertypes());
578            assert type != null : "Strange number value type constructor: " + numberValueTypeConstructor + ". " +
579                                  "Super types doesn't contain double, int or long: " + numberValueTypeConstructor.getSupertypes();
580            return type;
581        }
582    
583        @Nullable
584        private static JetType getDefaultPrimitiveNumberType(@NotNull Collection<JetType> supertypes) {
585            JetType doubleType = KotlinBuiltIns.getInstance().getDoubleType();
586            if (supertypes.contains(doubleType)) {
587                return doubleType;
588            }
589            JetType intType = KotlinBuiltIns.getInstance().getIntType();
590            if (supertypes.contains(intType)) {
591                return intType;
592            }
593            JetType longType = KotlinBuiltIns.getInstance().getLongType();
594            if (supertypes.contains(longType)) {
595                return longType;
596            }
597            return null;
598        }
599    
600        @NotNull
601        public static JetType getPrimitiveNumberType(
602                @NotNull IntegerValueTypeConstructor numberValueTypeConstructor,
603                @NotNull JetType expectedType
604        ) {
605            if (noExpectedType(expectedType) || expectedType.isError()) {
606                return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
607            }
608            for (JetType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) {
609                if (JetTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
610                    return primitiveNumberType;
611                }
612            }
613            return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
614        }
615    
616        public static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
617                @NotNull JetType type,
618                @NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances,
619                @NotNull final Set<TypeConstructor> visited
620        ) {
621            return DFS.dfs(
622                    Collections.singletonList(type),
623                    new DFS.Neighbors<JetType>() {
624                        @NotNull
625                        @Override
626                        public Iterable<JetType> getNeighbors(JetType current) {
627                            TypeSubstitutor substitutor = TypeSubstitutor.create(current);
628                            Collection<JetType> supertypes = current.getConstructor().getSupertypes();
629                            List<JetType> result = new ArrayList<JetType>(supertypes.size());
630                            for (JetType supertype : supertypes) {
631                                if (visited.contains(supertype.getConstructor())) {
632                                    continue;
633                                }
634                                result.add(substitutor.safeSubstitute(supertype, Variance.INVARIANT));
635                            }
636                            return result;
637                        }
638                    },
639                    new DFS.Visited<JetType>() {
640                        @Override
641                        public boolean checkAndMarkVisited(JetType current) {
642                            return visited.add(current.getConstructor());
643                        }
644                    },
645                    new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() {
646                        @Override
647                        public boolean beforeChildren(JetType current) {
648                            TypeConstructor constructor = current.getConstructor();
649    
650                            Set<JetType> instances = constructorToAllInstances.get(constructor);
651                            if (instances == null) {
652                                instances = new HashSet<JetType>();
653                                constructorToAllInstances.put(constructor, instances);
654                            }
655                            instances.add(current);
656    
657                            return true;
658                        }
659    
660                        @Override
661                        public void afterChildren(JetType current) {
662                            result.addFirst(current.getConstructor());
663                        }
664                    }
665            );
666        }
667    
668        public static TypeSubstitutor makeConstantSubstitutor(Collection<TypeParameterDescriptor> typeParameterDescriptors, JetType type) {
669            final Set<TypeConstructor> constructors = UtilsPackage.newHashSetWithExpectedSize(typeParameterDescriptors.size());
670            for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) {
671                constructors.add(typeParameterDescriptor.getTypeConstructor());
672            }
673            final TypeProjection projection = new TypeProjectionImpl(type);
674    
675            return TypeSubstitutor.create(new TypeSubstitution() {
676                @Override
677                public TypeProjection get(TypeConstructor key) {
678                    if (constructors.contains(key)) {
679                        return projection;
680                    }
681                    return null;
682                }
683    
684                @Override
685                public boolean isEmpty() {
686                    return false;
687                }
688            });
689        }
690    
691        public static TypeSubstitutor makeSubstitutorForTypeParametersMap(
692               @NotNull final Map<TypeParameterDescriptor, TypeProjection> substitutionContext
693        ) {
694            return TypeSubstitutor.create(new TypeSubstitution() {
695                @Nullable
696                @Override
697                public TypeProjection get(TypeConstructor key) {
698                    DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
699                    if (declarationDescriptor instanceof TypeParameterDescriptor) {
700                        TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
701                        return substitutionContext.get(descriptor);
702                    }
703                    return null;
704                }
705    
706                @Override
707                public boolean isEmpty() {
708                    return substitutionContext.isEmpty();
709                }
710    
711                @Override
712                public String toString() {
713                    return substitutionContext.toString();
714                }
715            });
716        }
717    
718        private static abstract class AbstractTypeWithKnownNullability extends AbstractJetType {
719            private final JetType delegate;
720    
721            private AbstractTypeWithKnownNullability(@NotNull JetType delegate) {
722                this.delegate = delegate;
723            }
724    
725            @Override
726            @NotNull
727            public TypeConstructor getConstructor() {
728                return delegate.getConstructor();
729            }
730    
731            @Override
732            @NotNull
733            public List<TypeProjection> getArguments() {
734                return delegate.getArguments();
735            }
736    
737            @Override
738            public abstract boolean isNullable();
739    
740            @Override
741            @NotNull
742            public JetScope getMemberScope() {
743                return delegate.getMemberScope();
744            }
745    
746            @Override
747            public boolean isError() {
748                return delegate.isError();
749            }
750    
751            @Override
752            @NotNull
753            public Annotations getAnnotations() {
754                return delegate.getAnnotations();
755            }
756        }
757    
758        private static class NullableType extends AbstractTypeWithKnownNullability {
759    
760            private NullableType(@NotNull JetType delegate) {
761                super(delegate);
762            }
763    
764            @Override
765            public boolean isNullable() {
766                return true;
767            }
768        }
769    
770        private static class NotNullType extends AbstractTypeWithKnownNullability {
771    
772            private NotNullType(@NotNull JetType delegate) {
773                super(delegate);
774            }
775    
776            @Override
777            public boolean isNullable() {
778                return false;
779            }
780        }
781    
782    }