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.codegen.state;
018    
019    import com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.asm4.Type;
023    import org.jetbrains.jet.codegen.*;
024    import org.jetbrains.jet.codegen.binding.BindingTraceAware;
025    import org.jetbrains.jet.codegen.binding.CalculatedClosure;
026    import org.jetbrains.jet.codegen.binding.CodegenBinding;
027    import org.jetbrains.jet.codegen.context.CodegenContext;
028    import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
029    import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
030    import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
031    import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
032    import org.jetbrains.jet.lang.descriptors.*;
033    import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
034    import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
035    import org.jetbrains.jet.lang.psi.JetFile;
036    import org.jetbrains.jet.lang.resolve.BindingContext;
037    import org.jetbrains.jet.lang.resolve.BindingContextUtils;
038    import org.jetbrains.jet.lang.resolve.BindingTrace;
039    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
040    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
041    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
042    import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
043    import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassStaticsPackageFragmentDescriptor;
044    import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap;
045    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
046    import org.jetbrains.jet.lang.types.*;
047    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
048    
049    import java.util.ArrayList;
050    import java.util.List;
051    
052    import static org.jetbrains.asm4.Opcodes.*;
053    import static org.jetbrains.jet.codegen.AsmUtil.boxType;
054    import static org.jetbrains.jet.codegen.AsmUtil.getTraitImplThisParameterType;
055    import static org.jetbrains.jet.codegen.CodegenUtil.*;
056    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
057    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure;
058    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
059    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
060    
061    public class JetTypeMapper extends BindingTraceAware {
062    
063        private final ClassBuilderMode classBuilderMode;
064    
065        public JetTypeMapper(BindingTrace bindingTrace, ClassBuilderMode mode) {
066            super(bindingTrace);
067            classBuilderMode = mode;
068        }
069    
070        private enum JetTypeMapperMode {
071            /**
072             * foo.Bar is mapped to Lfoo/Bar;
073             */
074            IMPL,
075            /**
076             * kotlin.Int is mapped to I
077             */
078            VALUE,
079            /**
080             * kotlin.Int is mapped to Ljava/lang/Integer;
081             */
082            TYPE_PARAMETER,
083            /**
084             * kotlin.Int is mapped to Ljava/lang/Integer;
085             * No projections allowed in immediate arguments
086             */
087            SUPER_TYPE
088        }
089    
090        @NotNull
091        public Type getOwner(@NotNull DeclarationDescriptor descriptor, @NotNull OwnerKind kind, boolean isInsideModule) {
092            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
093            if (containingDeclaration instanceof PackageFragmentDescriptor) {
094                return asmTypeForPackage((PackageFragmentDescriptor) containingDeclaration, descriptor, isInsideModule);
095            }
096            else if (containingDeclaration instanceof ClassDescriptor) {
097                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
098                return kind == OwnerKind.TRAIT_IMPL ? mapTraitImpl(classDescriptor) : mapClass(classDescriptor);
099            }
100            else if (containingDeclaration instanceof ScriptDescriptor) {
101                return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) containingDeclaration);
102            }
103            else {
104                throw new UnsupportedOperationException("don't know how to generate owner for parent " + containingDeclaration);
105            }
106        }
107    
108        @NotNull
109        private Type asmTypeForPackage(
110                @NotNull PackageFragmentDescriptor packageFragment,
111                @NotNull DeclarationDescriptor descriptor,
112                boolean insideModule
113        ) {
114            return Type.getObjectType(internalNameForPackage(packageFragment, descriptor, insideModule));
115        }
116    
117        @NotNull
118        private String internalNameForPackage(
119                @NotNull PackageFragmentDescriptor packageFragment,
120                @NotNull DeclarationDescriptor descriptor,
121                boolean insideModule
122        ) {
123            if (packageFragment instanceof JavaClassStaticsPackageFragmentDescriptor) {
124                JavaClassStaticsPackageFragmentDescriptor javaPackageFragment = (JavaClassStaticsPackageFragmentDescriptor) packageFragment;
125                return mapClass(javaPackageFragment.getCorrespondingClass()).getInternalName();
126            }
127    
128            // It's not a package created for Java class statics
129            JetFile file = BindingContextUtils.getContainingFile(bindingContext, descriptor);
130            if (insideModule && file != null) {
131                return PackageCodegen.getPackagePartInternalName(file);
132            }
133            else {
134                return PackageClassUtils.getPackageClassFqName(packageFragment.getFqName()).asString().replace('.', '/');
135            }
136        }
137    
138        @NotNull
139        public Type mapReturnType(@NotNull CallableDescriptor descriptor) {
140            return mapReturnType(descriptor, null);
141        }
142    
143        @NotNull
144        private Type mapReturnType(@NotNull CallableDescriptor descriptor, @Nullable BothSignatureWriter sw) {
145            JetType returnType = descriptor.getReturnType();
146            assert returnType != null : "Function has no return type: " + descriptor;
147            if (returnType.equals(KotlinBuiltIns.getInstance().getUnitType()) && !(descriptor instanceof PropertyGetterDescriptor)) {
148                if (sw != null) {
149                    sw.writeAsmType(Type.VOID_TYPE);
150                }
151                return Type.VOID_TYPE;
152            }
153            else {
154                return mapType(returnType, sw, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE, false);
155            }
156        }
157    
158        @NotNull
159        private Type mapType(@NotNull JetType jetType, @NotNull JetTypeMapperMode mode) {
160            return mapType(jetType, null, mode);
161        }
162    
163        @NotNull
164        public Type mapSupertype(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor) {
165            return mapType(jetType, signatureVisitor, JetTypeMapperMode.SUPER_TYPE);
166        }
167    
168        @NotNull
169        public Type mapClass(@NotNull ClassifierDescriptor classifier) {
170            return mapType(classifier.getDefaultType(), null, JetTypeMapperMode.IMPL);
171        }
172    
173        @NotNull
174        public Type mapType(@NotNull JetType jetType) {
175            return mapType(jetType, null, JetTypeMapperMode.VALUE);
176        }
177    
178        @NotNull
179        public Type mapType(@NotNull CallableDescriptor descriptor) {
180            //noinspection ConstantConditions
181            return mapType(descriptor.getReturnType());
182        }
183    
184        @NotNull
185        public Type mapType(@NotNull ClassifierDescriptor descriptor) {
186            return mapType(descriptor.getDefaultType());
187        }
188    
189        @NotNull
190        private Type mapType(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode mode) {
191            return mapType(jetType, signatureVisitor, mode, Variance.INVARIANT, false);
192        }
193    
194        @NotNull
195        private Type mapType(
196                @NotNull JetType jetType,
197                @Nullable BothSignatureWriter signatureVisitor,
198                @NotNull JetTypeMapperMode kind,
199                @NotNull Variance howThisTypeIsUsed,
200                boolean arrayParameter
201        ) {
202            Type known = null;
203            DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
204    
205            if (descriptor instanceof ClassDescriptor) {
206                FqNameUnsafe className = DescriptorUtils.getFqName(descriptor);
207                if (className.isSafe()) {
208                    known = KotlinToJavaTypesMap.getInstance().getJavaAnalog(className.toSafe(), jetType.isNullable());
209                }
210            }
211    
212            boolean projectionsAllowed = kind != JetTypeMapperMode.SUPER_TYPE;
213            if (known != null) {
214                if (kind == JetTypeMapperMode.VALUE) {
215                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
216                }
217                else if (kind == JetTypeMapperMode.TYPE_PARAMETER || kind == JetTypeMapperMode.SUPER_TYPE) {
218                    return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed, arrayParameter, projectionsAllowed);
219                }
220                else if (kind == JetTypeMapperMode.IMPL) {
221                    // TODO: enable and fix tests
222                    //throw new IllegalStateException("must not map known type to IMPL when not compiling builtins: " + jetType);
223                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
224                }
225                else {
226                    throw new IllegalStateException("unknown kind: " + kind);
227                }
228            }
229    
230            TypeConstructor constructor = jetType.getConstructor();
231            if (constructor instanceof IntersectionTypeConstructor) {
232                jetType = CommonSupertypes.commonSupertype(new ArrayList<JetType>(constructor.getSupertypes()));
233            }
234    
235            if (descriptor == null) {
236                throw new UnsupportedOperationException("no descriptor for type constructor of " + jetType);
237            }
238    
239            if (ErrorUtils.isError(descriptor)) {
240                if (classBuilderMode != ClassBuilderMode.LIGHT_CLASSES) {
241                    throw new IllegalStateException(generateErrorMessageForErrorType(jetType, descriptor));
242                }
243                Type asmType = Type.getObjectType("error/NonExistentClass");
244                if (signatureVisitor != null) {
245                    signatureVisitor.writeAsmType(asmType);
246                }
247                return asmType;
248            }
249    
250            if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.getInstance().isArray(jetType)) {
251                if (jetType.getArguments().size() != 1) {
252                    throw new UnsupportedOperationException("arrays must have one type argument");
253                }
254                TypeProjection memberProjection = jetType.getArguments().get(0);
255                JetType memberType = memberProjection.getType();
256    
257                if (signatureVisitor != null) {
258                    signatureVisitor.writeArrayType();
259                    mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER, memberProjection.getProjectionKind(), true);
260                    signatureVisitor.writeArrayEnd();
261                }
262    
263                if (memberType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
264                    return AsmTypeConstants.getType(Object[].class);
265                }
266    
267                return Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor());
268            }
269    
270            if (descriptor instanceof ClassDescriptor) {
271                Type asmType = getAsmType(bindingTrace, (ClassDescriptor) descriptor);
272                writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, projectionsAllowed);
273                return asmType;
274            }
275    
276            if (descriptor instanceof TypeParameterDescriptor) {
277                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
278                Type type = mapType(typeParameterDescriptor.getUpperBounds().iterator().next(), kind);
279                if (signatureVisitor != null) {
280                    signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), type);
281                }
282                return type;
283            }
284    
285            throw new UnsupportedOperationException("Unknown type " + jetType);
286        }
287    
288        @NotNull
289        public Type mapTraitImpl(@NotNull ClassDescriptor descriptor) {
290            return Type.getObjectType(getAsmType(bindingTrace, descriptor).getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
291        }
292    
293        @NotNull
294        private String generateErrorMessageForErrorType(@NotNull JetType type, @NotNull DeclarationDescriptor descriptor) {
295            PsiElement declarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
296            PsiElement parentDeclarationElement = null;
297            if (declarationElement != null) {
298                DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
299                if (containingDeclaration != null) {
300                    parentDeclarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, containingDeclaration);
301                }
302            }
303    
304            return String.format("Error types are not allowed when classBuilderMode = %s. " +
305                                 "Type: %s (%s). Descriptor: %s. For declaration %s:%s in %s:%s",
306                                 classBuilderMode,
307                                 type,
308                                 type.getClass().getSimpleName(),
309                                 descriptor,
310                                 declarationElement,
311                                 declarationElement != null ? declarationElement.getText() : "null",
312                                 parentDeclarationElement,
313                                 parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
314        }
315    
316        private void writeGenericType(
317                BothSignatureWriter signatureVisitor,
318                Type asmType,
319                JetType jetType,
320                Variance howThisTypeIsUsed,
321                boolean projectionsAllowed
322        ) {
323            if (signatureVisitor != null) {
324                signatureVisitor.writeClassBegin(asmType);
325    
326                List<TypeProjection> arguments = jetType.getArguments();
327                for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
328                    TypeProjection argument = arguments.get(parameter.getIndex());
329    
330                    Variance projectionKind = projectionsAllowed
331                                              ? getEffectiveVariance(
332                                                        parameter.getVariance(),
333                                                        argument.getProjectionKind(),
334                                                        howThisTypeIsUsed
335                                                )
336                                              : Variance.INVARIANT;
337                    signatureVisitor.writeTypeArgument(projectionKind);
338    
339                    mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
340                    signatureVisitor.writeTypeArgumentEnd();
341                }
342                signatureVisitor.writeClassEnd();
343            }
344        }
345    
346        private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) {
347            // Return type must not contain wildcards
348            if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind;
349    
350            if (parameterVariance == Variance.INVARIANT) {
351                return projectionKind;
352            }
353            if (projectionKind == Variance.INVARIANT) {
354                return parameterVariance;
355            }
356            if (parameterVariance == projectionKind) {
357                return parameterVariance;
358            }
359    
360            // In<out X> = In<*>
361            // Out<in X> = Out<*>
362            return Variance.OUT_VARIANCE;
363        }
364    
365        private Type mapKnownAsmType(
366                JetType jetType,
367                Type asmType,
368                @Nullable BothSignatureWriter signatureVisitor,
369                @NotNull Variance howThisTypeIsUsed
370        ) {
371            return mapKnownAsmType(jetType, asmType, signatureVisitor, howThisTypeIsUsed, false, true);
372        }
373    
374        private Type mapKnownAsmType(
375                JetType jetType,
376                Type asmType,
377                @Nullable BothSignatureWriter signatureVisitor,
378                @NotNull Variance howThisTypeIsUsed,
379                boolean arrayParameter,
380                boolean allowProjections
381        ) {
382            if (signatureVisitor != null) {
383                if (jetType.getArguments().isEmpty()) {
384                    if (arrayParameter && howThisTypeIsUsed == Variance.IN_VARIANCE) {
385                        asmType = AsmTypeConstants.OBJECT_TYPE;
386                    }
387                    signatureVisitor.writeAsmType(asmType);
388                }
389                else {
390                    writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, allowProjections);
391                }
392            }
393            return asmType;
394        }
395    
396        @NotNull
397        public CallableMethod mapToCallableMethod(
398                @NotNull FunctionDescriptor functionDescriptor,
399                boolean superCall,
400                @NotNull CodegenContext<?> context
401        ) {
402            DeclarationDescriptor functionParent = functionDescriptor.getOriginal().getContainingDeclaration();
403    
404            functionDescriptor = unwrapFakeOverride(functionDescriptor.getOriginal());
405    
406            JvmMethodSignature descriptor = mapSignature(functionDescriptor.getOriginal());
407            Type owner;
408            Type ownerForDefaultImpl;
409            Type ownerForDefaultParam;
410            int invokeOpcode;
411            Type thisClass;
412            Type calleeType = null;
413    
414            if (isLocalNamedFun(functionDescriptor)) {
415                functionDescriptor = functionDescriptor.getOriginal();
416    
417                owner = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
418                ownerForDefaultImpl = ownerForDefaultParam = thisClass = owner;
419                invokeOpcode = INVOKEVIRTUAL;
420                descriptor = mapSignature(functionDescriptor);
421                calleeType = owner;
422            }
423            else if (functionParent instanceof PackageFragmentDescriptor) {
424                assert !superCall;
425                owner = asmTypeForPackage((PackageFragmentDescriptor) functionParent, functionDescriptor,
426                                          isCallInsideSameModuleAsDeclared(functionDescriptor, context));
427                ownerForDefaultImpl = ownerForDefaultParam = owner;
428                invokeOpcode = INVOKESTATIC;
429                thisClass = null;
430            }
431            else if (functionDescriptor instanceof ConstructorDescriptor) {
432                assert !superCall;
433                owner = mapClass((ClassDescriptor) functionParent);
434                ownerForDefaultImpl = ownerForDefaultParam = owner;
435                invokeOpcode = INVOKESPECIAL;
436                thisClass = null;
437            }
438            else if (functionParent instanceof ScriptDescriptor) {
439                thisClass = owner = ownerForDefaultParam = ownerForDefaultImpl =
440                        asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) functionParent);
441                invokeOpcode = INVOKEVIRTUAL;
442            }
443            else if (functionParent instanceof ClassDescriptor) {
444    
445                FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
446    
447                ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
448                ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
449    
450                boolean originalIsInterface = isInterface(declarationOwner);
451                boolean currentIsInterface = isInterface(currentOwner);
452    
453                ClassDescriptor receiver;
454                if (currentIsInterface && !originalIsInterface) {
455                    receiver = declarationOwner;
456                }
457                else {
458                    receiver = currentOwner;
459                }
460    
461                boolean isInterface = originalIsInterface && currentIsInterface;
462                owner = mapClass(receiver);
463    
464                ClassDescriptor declarationOwnerForDefault = (ClassDescriptor) findBaseDeclaration(functionDescriptor).getContainingDeclaration();
465                ownerForDefaultParam = mapClass(declarationOwnerForDefault);
466                ownerForDefaultImpl = Type.getObjectType(
467                        ownerForDefaultParam.getInternalName() + (isInterface(declarationOwnerForDefault) ? JvmAbi.TRAIT_IMPL_SUFFIX : ""));
468                if (isInterface) {
469                    invokeOpcode = superCall ? INVOKESTATIC : INVOKEINTERFACE;
470                }
471                else {
472                    if (isAccessor(functionDescriptor)) {
473                        invokeOpcode = INVOKESTATIC;
474                    }
475                    else {
476                        boolean isPrivateFunInvocation = isCallInsideSameClassAsDeclared(functionDescriptor, context) &&
477                                                         functionDescriptor.getVisibility() == Visibilities.PRIVATE;
478                        invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
479                    }
480                }
481    
482                if (isInterface && superCall) {
483                    descriptor = mapSignature(functionDescriptor, OwnerKind.TRAIT_IMPL);
484                    owner = Type.getObjectType(owner.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
485                }
486                thisClass = mapType(receiver.getDefaultType());
487            }
488            else {
489                throw new UnsupportedOperationException("unknown function parent");
490            }
491    
492    
493            Type receiverParameterType;
494            ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getReceiverParameter();
495            if (receiverParameter != null) {
496                receiverParameterType = mapType(receiverParameter.getType());
497            }
498            else {
499                receiverParameterType = null;
500            }
501            return new CallableMethod(
502                    owner, ownerForDefaultImpl, ownerForDefaultParam, descriptor, invokeOpcode,
503                    thisClass, receiverParameterType, calleeType);
504        }
505    
506        public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
507            return descriptor instanceof AccessorForFunctionDescriptor ||
508                   descriptor instanceof AccessorForPropertyDescriptor ||
509                   descriptor instanceof AccessorForPropertyDescriptor.Getter ||
510                   descriptor instanceof AccessorForPropertyDescriptor.Setter;
511        }
512    
513        @NotNull
514        private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) {
515            if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
516                return function;
517            }
518            return findBaseDeclaration(function);
519        }
520    
521        @NotNull
522        private static FunctionDescriptor findBaseDeclaration(@NotNull FunctionDescriptor function) {
523            if (function.getOverriddenDescriptors().isEmpty()) {
524                return function;
525            }
526            else {
527                // TODO: prefer class to interface
528                return findBaseDeclaration(function.getOverriddenDescriptors().iterator().next());
529            }
530        }
531    
532        @NotNull
533        private static String mapFunctionName(@NotNull FunctionDescriptor descriptor) {
534            if (descriptor instanceof PropertyAccessorDescriptor) {
535                PropertyDescriptor property = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
536                if (isAnnotationClass(property.getContainingDeclaration())) {
537                    return property.getName().asString();
538                }
539    
540                if (descriptor instanceof PropertyGetterDescriptor) {
541                    return PropertyCodegen.getterName(property.getName());
542                }
543                else {
544                    return PropertyCodegen.setterName(property.getName());
545                }
546            }
547            else if (isLocalNamedFun(descriptor) || descriptor instanceof AnonymousFunctionDescriptor) {
548                return "invoke";
549            }
550            else {
551                return descriptor.getName().asString();
552            }
553        }
554    
555        @NotNull
556        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor descriptor) {
557            return mapSignature(descriptor, OwnerKind.IMPLEMENTATION);
558        }
559    
560        @NotNull
561        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind) {
562            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
563    
564            if (f instanceof ConstructorDescriptor) {
565                sw.writeParametersStart();
566                writeAdditionalConstructorParameters((ConstructorDescriptor) f, sw);
567    
568                for (ValueParameterDescriptor parameter : f.getOriginal().getValueParameters()) {
569                    writeParameter(sw, parameter.getType());
570                }
571    
572                writeVoidReturn(sw);
573            }
574            else {
575                if (f instanceof PropertyAccessorDescriptor) {
576                    writeFormalTypeParameters(((PropertyAccessorDescriptor) f).getCorrespondingProperty().getTypeParameters(), sw);
577                }
578                else {
579                    writeFormalTypeParameters(f.getTypeParameters(), sw);
580                }
581    
582                sw.writeParametersStart();
583                writeThisIfNeeded(f, kind, sw);
584                writeReceiverIfNeeded(f.getReceiverParameter(), sw);
585    
586                for (ValueParameterDescriptor parameter : f.getValueParameters()) {
587                    writeParameter(sw, parameter.getType());
588                }
589    
590                sw.writeReturnType();
591                if (forceBoxedReturnType(f)) {
592                    // TYPE_PARAMETER is a hack to automatically box the return type
593                    //noinspection ConstantConditions
594                    mapType(f.getReturnType(), sw, JetTypeMapperMode.TYPE_PARAMETER);
595                }
596                else {
597                    mapReturnType(f, sw);
598                }
599                sw.writeReturnTypeEnd();
600            }
601    
602            return sw.makeJvmMethodSignature(mapFunctionName(f));
603        }
604    
605        /**
606         * @return true iff a given function descriptor should be compiled to a method with boxed return type regardless of whether return type
607         * of that descriptor is nullable or not. This happens when a function returning a value of a primitive type overrides another function
608         * with a non-primitive return type. In that case the generated method's return type should be boxed: otherwise it's not possible to use
609         * this class from Java since javac issues errors when loading the class (incompatible return types)
610         */
611        private static boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
612            //noinspection ConstantConditions
613            if (!KotlinBuiltIns.getInstance().isPrimitiveType(descriptor.getReturnType())) return false;
614    
615            for (FunctionDescriptor overridden : descriptor.getOverriddenDescriptors()) {
616                //noinspection ConstantConditions
617                if (!KotlinBuiltIns.getInstance().isPrimitiveType(overridden.getOriginal().getReturnType())) return true;
618            }
619    
620            return false;
621        }
622    
623        private static void writeVoidReturn(@NotNull BothSignatureWriter sw) {
624            sw.writeReturnType();
625            sw.writeAsmType(Type.VOID_TYPE);
626            sw.writeReturnTypeEnd();
627        }
628    
629        @Nullable
630        public String mapFieldSignature(@NotNull JetType backingFieldType) {
631            BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
632            mapType(backingFieldType, signatureVisitor, JetTypeMapperMode.VALUE);
633            return signatureVisitor.makeJavaGenericSignature();
634        }
635    
636        private void writeThisIfNeeded(
637                @NotNull CallableMemberDescriptor descriptor,
638                @NotNull OwnerKind kind,
639                @NotNull BothSignatureWriter sw
640        ) {
641            if (kind == OwnerKind.TRAIT_IMPL) {
642                ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
643                Type type = getTraitImplThisParameterType(containingDeclaration, this);
644    
645                sw.writeParameterType(JvmMethodParameterKind.THIS);
646                sw.writeAsmType(type);
647                sw.writeParameterTypeEnd();
648            }
649            else if (isAccessor(descriptor) && descriptor.getExpectedThisObject() != null) {
650                sw.writeParameterType(JvmMethodParameterKind.THIS);
651                mapType(((ClassifierDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), sw, JetTypeMapperMode.VALUE);
652                sw.writeParameterTypeEnd();
653            }
654        }
655    
656    
657        public void writeFormalTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull BothSignatureWriter sw) {
658            for (TypeParameterDescriptor typeParameter : typeParameters) {
659                writeFormalTypeParameter(typeParameter, sw);
660            }
661        }
662    
663        private void writeFormalTypeParameter(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull BothSignatureWriter sw) {
664            sw.writeFormalTypeParameter(typeParameterDescriptor.getName().asString());
665    
666            classBound:
667            {
668                sw.writeClassBound();
669    
670                for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
671                    if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
672                        if (!isInterface(jetType)) {
673                            mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
674                            break classBound;
675                        }
676                    }
677                }
678    
679                // "extends Object" is optional according to ClassFileFormat-Java5.pdf
680                // but javac complaints to signature:
681                // <P:>Ljava/lang/Object;
682                // TODO: avoid writing java/lang/Object if interface list is not empty
683            }
684            sw.writeClassBoundEnd();
685    
686            for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
687                if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
688                    if (isInterface(jetType)) {
689                        sw.writeInterfaceBound();
690                        mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
691                        sw.writeInterfaceBoundEnd();
692                    }
693                }
694                if (jetType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
695                    sw.writeInterfaceBound();
696                    mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
697                    sw.writeInterfaceBoundEnd();
698                }
699            }
700        }
701    
702        private void writeReceiverIfNeeded(@Nullable ReceiverParameterDescriptor receiver, @NotNull BothSignatureWriter sw) {
703            if (receiver != null) {
704                sw.writeParameterType(JvmMethodParameterKind.RECEIVER);
705                mapType(receiver.getType(), sw, JetTypeMapperMode.VALUE);
706                sw.writeParameterTypeEnd();
707            }
708        }
709    
710        private void writeParameter(@NotNull BothSignatureWriter sw, @NotNull JetType type) {
711            sw.writeParameterType(JvmMethodParameterKind.VALUE);
712            mapType(type, sw, JetTypeMapperMode.VALUE);
713            sw.writeParameterTypeEnd();
714        }
715    
716        private void writeAdditionalConstructorParameters(
717                @NotNull ConstructorDescriptor descriptor,
718                @NotNull BothSignatureWriter signatureWriter
719        ) {
720            CalculatedClosure closure = bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration());
721    
722            ClassDescriptor captureThis = getExpectedThisObjectForConstructorCall(descriptor, closure);
723            if (captureThis != null) {
724                signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
725                mapType(captureThis.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
726                signatureWriter.writeParameterTypeEnd();
727            }
728    
729            JetType captureReceiverType = closure != null ? closure.getCaptureReceiverType() : null;
730            if (captureReceiverType != null) {
731                signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
732                mapType(captureReceiverType, signatureWriter, JetTypeMapperMode.VALUE);
733                signatureWriter.writeParameterTypeEnd();
734            }
735    
736            ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
737            if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
738                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_NAME);
739                mapType(KotlinBuiltIns.getInstance().getStringType(), signatureWriter, JetTypeMapperMode.VALUE);
740                signatureWriter.writeParameterTypeEnd();
741                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_ORDINAL);
742                mapType(KotlinBuiltIns.getInstance().getIntType(), signatureWriter, JetTypeMapperMode.VALUE);
743                signatureWriter.writeParameterTypeEnd();
744            }
745    
746            if (closure == null) return;
747    
748            for (DeclarationDescriptor variableDescriptor : closure.getCaptureVariables().keySet()) {
749                Type type;
750                if (variableDescriptor instanceof VariableDescriptor && !(variableDescriptor instanceof PropertyDescriptor)) {
751                    Type sharedVarType = getSharedVarType(variableDescriptor);
752                    if (sharedVarType == null) {
753                        sharedVarType = mapType(((VariableDescriptor) variableDescriptor).getType());
754                    }
755                    type = sharedVarType;
756                }
757                else if (isLocalNamedFun(variableDescriptor)) {
758                    type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) variableDescriptor);
759                }
760                else {
761                    type = null;
762                }
763    
764                if (type != null) {
765                    signatureWriter.writeParameterType(JvmMethodParameterKind.SHARED_VAR);
766                    signatureWriter.writeAsmType(type);
767                    signatureWriter.writeParameterTypeEnd();
768                }
769            }
770    
771            JetDelegatorToSuperCall superCall = closure.getSuperCall();
772            if (superCall != null) {
773                DeclarationDescriptor superDescriptor = bindingContext
774                        .get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
775    
776                if (superDescriptor instanceof ConstructorDescriptor && isAnonymousObject(descriptor.getContainingDeclaration())) {
777                    for (JvmMethodParameterSignature parameter : mapSignature((ConstructorDescriptor) superDescriptor).getValueParameters()) {
778                        signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_CALL_PARAM);
779                        signatureWriter.writeAsmType(parameter.getAsmType());
780                        signatureWriter.writeParameterTypeEnd();
781                    }
782                }
783            }
784        }
785    
786        @NotNull
787        public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
788            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
789    
790            signatureWriter.writeParametersStart();
791    
792            for (ScriptDescriptor importedScript : importedScripts) {
793                signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
794                ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
795                assert descriptor != null;
796                mapType(descriptor.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
797                signatureWriter.writeParameterTypeEnd();
798            }
799    
800            for (ValueParameterDescriptor valueParameter : script.getValueParameters()) {
801                writeParameter(signatureWriter, valueParameter.getType());
802            }
803    
804            writeVoidReturn(signatureWriter);
805    
806            return signatureWriter.makeJvmMethodSignature("<init>");
807        }
808    
809        @NotNull
810        public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor) {
811            JvmMethodSignature method = mapSignature(descriptor);
812            ClassDescriptor container = descriptor.getContainingDeclaration();
813            Type owner = mapClass(container);
814            if (owner.getSort() != Type.OBJECT) {
815                throw new IllegalStateException("type must have been mapped to object: " + container.getDefaultType() + ", actual: " + owner);
816            }
817            return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL, null, null, null);
818        }
819    
820        public Type getSharedVarType(DeclarationDescriptor descriptor) {
821            if (descriptor instanceof PropertyDescriptor) {
822                return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
823            }
824            else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
825                return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
826            }
827            else if (descriptor instanceof FunctionDescriptor) {
828                return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
829            }
830            else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
831                JetType outType = ((VariableDescriptor) descriptor).getType();
832                return StackValue.sharedTypeForType(mapType(outType));
833            }
834            return null;
835        }
836    
837        @NotNull
838        private static JvmMethodSignature erasedInvokeSignature(@NotNull FunctionDescriptor descriptor) {
839            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
840    
841            int paramCount = descriptor.getValueParameters().size();
842            if (descriptor.getReceiverParameter() != null) {
843                paramCount++;
844            }
845    
846            sw.writeParametersStart();
847    
848            for (int i = 0; i < paramCount; ++i) {
849                sw.writeParameterType(JvmMethodParameterKind.VALUE);
850                sw.writeAsmType(OBJECT_TYPE);
851                sw.writeParameterTypeEnd();
852            }
853    
854            sw.writeReturnType();
855            sw.writeAsmType(OBJECT_TYPE);
856            sw.writeReturnTypeEnd();
857    
858            return sw.makeJvmMethodSignature("invoke");
859        }
860    }