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