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