001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.types;
018    
019    import kotlin.Unit;
020    import kotlin.jvm.functions.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024    import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
025    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
026    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
027    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
028    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
029    import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
030    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
031    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
032    
033    import java.util.*;
034    
035    import static org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImplKt.registerTypeVariables;
036    import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL;
037    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
038    
039    public class TypeIntersector {
040    
041        public static boolean isIntersectionEmpty(@NotNull KotlinType typeA, @NotNull KotlinType typeB) {
042            return intersectTypes(KotlinTypeChecker.DEFAULT, new LinkedHashSet<KotlinType>(Arrays.asList(typeA, typeB))) == null;
043        }
044    
045        @Nullable
046        public static KotlinType intersectTypes(@NotNull KotlinTypeChecker typeChecker, @NotNull Collection<KotlinType> types) {
047            assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site.";
048    
049            if (types.size() == 1) {
050                return types.iterator().next();
051            }
052    
053            // Intersection of T1..Tn is an intersection of their non-null versions,
054            //   made nullable is they all were nullable
055            KotlinType nothingOrNullableNothing = null;
056            boolean allNullable = true;
057            List<KotlinType> nullabilityStripped = new ArrayList<KotlinType>(types.size());
058            for (KotlinType type : types) {
059                if (type.isError()) continue;
060    
061                if (KotlinBuiltIns.isNothingOrNullableNothing(type)) {
062                    nothingOrNullableNothing = type;
063                }
064                allNullable &= type.isMarkedNullable();
065                nullabilityStripped.add(TypeUtils.makeNotNullable(type));
066            }
067    
068            if (nothingOrNullableNothing != null) {
069                return TypeUtils.makeNullableAsSpecified(nothingOrNullableNothing, allNullable);
070            }
071    
072            if (nullabilityStripped.isEmpty()) {
073                // All types were errors
074                return ErrorUtils.createErrorType("Intersection of error types: " + types);
075            }
076    
077            // Now we remove types that have subtypes in the list
078            List<KotlinType> resultingTypes = new ArrayList<KotlinType>();
079            outer:
080            for (KotlinType type : nullabilityStripped) {
081                if (!TypeUtils.canHaveSubtypes(typeChecker, type)) {
082                    for (KotlinType other : nullabilityStripped) {
083                        // It makes sense to check for subtyping (other <: type), despite that
084                        // type is not supposed to be open, for there're enums
085                        if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
086                            return null;
087                        }
088                    }
089                    return TypeUtils.makeNullableAsSpecified(type, allNullable);
090                }
091                else {
092                    for (KotlinType other : nullabilityStripped) {
093                        if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
094                            continue outer;
095                        }
096                    }
097                }
098    
099                // Don't add type if it is already present, to avoid trivial type intersections in result
100                for (KotlinType other : resultingTypes) {
101                    if (typeChecker.equalTypes(other, type)) {
102                        continue outer;
103                    }
104                }
105                resultingTypes.add(type);
106            }
107    
108            if (resultingTypes.isEmpty()) {
109                // If we ended up here, it means that all types from `nullabilityStripped` were excluded by the code above
110                // most likely, this is because they are all semantically interchangeable (e.g. List<Foo>! and List<Foo>),
111                // in that case, we can safely select the best representative out of that set and return it
112                // TODO: maybe return the most specific among the types that are subtypes to all others in the `nullabilityStripped`?
113                // TODO: e.g. among {Int, Int?, Int!}, return `Int` (now it returns `Int!`).
114                KotlinType bestRepresentative = FlexibleTypesKt.singleBestRepresentative(nullabilityStripped);
115                if (bestRepresentative == null) {
116                    throw new AssertionError("Empty intersection for types " + types);
117                }
118                return TypeUtils.makeNullableAsSpecified(bestRepresentative, allNullable);
119            }
120    
121            if (resultingTypes.size() == 1) {
122                return TypeUtils.makeNullableAsSpecified(resultingTypes.get(0), allNullable);
123            }
124    
125            TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.Companion.getEMPTY(), resultingTypes);
126    
127            MemberScope[] scopes = new MemberScope[resultingTypes.size()];
128            int i = 0;
129            for (KotlinType type : resultingTypes) {
130                scopes[i] = type.getMemberScope();
131                i++;
132            }
133    
134            return KotlinTypeImpl.create(
135                    Annotations.Companion.getEMPTY(),
136                    constructor,
137                    allNullable,
138                    Collections.<TypeProjection>emptyList(),
139                    new ChainedScope("member scope for intersection type " + constructor, scopes)
140            );
141        }
142    
143        /**
144         * Note: this method was used in overload and override bindings to approximate type parameters with several bounds,
145         * but as it turned out at some point, that logic was inconsistent with Java rules, so it was simplified.
146         * Most of the other usages of this method are left untouched but probably should be investigated closely if they're still valid.
147         */
148        @NotNull
149        public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) {
150            List<KotlinType> upperBounds = descriptor.getUpperBounds();
151            assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor;
152            KotlinType upperBoundsAsType = intersectTypes(KotlinTypeChecker.DEFAULT, upperBounds);
153            return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType();
154        }
155    
156        private static class TypeUnifier {
157            private static class TypeParameterUsage {
158                private final TypeParameterDescriptor typeParameterDescriptor;
159                private final Variance howTheTypeParameterIsUsed;
160    
161                public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
162                    this.typeParameterDescriptor = typeParameterDescriptor;
163                    this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
164                }
165            }
166    
167            public static boolean mayBeEqual(@NotNull KotlinType type, @NotNull KotlinType other) {
168                return unify(type, other);
169            }
170    
171            private static boolean unify(KotlinType withParameters, KotlinType expected) {
172                // T -> how T is used
173                final Map<TypeParameterDescriptor, Variance> parameters = new HashMap<TypeParameterDescriptor, Variance>();
174                Function1<TypeParameterUsage, Unit> processor = new Function1<TypeParameterUsage, Unit>() {
175                    @Override
176                    public Unit invoke(TypeParameterUsage parameterUsage) {
177                        Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
178                        if (howTheTypeIsUsedBefore == null) {
179                            howTheTypeIsUsedBefore = Variance.INVARIANT;
180                        }
181                        parameters.put(parameterUsage.typeParameterDescriptor,
182                                       parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
183                        return Unit.INSTANCE;
184                    }
185                };
186                processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
187                processAllTypeParameters(expected, Variance.INVARIANT, processor);
188                ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
189                registerTypeVariables(constraintSystem, parameters);
190                constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
191    
192                return constraintSystem.getStatus().isSuccessful();
193            }
194    
195            private static void processAllTypeParameters(KotlinType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
196                ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
197                if (descriptor instanceof TypeParameterDescriptor) {
198                    result.invoke(new TypeParameterUsage((TypeParameterDescriptor) descriptor, howThisTypeIsUsed));
199                }
200                for (TypeProjection projection : type.getArguments()) {
201                    if (projection.isStarProjection()) continue;
202                    processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result);
203                }
204            }
205        }
206    }