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
017package org.jetbrains.jet.lang.resolve.java.kotlinSignature;
018
019import com.google.common.collect.*;
020import com.intellij.openapi.diagnostic.Logger;
021import com.intellij.openapi.util.Pair;
022import com.intellij.openapi.util.SystemInfo;
023import com.intellij.psi.PsiClass;
024import com.intellij.psi.PsiElement;
025import com.intellij.psi.PsiManager;
026import com.intellij.psi.PsiMethod;
027import com.intellij.util.Function;
028import com.intellij.util.containers.ContainerUtil;
029import org.jetbrains.annotations.NotNull;
030import org.jetbrains.annotations.Nullable;
031import org.jetbrains.jet.lang.descriptors.*;
032import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
033import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
034import org.jetbrains.jet.lang.resolve.BindingContext;
035import org.jetbrains.jet.lang.resolve.BindingContextUtils;
036import org.jetbrains.jet.lang.resolve.BindingTrace;
037import org.jetbrains.jet.lang.resolve.DescriptorUtils;
038import org.jetbrains.jet.lang.resolve.java.*;
039import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
040import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
041import org.jetbrains.jet.lang.resolve.name.FqName;
042import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
043import org.jetbrains.jet.lang.resolve.name.Name;
044import org.jetbrains.jet.lang.resolve.scopes.JetScope;
045import org.jetbrains.jet.lang.types.*;
046import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
047
048import java.util.*;
049
050import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName;
051import static org.jetbrains.jet.lang.resolve.java.TypeUsage.*;
052import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
053
054public class SignaturesPropagationData {
055    private static final Logger LOG = Logger.getInstance(SignaturesPropagationData.class);
056
057    private final List<TypeParameterDescriptor> modifiedTypeParameters;
058    private final JavaDescriptorResolver.ValueParameterDescriptors modifiedValueParameters;
059    private final JetType modifiedReturnType;
060
061    private final List<String> signatureErrors = Lists.newArrayList();
062    private final List<FunctionDescriptor> superFunctions;
063    private final Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> autoTypeParameterToModified;
064    final ClassDescriptor containingClass;
065
066    public SignaturesPropagationData(
067            @NotNull ClassDescriptor containingClass,
068            @NotNull JetType autoReturnType, // type built by JavaTypeTransformer from Java signature and @NotNull annotations
069            @NotNull JavaDescriptorResolver.ValueParameterDescriptors autoValueParameters, // descriptors built by parameters resolver
070            @NotNull List<TypeParameterDescriptor> autoTypeParameters, // descriptors built by signature resolver
071            @NotNull PsiMethodWrapper method,
072            @NotNull BindingTrace trace
073    ) {
074        this.containingClass = containingClass;
075        superFunctions = getSuperFunctionsForMethod(method, trace, containingClass);
076
077        autoTypeParameterToModified = SignaturesUtil.recreateTypeParametersAndReturnMapping(autoTypeParameters, null);
078
079        modifiedTypeParameters = modifyTypeParametersAccordingToSuperMethods(autoTypeParameters);
080        modifiedReturnType = modifyReturnTypeAccordingToSuperMethods(autoReturnType);
081        modifiedValueParameters = modifyValueParametersAccordingToSuperMethods(autoValueParameters);
082    }
083
084    public List<TypeParameterDescriptor> getModifiedTypeParameters() {
085        return modifiedTypeParameters;
086    }
087
088    public JavaDescriptorResolver.ValueParameterDescriptors getModifiedValueParameters() {
089        return modifiedValueParameters;
090    }
091
092    public JetType getModifiedReturnType() {
093        return modifiedReturnType;
094    }
095
096    public List<String> getSignatureErrors() {
097        return signatureErrors;
098    }
099
100    public List<FunctionDescriptor> getSuperFunctions() {
101        return superFunctions;
102    }
103
104    void reportError(String error) {
105        signatureErrors.add(error);
106    }
107
108    private JetType modifyReturnTypeAccordingToSuperMethods(
109            @NotNull JetType autoType // type built by JavaTypeTransformer
110    ) {
111        List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
112                new Function<FunctionDescriptor, TypeAndVariance>() {
113                    @Override
114                    public TypeAndVariance fun(FunctionDescriptor superFunction) {
115                        return new TypeAndVariance(superFunction.getReturnType(), Variance.OUT_VARIANCE);
116                    }
117                });
118
119        return modifyTypeAccordingToSuperMethods(autoType, typesFromSuperMethods, MEMBER_SIGNATURE_COVARIANT);
120    }
121
122    private List<TypeParameterDescriptor> modifyTypeParametersAccordingToSuperMethods(List<TypeParameterDescriptor> autoTypeParameters) {
123        List<TypeParameterDescriptor> result = Lists.newArrayList();
124
125        for (TypeParameterDescriptor autoParameter : autoTypeParameters) {
126            int index = autoParameter.getIndex();
127            TypeParameterDescriptorImpl modifiedTypeParameter = autoTypeParameterToModified.get(autoParameter);
128
129            List<Iterator<JetType>> upperBoundFromSuperFunctionsIterators = Lists.newArrayList();
130            for (FunctionDescriptor superFunction : superFunctions) {
131                upperBoundFromSuperFunctionsIterators.add(superFunction.getTypeParameters().get(index).getUpperBounds().iterator());
132            }
133
134            for (JetType autoUpperBound : autoParameter.getUpperBounds()) {
135                List<TypeAndVariance> upperBoundsFromSuperFunctions = Lists.newArrayList();
136
137                for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
138                    assert iterator.hasNext();
139                    upperBoundsFromSuperFunctions.add(new TypeAndVariance(iterator.next(), INVARIANT));
140                }
141
142                JetType modifiedUpperBound = modifyTypeAccordingToSuperMethods(autoUpperBound, upperBoundsFromSuperFunctions, UPPER_BOUND);
143                modifiedTypeParameter.addUpperBound(modifiedUpperBound);
144            }
145
146            for (Iterator<JetType> iterator : upperBoundFromSuperFunctionsIterators) {
147                assert !iterator.hasNext();
148            }
149
150            modifiedTypeParameter.setInitialized();
151            result.add(modifiedTypeParameter);
152        }
153
154        return result;
155    }
156
157    private JavaDescriptorResolver.ValueParameterDescriptors modifyValueParametersAccordingToSuperMethods(
158            @NotNull JavaDescriptorResolver.ValueParameterDescriptors parameters // descriptors built by parameters resolver
159    ) {
160        assert parameters.getReceiverType() == null : "Parameters before propagation have receiver type," +
161                                                      " but propagation should be disabled for functions compiled from Kotlin in class: " +
162                                                      DescriptorUtils.getFQName(containingClass);
163
164        JetType receiverType = null;
165        List<ValueParameterDescriptor> resultParameters = Lists.newArrayList();
166
167        boolean shouldBeExtension = checkIfShouldBeExtension();
168
169        for (ValueParameterDescriptor originalParam : parameters.getDescriptors()) {
170            final int originalIndex = originalParam.getIndex();
171            List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
172                    new Function<FunctionDescriptor, TypeAndVariance>() {
173                        @Override
174                        public TypeAndVariance fun(FunctionDescriptor superFunction) {
175                            ReceiverParameterDescriptor receiver = superFunction.getReceiverParameter();
176                            int index = receiver != null ? originalIndex - 1 : originalIndex;
177                            if (index == -1) {
178                                assert receiver != null : "can't happen: index is -1, while function is not extension";
179                                return new TypeAndVariance(receiver.getType(), INVARIANT);
180                            }
181                            return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), INVARIANT);
182                        }
183                    });
184
185            VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
186
187            JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods, MEMBER_SIGNATURE_CONTRAVARIANT);
188
189            if (shouldBeExtension && originalIndex == 0) {
190                receiverType = altType;
191            }
192            else {
193                resultParameters.add(new ValueParameterDescriptorImpl(
194                        originalParam.getContainingDeclaration(),
195                        shouldBeExtension ? originalIndex - 1 : originalIndex,
196                        originalParam.getAnnotations(),
197                        originalParam.getName(),
198                        altType,
199                        originalParam.declaresDefaultValue(),
200                        varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null
201                ));
202            }
203        }
204
205        return new JavaDescriptorResolver.ValueParameterDescriptors(receiverType, resultParameters);
206    }
207
208    private static List<FunctionDescriptor> getSuperFunctionsForMethod(
209            @NotNull PsiMethodWrapper method,
210            @NotNull BindingTrace trace,
211            @NotNull ClassDescriptor containingClass
212    ) {
213        List<FunctionDescriptor> superFunctions = Lists.newArrayList();
214
215        Map<ClassDescriptor, JetType> superclassToSupertype = getSuperclassToSupertypeMap(containingClass);
216
217        Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> superclassToFunctions =
218                getSuperclassToFunctionsMultimap(method, trace.getBindingContext(), containingClass);
219
220        for (PsiMethod superMethod : PropagationHeuristics.getSuperMethods(method.getPsiMethod())) {
221            PsiClass psiClass = superMethod.getContainingClass();
222            assert psiClass != null;
223            String classFqNameString = psiClass.getQualifiedName();
224            assert classFqNameString != null;
225            FqName classFqName = new FqName(classFqNameString);
226
227            if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(classFqName).isEmpty()) {
228                for (FunctionDescriptor superFun : JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, containingClass)) {
229                    superFunctions.add(substituteSuperFunction(superclassToSupertype, superFun));
230                }
231                continue;
232            }
233
234            DeclarationDescriptor superFun = superMethod instanceof JetClsMethod
235                                             ? trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ((JetClsMethod) superMethod).getOrigin())
236                                             : findSuperFunction(superclassToFunctions.get(classFqName), superMethod);
237            if (superFun == null) {
238                // Super methods which are Object methods in interfaces are not loaded by JDR.
239                if (!MembersCache.isObjectMethodInInterface(superMethod)) {
240                    reportCantFindSuperFunction(method);
241                }
242                continue;
243            }
244
245            // TODO: Add propagation for other kotlin descriptors (KT-3621)
246            if (superFun instanceof FunctionDescriptor) {
247                superFunctions.add(substituteSuperFunction(superclassToSupertype, (FunctionDescriptor) superFun));
248            }
249        }
250
251        // sorting for diagnostic stability
252        Collections.sort(superFunctions, new Comparator<FunctionDescriptor>() {
253            @Override
254            public int compare(FunctionDescriptor fun1, FunctionDescriptor fun2) {
255                FqNameUnsafe fqName1 = getFQName(fun1.getContainingDeclaration());
256                FqNameUnsafe fqName2 = getFQName(fun2.getContainingDeclaration());
257                return fqName1.asString().compareTo(fqName2.asString());
258            }
259        });
260        return superFunctions;
261    }
262
263    @NotNull
264    private static Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> getSuperclassToFunctionsMultimap(
265            @NotNull PsiMethodWrapper method,
266            @NotNull BindingContext bindingContext,
267            @NotNull ClassDescriptor containingClass
268    ) {
269        Multimap<FqName, Pair<FunctionDescriptor, PsiMethod>> result = HashMultimap.create();
270
271        Name functionName = Name.identifier(method.getName());
272        int parameterCount = method.getParameters().size();
273
274        for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
275            ClassifierDescriptor klass = supertype.getConstructor().getDeclarationDescriptor();
276            assert klass != null;
277            FqName fqName = DescriptorUtils.getFQName(klass).toSafe();
278
279            for (FunctionDescriptor fun : klass.getDefaultType().getMemberScope().getFunctions(functionName)) {
280                CallableMemberDescriptor.Kind kind = fun.getKind();
281                if ((kind == CallableMemberDescriptor.Kind.DECLARATION || kind == CallableMemberDescriptor.Kind.DELEGATION) &&
282                    fun.getValueParameters().size() + (fun.getReceiverParameter() != null ? 1 : 0) == parameterCount) {
283                    PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun);
284                    if (declaration instanceof PsiMethod) {
285                        result.put(fqName, Pair.create(fun, (PsiMethod) declaration));
286                    } // else declaration is null or JetNamedFunction: both cases are processed later
287                }
288            }
289        }
290        return result;
291    }
292
293    @Nullable
294    private static DeclarationDescriptor findSuperFunction(
295            @NotNull Collection<Pair<FunctionDescriptor, PsiMethod>> superFunctionCandidates,
296            @NotNull PsiMethod superMethod
297    ) {
298        PsiManager psiManager = PsiManager.getInstance(superMethod.getProject());
299        for (Pair<FunctionDescriptor, PsiMethod> candidate : superFunctionCandidates) {
300            if (psiManager.areElementsEquivalent(candidate.second, superMethod)) {
301                return candidate.first;
302            }
303        }
304        return null;
305    }
306
307    private boolean checkIfShouldBeExtension() {
308        boolean someSupersExtension = false;
309        boolean someSupersNotExtension = false;
310
311        for (FunctionDescriptor superFunction : superFunctions) {
312            if (superFunction.getReceiverParameter() != null)  {
313                someSupersExtension = true;
314            }
315            else {
316                someSupersNotExtension = true;
317            }
318        }
319
320        if (someSupersExtension) {
321            if (someSupersNotExtension) {
322                reportError("Incompatible super methods: some are extension functions, some are not");
323            }
324            else {
325                return true;
326            }
327        }
328        return false;
329    }
330
331    @NotNull
332    private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
333        boolean someSupersVararg = false;
334        boolean someSupersNotVararg = false;
335        for (FunctionDescriptor superFunction : superFunctions) {
336            int originalIndex = originalParam.getIndex();
337            int index = superFunction.getReceiverParameter() != null ? originalIndex - 1 : originalIndex;
338            if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
339                someSupersVararg = true;
340            }
341            else {
342                someSupersNotVararg = true;
343            }
344        }
345
346        JetType originalVarargElementType = originalParam.getVarargElementType();
347        JetType originalType = originalParam.getType();
348
349        if (someSupersVararg && someSupersNotVararg) {
350            reportError("Incompatible super methods: some have vararg parameter, some have not");
351            return new VarargCheckResult(originalType, originalVarargElementType != null);
352        }
353
354        KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
355        if (someSupersVararg && originalVarargElementType == null) {
356            // convert to vararg
357
358            assert isArrayType(originalType);
359
360            if (builtIns.isPrimitiveArray(originalType)) {
361                // replace IntArray? with IntArray
362                return new VarargCheckResult(TypeUtils.makeNotNullable(originalType), true);
363            }
364
365            // replace Array<out Foo>? with Array<Foo>
366            JetType varargElementType = builtIns.getArrayElementType(originalType);
367            return new VarargCheckResult(builtIns.getArrayType(INVARIANT, varargElementType), true);
368        }
369        else if (someSupersNotVararg && originalVarargElementType != null) {
370            // convert to non-vararg
371
372            assert isArrayType(originalType);
373
374            if (builtIns.isPrimitiveArray(originalType)) {
375                // replace IntArray with IntArray?
376                return new VarargCheckResult(TypeUtils.makeNullable(originalType), false);
377            }
378
379            // replace Array<Foo> with Array<out Foo>?
380            return new VarargCheckResult(TypeUtils.makeNullable(builtIns.getArrayType(Variance.OUT_VARIANCE, originalVarargElementType)),
381                                         false);
382        }
383
384        return new VarargCheckResult(originalType, originalVarargElementType != null);
385    }
386
387    @NotNull
388    private JetType modifyTypeAccordingToSuperMethods(
389            @NotNull JetType autoType,
390            @NotNull List<TypeAndVariance> typesFromSuper,
391            @NotNull TypeUsage howThisTypeIsUsed
392    ) {
393        if (ErrorUtils.isErrorType(autoType)) {
394            return autoType;
395        }
396
397        boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
398        ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
399        List<TypeProjection> resultArguments = getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
400        JetScope resultScope;
401        if (resultClassifier instanceof ClassDescriptor) {
402            resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
403        }
404        else {
405            resultScope = autoType.getMemberScope();
406        }
407
408        JetTypeImpl type = new JetTypeImpl(autoType.getAnnotations(),
409                                           resultClassifier.getTypeConstructor(),
410                                           resultNullable,
411                                           resultArguments,
412                                           resultScope);
413
414        PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
415        return type;
416    }
417
418    @NotNull
419    private List<TypeProjection> getTypeArgsOfType(
420            @NotNull JetType autoType,
421            @NotNull ClassifierDescriptor classifier,
422            @NotNull List<TypeAndVariance> typesFromSuper
423    ) {
424        List<TypeProjection> autoArguments = autoType.getArguments();
425
426        if (!(classifier instanceof ClassDescriptor)) {
427            assert autoArguments.isEmpty() :
428                    "Unexpected type arguments when type constructor is not ClassDescriptor, type = " + autoType;
429            return autoArguments;
430        }
431
432        List<List<TypeProjectionAndVariance>> typeArgumentsFromSuper = calculateTypeArgumentsFromSuper((ClassDescriptor) classifier,
433                                                                                                       typesFromSuper);
434
435        // Modify type arguments using info from typesFromSuper
436        List<TypeProjection> resultArguments = Lists.newArrayList();
437        for (TypeParameterDescriptor parameter : classifier.getTypeConstructor().getParameters()) {
438            TypeProjection argument = autoArguments.get(parameter.getIndex());
439
440            JetType argumentType = argument.getType();
441            List<TypeProjectionAndVariance> projectionsFromSuper = typeArgumentsFromSuper.get(parameter.getIndex());
442            List<TypeAndVariance> argTypesFromSuper = getTypes(projectionsFromSuper);
443
444            JetType type = modifyTypeAccordingToSuperMethods(argumentType, argTypesFromSuper, TYPE_ARGUMENT);
445            Variance projectionKind = calculateArgumentProjectionKindFromSuper(argument, projectionsFromSuper);
446
447            resultArguments.add(new TypeProjection(projectionKind, type));
448        }
449        return resultArguments;
450    }
451
452    private Variance calculateArgumentProjectionKindFromSuper(
453            @NotNull TypeProjection argument,
454            @NotNull List<TypeProjectionAndVariance> projectionsFromSuper
455    ) {
456        Set<Variance> projectionKindsInSuper = Sets.newLinkedHashSet();
457        for (TypeProjectionAndVariance projectionAndVariance : projectionsFromSuper) {
458            projectionKindsInSuper.add(projectionAndVariance.typeProjection.getProjectionKind());
459        }
460
461        Variance defaultProjectionKind = argument.getProjectionKind();
462        if (projectionKindsInSuper.size() == 0) {
463            return defaultProjectionKind;
464        }
465        else if (projectionKindsInSuper.size() == 1) {
466            Variance projectionKindInSuper = projectionKindsInSuper.iterator().next();
467            if (defaultProjectionKind == INVARIANT || defaultProjectionKind == projectionKindInSuper) {
468                return projectionKindInSuper;
469            }
470            else {
471                reportError("Incompatible projection kinds in type arguments of super methods' return types: "
472                            + projectionsFromSuper + ", defined in current: " + argument);
473                return defaultProjectionKind;
474            }
475        }
476        else {
477            reportError("Incompatible projection kinds in type arguments of super methods' return types: " + projectionsFromSuper);
478            return defaultProjectionKind;
479        }
480    }
481
482    @NotNull
483    private static List<TypeAndVariance> getTypes(@NotNull List<TypeProjectionAndVariance> projections) {
484        List<TypeAndVariance> types = Lists.newArrayList();
485        for (TypeProjectionAndVariance projection : projections) {
486            types.add(new TypeAndVariance(projection.typeProjection.getType(),
487                                          merge(projection.varianceOfPosition, projection.typeProjection.getProjectionKind())));
488        }
489        return types;
490    }
491
492    private static Variance merge(Variance positionOfOuter, Variance projectionKind) {
493        // Inv<Inv<out X>>, X is in invariant position
494        if (positionOfOuter == INVARIANT) return INVARIANT;
495        // Out<X>, X is in out-position
496        if (projectionKind == INVARIANT) return positionOfOuter;
497        // Out<Out<X>>, X is in out-position
498        // In<In<X>>, X is in out-position
499        // Out<In<X>>, X is in in-position
500        // In<Out<X>>, X is in in-position
501        return positionOfOuter.superpose(projectionKind);
502    }
503
504    // Returns list with type arguments info from supertypes
505    // Example:
506    //     - Foo<A, B> is a subtype of Bar<A, List<B>>, Baz<Boolean, A>
507    //     - input: klass = Foo, typesFromSuper = [Bar<String, List<Int>>, Baz<Boolean, CharSequence>]
508    //     - output[0] = [String, CharSequence], output[1] = []
509    private static List<List<TypeProjectionAndVariance>> calculateTypeArgumentsFromSuper(
510            @NotNull ClassDescriptor klass,
511            @NotNull Collection<TypeAndVariance> typesFromSuper
512    ) {
513        // For each superclass of klass and its parameters, hold their mapping to klass' parameters
514        // #0 of Bar ->  A
515        // #1 of Bar ->  List<B>
516        // #0 of Baz ->  Boolean
517        // #1 of Baz ->  A
518        // #0 of Foo ->  A (mapped to itself)
519        // #1 of Foo ->  B (mapped to itself)
520        Multimap<TypeConstructor, TypeProjection> substitution = SubstitutionUtils.buildDeepSubstitutionMultimap(
521                TypeUtils.makeUnsubstitutedType(klass, JetScope.EMPTY));
522
523        // for each parameter of klass, hold arguments in corresponding supertypes
524        List<List<TypeProjectionAndVariance>> parameterToArgumentsFromSuper = Lists.newArrayList();
525        for (TypeParameterDescriptor ignored : klass.getTypeConstructor().getParameters()) {
526            parameterToArgumentsFromSuper.add(new ArrayList<TypeProjectionAndVariance>());
527        }
528
529        // Enumerate all types from super and all its parameters
530        for (TypeAndVariance typeFromSuper : typesFromSuper) {
531            for (TypeParameterDescriptor parameter : typeFromSuper.type.getConstructor().getParameters()) {
532                TypeProjection argument = typeFromSuper.type.getArguments().get(parameter.getIndex());
533
534                // for given example, this block is executed four times:
535                // 1. typeFromSuper = Bar<String, List<Int>>,      parameter = "#0 of Bar",  argument = String
536                // 2. typeFromSuper = Bar<String, List<Int>>,      parameter = "#1 of Bar",  argument = List<Int>
537                // 3. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#0 of Baz",  argument = Boolean
538                // 4. typeFromSuper = Baz<Boolean, CharSequence>,  parameter = "#1 of Baz",  argument = CharSequence
539
540                // if it is mapped to klass' parameter, then store it into map
541                for (TypeProjection projection : substitution.get(parameter.getTypeConstructor())) {
542                    // 1. projection = A
543                    // 2. projection = List<B>
544                    // 3. projection = Boolean
545                    // 4. projection = A
546                    ClassifierDescriptor classifier = projection.getType().getConstructor().getDeclarationDescriptor();
547
548                    // this condition is true for 1 and 4, false for 2 and 3
549                    if (classifier instanceof TypeParameterDescriptor && classifier.getContainingDeclaration() == klass) {
550                        int parameterIndex = ((TypeParameterDescriptor) classifier).getIndex();
551                        Variance effectiveVariance = parameter.getVariance().superpose(typeFromSuper.varianceOfPosition);
552                        parameterToArgumentsFromSuper.get(parameterIndex).add(new TypeProjectionAndVariance(argument, effectiveVariance));
553                    }
554                }
555            }
556        }
557        return parameterToArgumentsFromSuper;
558    }
559
560    private boolean typeMustBeNullable(
561            @NotNull JetType autoType,
562            @NotNull List<TypeAndVariance> typesFromSuper,
563            @NotNull TypeUsage howThisTypeIsUsed
564    ) {
565        boolean someSupersNotCovariantNullable = false;
566        boolean someSupersCovariantNullable = false;
567        boolean someSupersNotNull = false;
568        for (TypeAndVariance typeFromSuper : typesFromSuper) {
569            if (!typeFromSuper.type.isNullable()) {
570                someSupersNotNull = true;
571            }
572            else {
573                if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
574                    someSupersCovariantNullable = true;
575                }
576                else {
577                    someSupersNotCovariantNullable = true;
578                }
579            }
580        }
581
582        if (someSupersNotNull && someSupersNotCovariantNullable) {
583            reportError("Incompatible types in superclasses: " + typesFromSuper);
584            return autoType.isNullable();
585        }
586        else if (someSupersNotNull) {
587            return false;
588        }
589        else if (someSupersNotCovariantNullable || someSupersCovariantNullable) {
590            boolean annotatedAsNotNull = howThisTypeIsUsed != TYPE_ARGUMENT && !autoType.isNullable();
591
592            if (annotatedAsNotNull && someSupersNotCovariantNullable) {
593                reportError("In superclass type is nullable: " + typesFromSuper + ", in subclass it is not: " + autoType);
594                return true;
595            }
596
597            return !annotatedAsNotNull;
598        }
599        return autoType.isNullable();
600    }
601
602    @NotNull
603    private ClassifierDescriptor modifyTypeClassifier(
604            @NotNull JetType autoType,
605            @NotNull List<TypeAndVariance> typesFromSuper
606    ) {
607        ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
608        if (!(classifier instanceof ClassDescriptor)) {
609            assert classifier != null : "no declaration descriptor for type " + autoType;
610
611            if (classifier instanceof TypeParameterDescriptor && autoTypeParameterToModified.containsKey(classifier)) {
612                return autoTypeParameterToModified.get(classifier);
613            }
614            return classifier;
615        }
616        ClassDescriptor klass = (ClassDescriptor) classifier;
617
618        CollectionClassMapping collectionMapping = CollectionClassMapping.getInstance();
619
620        boolean someSupersMutable = false;
621        boolean someSupersCovariantReadOnly = false;
622        boolean someSupersNotCovariantReadOnly = false;
623        for (TypeAndVariance typeFromSuper : typesFromSuper) {
624            ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor();
625            if (classifierFromSuper instanceof ClassDescriptor) {
626                ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;
627
628                if (collectionMapping.isMutableCollection(classFromSuper)) {
629                    someSupersMutable = true;
630                }
631                else if (collectionMapping.isReadOnlyCollection(classFromSuper)) {
632                    if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
633                        someSupersCovariantReadOnly = true;
634                    }
635                    else {
636                        someSupersNotCovariantReadOnly = true;
637                    }
638                }
639            }
640        }
641
642        if (someSupersMutable && someSupersNotCovariantReadOnly) {
643            reportError("Incompatible types in superclasses: " + typesFromSuper);
644            return classifier;
645        }
646        else if (someSupersMutable) {
647            if (collectionMapping.isReadOnlyCollection(klass)) {
648                return collectionMapping.convertReadOnlyToMutable(klass);
649            }
650        }
651        else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
652            if (collectionMapping.isMutableCollection(klass)) {
653                return collectionMapping.convertMutableToReadOnly(klass);
654            }
655        }
656
657        ClassifierDescriptor fixed = PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper);
658        return fixed != null ? fixed : classifier;
659    }
660
661    private static Map<ClassDescriptor, JetType> getSuperclassToSupertypeMap(ClassDescriptor containingClass) {
662        Map<ClassDescriptor, JetType> superclassToSupertype = Maps.newHashMap();
663        for (JetType supertype : TypeUtils.getAllSupertypes(containingClass.getDefaultType())) {
664            ClassifierDescriptor superclass = supertype.getConstructor().getDeclarationDescriptor();
665            assert superclass instanceof ClassDescriptor;
666            superclassToSupertype.put((ClassDescriptor) superclass, supertype);
667        }
668        return superclassToSupertype;
669    }
670
671    @NotNull
672    private static FunctionDescriptor substituteSuperFunction(
673            @NotNull Map<ClassDescriptor, JetType> superclassToSupertype,
674            @NotNull FunctionDescriptor superFun
675    ) {
676        DeclarationDescriptor superFunContainer = superFun.getContainingDeclaration();
677        assert superFunContainer instanceof ClassDescriptor: superFunContainer;
678
679        JetType supertype = superclassToSupertype.get(superFunContainer);
680        assert supertype != null : "Couldn't find super type for super function: " + superFun;
681        TypeSubstitutor supertypeSubstitutor = TypeSubstitutor.create(supertype);
682
683        FunctionDescriptor substitutedSuperFun = superFun.substitute(supertypeSubstitutor);
684        assert substitutedSuperFun != null;
685        return substitutedSuperFun;
686    }
687
688    private static boolean isArrayType(@NotNull JetType type) {
689        KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
690        return builtIns.isArray(type) || builtIns.isPrimitiveArray(type);
691    }
692
693    private static void reportCantFindSuperFunction(PsiMethodWrapper method) {
694        String errorMessage = "Can't find super function for " + method.getPsiMethod() +
695                              " defined in " + method.getPsiMethod().getContainingClass();
696        if (SystemInfo.isMac) {
697            LOG.error("Remove duplicates from your JDK definition\n" + errorMessage);
698        }
699        else {
700            LOG.error(errorMessage);
701        }
702    }
703
704    private static class VarargCheckResult {
705        public final JetType parameterType;
706        public final boolean isVararg;
707
708        public VarargCheckResult(JetType parameterType, boolean isVararg) {
709            this.parameterType = parameterType;
710            this.isVararg = isVararg;
711        }
712    }
713
714    private static class TypeProjectionAndVariance {
715        public final TypeProjection typeProjection;
716        public final Variance varianceOfPosition;
717
718        public TypeProjectionAndVariance(TypeProjection typeProjection, Variance varianceOfPosition) {
719            this.typeProjection = typeProjection;
720            this.varianceOfPosition = varianceOfPosition;
721        }
722
723        public String toString() {
724            return typeProjection.toString();
725        }
726    }
727
728    static class TypeAndVariance {
729        public final JetType type;
730        public final Variance varianceOfPosition;
731
732        public TypeAndVariance(JetType type, Variance varianceOfPosition) {
733            this.type = type;
734            this.varianceOfPosition = varianceOfPosition;
735        }
736
737        public String toString() {
738            return type.toString();
739        }
740    }
741}