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