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