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.resolve.calls.inference;
018    
019    import com.google.common.base.Function;
020    import com.google.common.base.Functions;
021    import com.google.common.collect.Lists;
022    import com.google.common.collect.Maps;
023    import com.google.common.collect.Sets;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
027    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
028    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
029    import org.jetbrains.jet.lang.types.*;
030    import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
031    import org.jetbrains.jet.lang.types.checker.TypingConstraints;
032    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033    
034    import java.util.List;
035    import java.util.Map;
036    import java.util.Set;
037    
038    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
039    import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL;
040    import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
041    import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind;
042    import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*;
043    
044    public class ConstraintSystemImpl implements ConstraintSystem {
045    
046        public enum ConstraintKind {
047            SUB_TYPE, EQUAL
048        }
049    
050        private final Map<TypeParameterDescriptor, TypeConstraintsImpl> typeParameterConstraints = Maps.newLinkedHashMap();
051        private final Set<ConstraintPosition> errorConstraintPositions = Sets.newHashSet();
052        private final TypeSubstitutor resultingSubstitutor;
053        private final TypeSubstitutor currentSubstitutor;
054        private boolean hasErrorInConstrainingTypes;
055    
056        @Nullable
057        private ConstraintSystem systemWithoutExpectedTypeConstraint;
058    
059        public ConstraintSystemImpl() {
060            this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER));
061            this.currentSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(DONT_CARE));
062        }
063    
064        private TypeSubstitutor createTypeSubstitutorWithDefaultForUnknownTypeParameter(@Nullable final TypeProjection defaultTypeProjection) {
065            return TypeSubstitutor.create(new TypeSubstitution() {
066                @Override
067                public TypeProjection get(TypeConstructor key) {
068                    DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
069                    if (declarationDescriptor instanceof TypeParameterDescriptor) {
070                        TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
071    
072                        JetType value = ConstraintsUtil.getValue(getTypeConstraints(descriptor));
073                        if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
074                            return new TypeProjection(value);
075                        }
076                        if (typeParameterConstraints.containsKey(descriptor)) {
077                            return defaultTypeProjection;
078                        }
079                    }
080                    return null;
081                }
082    
083                @Override
084                public boolean isEmpty() {
085                    return false;
086                }
087    
088                @Override
089                public String toString() {
090                    return typeParameterConstraints.toString();
091                }
092            });
093        }
094    
095        @Override
096        public boolean hasTypeConstructorMismatch() {
097            return !errorConstraintPositions.isEmpty();
098        }
099    
100        @Override
101        public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
102            return errorConstraintPositions.contains(constraintPosition);
103        }
104    
105        @Override
106        public boolean hasOnlyExpectedTypeMismatch() {
107            if (systemWithoutExpectedTypeConstraint == null) {
108                // the expected type constraint isn't added, there can't be an error with it
109                return false;
110            }
111            if (!isSuccessful() && systemWithoutExpectedTypeConstraint.isSuccessful()) {
112                return true;
113            }
114            if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)) {
115                // if systemWithoutExpectedTypeConstraint has unknown type parameters, it's not successful,
116                // but there can be expected type mismatch after expected type is added
117                return true;
118            }
119            return false;
120        }
121    
122        @Override
123        public boolean hasErrorInConstrainingTypes() {
124            return hasErrorInConstrainingTypes;
125        }
126    
127        @Override
128        public void registerTypeVariable(@NotNull TypeParameterDescriptor typeVariable, @NotNull Variance positionVariance) {
129            typeParameterConstraints.put(typeVariable, new TypeConstraintsImpl(positionVariance));
130        }
131    
132        @Override
133        @NotNull
134        public ConstraintSystem copy() {
135            return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(), true);
136        }
137    
138        @NotNull
139        public ConstraintSystem replaceTypeVariables(@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
140            return replaceTypeVariables(typeVariablesMap, false);
141        }
142    
143        @NotNull
144        private ConstraintSystem replaceTypeVariables(
145                @NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
146                boolean recreateTypeConstraints
147        ) {
148            ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
149            for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
150                TypeParameterDescriptor typeParameter = entry.getKey();
151                TypeConstraintsImpl typeConstraints = entry.getValue();
152    
153                TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
154                assert newTypeParameter != null;
155                newConstraintSystem.typeParameterConstraints.put(newTypeParameter, recreateTypeConstraints ? typeConstraints.copy() : typeConstraints);
156            }
157            newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions);
158            newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
159            return newConstraintSystem;
160        }
161    
162        @Override
163        public void addSupertypeConstraint(
164                @Nullable JetType constrainingType,
165                @NotNull JetType subjectType,
166                @NotNull ConstraintPosition constraintPosition
167        ) {
168            if (constrainingType == TypeUtils.NO_EXPECTED_TYPE) return;
169    
170            if (constraintPosition == ConstraintPosition.EXPECTED_TYPE_POSITION) {
171                systemWithoutExpectedTypeConstraint = copy();
172            }
173            addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
174        }
175    
176        @Override
177        public void addSubtypeConstraint(
178                @Nullable JetType constrainingType,
179                @NotNull JetType subjectType,
180                @NotNull ConstraintPosition constraintPosition
181        ) {
182            addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
183        }
184    
185        private void addConstraint(
186                @NotNull ConstraintKind constraintKind,
187                @Nullable JetType subType,
188                @Nullable JetType superType,
189                @NotNull final ConstraintPosition constraintPosition
190        ) {
191            TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
192                @Override
193                public boolean assertEqualTypes(
194                        @NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
195                ) {
196                    doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
197                    return true;
198    
199                }
200    
201                @Override
202                public boolean assertEqualTypeConstructors(
203                        @NotNull TypeConstructor a, @NotNull TypeConstructor b
204                ) {
205                    throw new IllegalStateException("'assertEqualTypeConstructors' shouldn't be invoked inside 'isSubtypeOf'");
206                }
207    
208                @Override
209                public boolean assertSubtype(
210                        @NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure
211                ) {
212                    doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
213                    return true;
214                }
215    
216                @Override
217                public boolean noCorrespondingSupertype(
218                        @NotNull JetType subtype, @NotNull JetType supertype
219                ) {
220                    errorConstraintPositions.add(constraintPosition);
221                    return true;
222                }
223            });
224            doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure);
225        }
226    
227        private boolean isErrorOrSpecialType(@Nullable JetType type) {
228            if (type == DONT_CARE || type == CANT_INFER_TYPE_PARAMETER) {
229                return true;
230            }
231    
232            if (type == null || ((ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE))) {
233                hasErrorInConstrainingTypes = true;
234                return true;
235            }
236            return false;
237        }
238    
239        private void doAddConstraint(
240                @NotNull ConstraintKind constraintKind,
241                @Nullable JetType subType,
242                @Nullable JetType superType,
243                @NotNull ConstraintPosition constraintPosition,
244                @NotNull TypeCheckingProcedure typeCheckingProcedure
245        ) {
246    
247            if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return;
248            assert subType != null && superType != null;
249    
250            assert superType != PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
251    
252            KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
253            if (subType == PLACEHOLDER_FUNCTION_TYPE) {
254                if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
255                    if (isMyTypeVariable(superType)) {
256                        // a constraint binds type parameter and any function type, so there is no new info and no error
257                        return;
258                    }
259                    errorConstraintPositions.add(constraintPosition);
260                }
261                return;
262            }
263    
264            // todo temporary hack
265            // function literal without declaring receiver type { x -> ... }
266            // can be considered as extension function if one is expected
267            // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
268            if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
269                subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
270            }
271    
272            // can be equal for the recursive invocations:
273            // fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
274            if (subType.equals(superType)) return;
275    
276            assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
277                    "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
278    
279    
280            if (isMyTypeVariable(subType)) {
281                generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND);
282                return;
283            }
284            if (isMyTypeVariable(superType)) {
285                generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND);
286                return;
287            }
288            // if superType is nullable and subType is not nullable, unsafe call error will be generated later,
289            // but constraint system should be solved anyway
290            typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
291        }
292    
293        private void generateTypeParameterConstraint(
294                @NotNull JetType parameterType,
295                @NotNull JetType constrainingType,
296                @NotNull BoundKind boundKind
297        ) {
298            TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
299            assert typeConstraints != null : "constraint should be generated only for type variables";
300    
301            if (parameterType.isNullable()) {
302                // For parameter type T constraint T? <: Int? should transform to T <: Int
303                constrainingType = TypeUtils.makeNotNullable(constrainingType);
304            }
305            typeConstraints.addBound(boundKind, constrainingType);
306        }
307    
308        public void processDeclaredBoundConstraints() {
309            for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
310                TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
311                TypeConstraintsImpl typeConstraints = entry.getValue();
312                for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
313                    //todo order matters here
314                    for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
315                        addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
316                    }
317                }
318            }
319        }
320    
321        @NotNull
322        @Override
323        public Set<TypeParameterDescriptor> getTypeVariables() {
324            return typeParameterConstraints.keySet();
325        }
326    
327        @Override
328        @Nullable
329        public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable) {
330            return typeParameterConstraints.get(typeVariable);
331        }
332    
333        @Nullable
334        private TypeConstraintsImpl getTypeConstraints(@NotNull JetType type) {
335            ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
336            if (parameterDescriptor instanceof TypeParameterDescriptor) {
337                return typeParameterConstraints.get(parameterDescriptor);
338            }
339            return null;
340        }
341    
342        private boolean isMyTypeVariable(@NotNull JetType type) {
343            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
344            return descriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(descriptor) != null;
345        }
346    
347        @Override
348        public boolean isSuccessful() {
349            return !hasContradiction() && !hasUnknownParameters();
350        }
351    
352        @Override
353        public boolean hasContradiction() {
354            return hasTypeConstructorMismatch() || hasConflictingConstraints();
355        }
356    
357        @Override
358        public boolean hasConflictingConstraints() {
359            for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
360                TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
361                if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
362            }
363            return false;
364        }
365    
366        @Override
367        public boolean hasUnknownParameters() {
368            for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
369                if (constraints.isEmpty()) {
370                    return true;
371                }
372            }
373            return false;
374        }
375    
376        @NotNull
377        @Override
378        public TypeSubstitutor getResultingSubstitutor() {
379            if (hasOnlyExpectedTypeMismatch()) {
380                assert systemWithoutExpectedTypeConstraint != null;
381                return systemWithoutExpectedTypeConstraint.getResultingSubstitutor();
382            }
383            return resultingSubstitutor;
384        }
385    
386        @NotNull
387        @Override
388        public TypeSubstitutor getCurrentSubstitutor() {
389            return currentSubstitutor;
390        }
391    
392        @NotNull
393        public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
394            assert KotlinBuiltIns.getInstance().isFunctionType(functionType);
395    
396            List<TypeProjection> typeArguments = functionType.getArguments();
397            assert !typeArguments.isEmpty();
398    
399            List<JetType> arguments = Lists.newArrayList();
400            // excluding the last type argument of the function type, which is the return type
401            int index = 0;
402            int lastIndex = typeArguments.size() - 1;
403            for (TypeProjection typeArgument : typeArguments) {
404                if (index < lastIndex) {
405                    arguments.add(typeArgument.getType());
406                }
407                index++;
408            }
409            JetType returnType = typeArguments.get(lastIndex).getType();
410            return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
411        }
412    }