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