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