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