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.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
028    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
029    import org.jetbrains.jet.lang.resolve.java.jvmSignature.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    import org.jetbrains.org.objectweb.asm.commons.Method;
049    
050    import java.util.ArrayList;
051    import java.util.List;
052    
053    import static org.jetbrains.jet.codegen.AsmUtil.*;
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                return Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor());
266            }
267    
268            if (descriptor instanceof ClassDescriptor) {
269                Type asmType = getAsmType(bindingContext, (ClassDescriptor) descriptor);
270                writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, projectionsAllowed);
271                return asmType;
272            }
273    
274            if (descriptor instanceof TypeParameterDescriptor) {
275                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
276                Type type = mapType(typeParameterDescriptor.getUpperBounds().iterator().next(), kind);
277                if (signatureVisitor != null) {
278                    signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), type);
279                }
280                return type;
281            }
282    
283            throw new UnsupportedOperationException("Unknown type " + jetType);
284        }
285    
286        @NotNull
287        public Type mapTraitImpl(@NotNull ClassDescriptor descriptor) {
288            return Type.getObjectType(getAsmType(bindingContext, descriptor).getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
289        }
290    
291        @NotNull
292        private String generateErrorMessageForErrorType(@NotNull JetType type, @NotNull DeclarationDescriptor descriptor) {
293            PsiElement declarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
294            PsiElement parentDeclarationElement = null;
295            if (declarationElement != null) {
296                DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
297                if (containingDeclaration != null) {
298                    parentDeclarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, containingDeclaration);
299                }
300            }
301    
302            return String.format("Error types are not allowed when classBuilderMode = %s. " +
303                                 "Type: %s (%s). Descriptor: %s. For declaration %s:%s in %s:%s",
304                                 classBuilderMode,
305                                 type,
306                                 type.getClass().getSimpleName(),
307                                 descriptor,
308                                 declarationElement,
309                                 declarationElement != null ? declarationElement.getText() : "null",
310                                 parentDeclarationElement,
311                                 parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
312        }
313    
314        private void writeGenericType(
315                BothSignatureWriter signatureVisitor,
316                Type asmType,
317                JetType jetType,
318                Variance howThisTypeIsUsed,
319                boolean projectionsAllowed
320        ) {
321            if (signatureVisitor != null) {
322                signatureVisitor.writeClassBegin(asmType);
323    
324                List<TypeProjection> arguments = jetType.getArguments();
325                for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
326                    TypeProjection argument = arguments.get(parameter.getIndex());
327    
328                    Variance projectionKind = projectionsAllowed
329                                              ? getEffectiveVariance(
330                                                        parameter.getVariance(),
331                                                        argument.getProjectionKind(),
332                                                        howThisTypeIsUsed
333                                                )
334                                              : Variance.INVARIANT;
335                    signatureVisitor.writeTypeArgument(projectionKind);
336    
337                    mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
338                    signatureVisitor.writeTypeArgumentEnd();
339                }
340                signatureVisitor.writeClassEnd();
341            }
342        }
343    
344        private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) {
345            // Return type must not contain wildcards
346            if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind;
347    
348            if (parameterVariance == Variance.INVARIANT) {
349                return projectionKind;
350            }
351            if (projectionKind == Variance.INVARIANT) {
352                return parameterVariance;
353            }
354            if (parameterVariance == projectionKind) {
355                return parameterVariance;
356            }
357    
358            // In<out X> = In<*>
359            // Out<in X> = Out<*>
360            return Variance.OUT_VARIANCE;
361        }
362    
363        private Type mapKnownAsmType(
364                JetType jetType,
365                Type asmType,
366                @Nullable BothSignatureWriter signatureVisitor,
367                @NotNull Variance howThisTypeIsUsed
368        ) {
369            return mapKnownAsmType(jetType, asmType, signatureVisitor, howThisTypeIsUsed, false, true);
370        }
371    
372        private Type mapKnownAsmType(
373                JetType jetType,
374                Type asmType,
375                @Nullable BothSignatureWriter signatureVisitor,
376                @NotNull Variance howThisTypeIsUsed,
377                boolean arrayParameter,
378                boolean allowProjections
379        ) {
380            if (signatureVisitor != null) {
381                if (jetType.getArguments().isEmpty()) {
382                    if (arrayParameter && howThisTypeIsUsed == Variance.IN_VARIANCE) {
383                        asmType = AsmTypeConstants.OBJECT_TYPE;
384                    }
385                    signatureVisitor.writeAsmType(asmType);
386                }
387                else {
388                    writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, allowProjections);
389                }
390            }
391            return asmType;
392        }
393    
394        @NotNull
395        public CallableMethod mapToCallableMethod(
396                @NotNull FunctionDescriptor descriptor,
397                boolean superCall,
398                @NotNull CodegenContext<?> context
399        ) {
400            DeclarationDescriptor functionParent = descriptor.getOriginal().getContainingDeclaration();
401    
402            FunctionDescriptor functionDescriptor = unwrapFakeOverride(descriptor.getOriginal());
403    
404            JvmMethodSignature signature;
405            Type owner;
406            Type ownerForDefaultImpl;
407            Type ownerForDefaultParam;
408            int invokeOpcode;
409            Type thisClass;
410    
411            if (functionParent instanceof ClassDescriptor) {
412                FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
413    
414                ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
415                ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
416    
417                boolean originalIsInterface = isInterface(declarationOwner);
418                boolean currentIsInterface = isInterface(currentOwner);
419    
420                boolean isInterface = currentIsInterface && originalIsInterface;
421    
422                ClassDescriptor ownerForDefault = (ClassDescriptor) findBaseDeclaration(functionDescriptor).getContainingDeclaration();
423                ownerForDefaultParam = mapClass(ownerForDefault);
424                ownerForDefaultImpl = isInterface(ownerForDefault) ? mapTraitImpl(ownerForDefault) : ownerForDefaultParam;
425    
426                if (isInterface && superCall) {
427                    invokeOpcode = INVOKESTATIC;
428                    signature = mapSignature(functionDescriptor, OwnerKind.TRAIT_IMPL);
429                    owner = mapTraitImpl(currentOwner);
430                    thisClass = mapClass(currentOwner);
431                }
432                else {
433                    if (isAccessor(functionDescriptor)) {
434                        invokeOpcode = INVOKESTATIC;
435                    }
436                    else if (isInterface) {
437                        invokeOpcode = INVOKEINTERFACE;
438                    }
439                    else {
440                        boolean isPrivateFunInvocation = isCallInsideSameClassAsDeclared(functionDescriptor, context) &&
441                                                         functionDescriptor.getVisibility() == Visibilities.PRIVATE;
442                        invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
443                    }
444    
445                    signature = mapSignature(functionDescriptor.getOriginal());
446    
447                    ClassDescriptor receiver = currentIsInterface && !originalIsInterface ? declarationOwner : currentOwner;
448                    owner = mapClass(receiver);
449                    thisClass = owner;
450                }
451            }
452            else {
453                signature = mapSignature(functionDescriptor.getOriginal());
454                owner = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context));
455                ownerForDefaultParam = owner;
456                ownerForDefaultImpl = owner;
457                if (functionParent instanceof PackageFragmentDescriptor) {
458                    invokeOpcode = INVOKESTATIC;
459                    thisClass = null;
460                }
461                else if (functionDescriptor instanceof ConstructorDescriptor) {
462                    invokeOpcode = INVOKESPECIAL;
463                    thisClass = null;
464                }
465                else {
466                    invokeOpcode = INVOKEVIRTUAL;
467                    thisClass = owner;
468                }
469            }
470    
471            Type calleeType = isLocalNamedFun(functionDescriptor) ? owner : null;
472    
473            Type receiverParameterType;
474            ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getReceiverParameter();
475            if (receiverParameter != null) {
476                receiverParameterType = mapType(receiverParameter.getType());
477            }
478            else {
479                receiverParameterType = null;
480            }
481            return new CallableMethod(
482                    owner, ownerForDefaultImpl, ownerForDefaultParam, signature, invokeOpcode,
483                    thisClass, receiverParameterType, calleeType);
484        }
485    
486        public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
487            return descriptor instanceof AccessorForFunctionDescriptor ||
488                   descriptor instanceof AccessorForPropertyDescriptor ||
489                   descriptor instanceof AccessorForPropertyDescriptor.Getter ||
490                   descriptor instanceof AccessorForPropertyDescriptor.Setter;
491        }
492    
493        @NotNull
494        private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) {
495            if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
496                return function;
497            }
498            return findBaseDeclaration(function);
499        }
500    
501        @NotNull
502        private static FunctionDescriptor findBaseDeclaration(@NotNull FunctionDescriptor function) {
503            if (function.getOverriddenDescriptors().isEmpty()) {
504                return function;
505            }
506            else {
507                // TODO: prefer class to interface
508                return findBaseDeclaration(function.getOverriddenDescriptors().iterator().next());
509            }
510        }
511    
512        @NotNull
513        private static String mapFunctionName(@NotNull FunctionDescriptor descriptor) {
514            if (descriptor instanceof PropertyAccessorDescriptor) {
515                PropertyDescriptor property = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
516                if (isAnnotationClass(property.getContainingDeclaration())) {
517                    return property.getName().asString();
518                }
519    
520                if (descriptor instanceof PropertyGetterDescriptor) {
521                    return PropertyCodegen.getterName(property.getName());
522                }
523                else {
524                    return PropertyCodegen.setterName(property.getName());
525                }
526            }
527            else if (isLocalNamedFun(descriptor) || descriptor instanceof AnonymousFunctionDescriptor) {
528                return "invoke";
529            }
530            else {
531                return descriptor.getName().asString();
532            }
533        }
534    
535        @NotNull
536        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor descriptor) {
537            return mapSignature(descriptor, OwnerKind.IMPLEMENTATION);
538        }
539    
540        @NotNull
541        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind) {
542            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
543    
544            if (f instanceof ConstructorDescriptor) {
545                sw.writeParametersStart();
546                writeAdditionalConstructorParameters((ConstructorDescriptor) f, sw);
547    
548                for (ValueParameterDescriptor parameter : f.getOriginal().getValueParameters()) {
549                    writeParameter(sw, parameter.getType());
550                }
551    
552                writeVoidReturn(sw);
553            }
554            else {
555                if (f instanceof PropertyAccessorDescriptor) {
556                    writeFormalTypeParameters(((PropertyAccessorDescriptor) f).getCorrespondingProperty().getTypeParameters(), sw);
557                }
558                else {
559                    writeFormalTypeParameters(f.getTypeParameters(), sw);
560                }
561    
562                sw.writeParametersStart();
563                writeThisIfNeeded(f, kind, sw);
564                writeReceiverIfNeeded(f.getReceiverParameter(), sw);
565    
566                for (ValueParameterDescriptor parameter : f.getValueParameters()) {
567                    writeParameter(sw, parameter.getType());
568                }
569    
570                sw.writeReturnType();
571                if (forceBoxedReturnType(f)) {
572                    // TYPE_PARAMETER is a hack to automatically box the return type
573                    //noinspection ConstantConditions
574                    mapType(f.getReturnType(), sw, JetTypeMapperMode.TYPE_PARAMETER);
575                }
576                else {
577                    mapReturnType(f, sw);
578                }
579                sw.writeReturnTypeEnd();
580            }
581    
582            return sw.makeJvmMethodSignature(mapFunctionName(f));
583        }
584    
585        @NotNull
586        public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) {
587            Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
588            Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context));
589            String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
590            boolean isConstructor = "<init>".equals(jvmSignature.getName());
591            if (!isStatic(kind) && !isConstructor) {
592                descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
593            }
594    
595            return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
596        }
597    
598        /**
599         * @return true iff a given function descriptor should be compiled to a method with boxed return type regardless of whether return type
600         * of that descriptor is nullable or not. This happens when a function returning a value of a primitive type overrides another function
601         * 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
602         * this class from Java since javac issues errors when loading the class (incompatible return types)
603         */
604        private static boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
605            //noinspection ConstantConditions
606            if (!KotlinBuiltIns.getInstance().isPrimitiveType(descriptor.getReturnType())) return false;
607    
608            for (FunctionDescriptor overridden : descriptor.getOverriddenDescriptors()) {
609                //noinspection ConstantConditions
610                if (!KotlinBuiltIns.getInstance().isPrimitiveType(overridden.getOriginal().getReturnType())) return true;
611            }
612    
613            return false;
614        }
615    
616        private static void writeVoidReturn(@NotNull BothSignatureWriter sw) {
617            sw.writeReturnType();
618            sw.writeAsmType(Type.VOID_TYPE);
619            sw.writeReturnTypeEnd();
620        }
621    
622        @Nullable
623        public String mapFieldSignature(@NotNull JetType backingFieldType) {
624            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
625            mapType(backingFieldType, sw, JetTypeMapperMode.VALUE);
626            return sw.makeJavaGenericSignature();
627        }
628    
629        private void writeThisIfNeeded(
630                @NotNull CallableMemberDescriptor descriptor,
631                @NotNull OwnerKind kind,
632                @NotNull BothSignatureWriter sw
633        ) {
634            if (kind == OwnerKind.TRAIT_IMPL) {
635                ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
636                Type type = getTraitImplThisParameterType(containingDeclaration, this);
637    
638                sw.writeParameterType(JvmMethodParameterKind.THIS);
639                sw.writeAsmType(type);
640                sw.writeParameterTypeEnd();
641            }
642            else if (isAccessor(descriptor) && descriptor.getExpectedThisObject() != null) {
643                sw.writeParameterType(JvmMethodParameterKind.THIS);
644                mapType(((ClassifierDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), sw, JetTypeMapperMode.VALUE);
645                sw.writeParameterTypeEnd();
646            }
647        }
648    
649    
650        public void writeFormalTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull BothSignatureWriter sw) {
651            for (TypeParameterDescriptor typeParameter : typeParameters) {
652                writeFormalTypeParameter(typeParameter, sw);
653            }
654        }
655    
656        private void writeFormalTypeParameter(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull BothSignatureWriter sw) {
657            sw.writeFormalTypeParameter(typeParameterDescriptor.getName().asString());
658    
659            classBound:
660            {
661                sw.writeClassBound();
662    
663                for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
664                    if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
665                        if (!isInterface(jetType)) {
666                            mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
667                            break classBound;
668                        }
669                    }
670                }
671    
672                // "extends Object" is optional according to ClassFileFormat-Java5.pdf
673                // but javac complaints to signature:
674                // <P:>Ljava/lang/Object;
675                // TODO: avoid writing java/lang/Object if interface list is not empty
676            }
677            sw.writeClassBoundEnd();
678    
679            for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
680                ClassifierDescriptor classifier = jetType.getConstructor().getDeclarationDescriptor();
681                if (classifier instanceof ClassDescriptor) {
682                    if (isInterface(jetType)) {
683                        sw.writeInterfaceBound();
684                        mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
685                        sw.writeInterfaceBoundEnd();
686                    }
687                }
688                else if (classifier instanceof TypeParameterDescriptor) {
689                    sw.writeInterfaceBound();
690                    mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
691                    sw.writeInterfaceBoundEnd();
692                }
693                else {
694                    throw new UnsupportedOperationException("Unknown classifier: " + classifier);
695                }
696            }
697        }
698    
699        private void writeReceiverIfNeeded(@Nullable ReceiverParameterDescriptor receiver, @NotNull BothSignatureWriter sw) {
700            if (receiver != null) {
701                sw.writeParameterType(JvmMethodParameterKind.RECEIVER);
702                mapType(receiver.getType(), sw, JetTypeMapperMode.VALUE);
703                sw.writeParameterTypeEnd();
704            }
705        }
706    
707        private void writeParameter(@NotNull BothSignatureWriter sw, @NotNull JetType type) {
708            sw.writeParameterType(JvmMethodParameterKind.VALUE);
709            mapType(type, sw, JetTypeMapperMode.VALUE);
710            sw.writeParameterTypeEnd();
711        }
712    
713        private void writeAdditionalConstructorParameters(
714                @NotNull ConstructorDescriptor descriptor,
715                @NotNull BothSignatureWriter signatureWriter
716        ) {
717            CalculatedClosure closure = bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration());
718    
719            ClassDescriptor captureThis = getExpectedThisObjectForConstructorCall(descriptor, closure);
720            if (captureThis != null) {
721                signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
722                mapType(captureThis.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
723                signatureWriter.writeParameterTypeEnd();
724            }
725    
726            JetType captureReceiverType = closure != null ? closure.getCaptureReceiverType() : null;
727            if (captureReceiverType != null) {
728                signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
729                mapType(captureReceiverType, signatureWriter, JetTypeMapperMode.VALUE);
730                signatureWriter.writeParameterTypeEnd();
731            }
732    
733            ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
734            if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
735                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_NAME);
736                mapType(KotlinBuiltIns.getInstance().getStringType(), signatureWriter, JetTypeMapperMode.VALUE);
737                signatureWriter.writeParameterTypeEnd();
738                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_ORDINAL);
739                mapType(KotlinBuiltIns.getInstance().getIntType(), signatureWriter, JetTypeMapperMode.VALUE);
740                signatureWriter.writeParameterTypeEnd();
741            }
742    
743            if (closure == null) return;
744    
745            for (DeclarationDescriptor variableDescriptor : closure.getCaptureVariables().keySet()) {
746                Type type;
747                if (variableDescriptor instanceof VariableDescriptor && !(variableDescriptor instanceof PropertyDescriptor)) {
748                    Type sharedVarType = getSharedVarType(variableDescriptor);
749                    if (sharedVarType == null) {
750                        sharedVarType = mapType(((VariableDescriptor) variableDescriptor).getType());
751                    }
752                    type = sharedVarType;
753                }
754                else if (isLocalNamedFun(variableDescriptor)) {
755                    type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) variableDescriptor);
756                }
757                else {
758                    type = null;
759                }
760    
761                if (type != null) {
762                    signatureWriter.writeParameterType(JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE);
763                    signatureWriter.writeAsmType(type);
764                    signatureWriter.writeParameterTypeEnd();
765                }
766            }
767    
768            JetDelegatorToSuperCall superCall = closure.getSuperCall();
769            if (superCall != null) {
770                DeclarationDescriptor superDescriptor = bindingContext
771                        .get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
772    
773                if (superDescriptor instanceof ConstructorDescriptor && isAnonymousObject(descriptor.getContainingDeclaration())) {
774                    for (JvmMethodParameterSignature parameter : mapSignature((ConstructorDescriptor) superDescriptor).getValueParameters()) {
775                        signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_OF_ANONYMOUS_CALL_PARAM);
776                        signatureWriter.writeAsmType(parameter.getAsmType());
777                        signatureWriter.writeParameterTypeEnd();
778                    }
779                }
780            }
781        }
782    
783        @NotNull
784        public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
785            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
786    
787            sw.writeParametersStart();
788    
789            for (ScriptDescriptor importedScript : importedScripts) {
790                sw.writeParameterType(JvmMethodParameterKind.VALUE);
791                ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
792                assert descriptor != null;
793                mapType(descriptor.getDefaultType(), sw, JetTypeMapperMode.VALUE);
794                sw.writeParameterTypeEnd();
795            }
796    
797            for (ValueParameterDescriptor valueParameter : script.getScriptCodeDescriptor().getValueParameters()) {
798                writeParameter(sw, valueParameter.getType());
799            }
800    
801            writeVoidReturn(sw);
802    
803            return sw.makeJvmMethodSignature("<init>");
804        }
805    
806        @NotNull
807        public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor) {
808            JvmMethodSignature method = mapSignature(descriptor);
809            ClassDescriptor container = descriptor.getContainingDeclaration();
810            Type owner = mapClass(container);
811            if (owner.getSort() != Type.OBJECT) {
812                throw new IllegalStateException("type must have been mapped to object: " + container.getDefaultType() + ", actual: " + owner);
813            }
814            return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL, null, null, null);
815        }
816    
817        public Type getSharedVarType(DeclarationDescriptor descriptor) {
818            if (descriptor instanceof PropertyDescriptor) {
819                return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
820            }
821            else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
822                return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
823            }
824            else if (descriptor instanceof FunctionDescriptor) {
825                return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
826            }
827            else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
828                JetType outType = ((VariableDescriptor) descriptor).getType();
829                return StackValue.sharedTypeForType(mapType(outType));
830            }
831            return null;
832        }
833    }