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
017package org.jetbrains.jet.codegen.state;
018
019import com.intellij.psi.PsiElement;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.asm4.Type;
023import org.jetbrains.jet.codegen.*;
024import org.jetbrains.jet.codegen.binding.BindingTraceAware;
025import org.jetbrains.jet.codegen.binding.CalculatedClosure;
026import org.jetbrains.jet.codegen.binding.CodegenBinding;
027import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
028import org.jetbrains.jet.codegen.signature.*;
029import org.jetbrains.jet.lang.descriptors.*;
030import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
031import org.jetbrains.jet.lang.psi.JetExpression;
032import org.jetbrains.jet.lang.psi.JetFile;
033import org.jetbrains.jet.lang.resolve.BindingContext;
034import org.jetbrains.jet.lang.resolve.BindingContextUtils;
035import org.jetbrains.jet.lang.resolve.BindingTrace;
036import org.jetbrains.jet.lang.resolve.DescriptorUtils;
037import org.jetbrains.jet.lang.resolve.java.*;
038import org.jetbrains.jet.lang.resolve.name.Name;
039import org.jetbrains.jet.lang.types.*;
040import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
041
042import java.util.ArrayList;
043import java.util.Collections;
044import java.util.List;
045import java.util.Map;
046
047import static org.jetbrains.asm4.Opcodes.*;
048import static org.jetbrains.jet.codegen.AsmUtil.boxType;
049import static org.jetbrains.jet.codegen.AsmUtil.getTraitImplThisParameterType;
050import static org.jetbrains.jet.codegen.CodegenUtil.*;
051import static org.jetbrains.jet.codegen.FunctionTypesUtil.getFunctionTraitClassName;
052import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
053
054public class JetTypeMapper extends BindingTraceAware {
055
056    private final boolean mapBuiltinsToJava;
057    private final ClassBuilderMode classBuilderMode;
058
059    public JetTypeMapper(BindingTrace bindingTrace, boolean mapBuiltinsToJava, ClassBuilderMode mode) {
060        super(bindingTrace);
061        this.mapBuiltinsToJava = mapBuiltinsToJava;
062        classBuilderMode = mode;
063    }
064
065    @NotNull
066    public JvmClassName getOwner(DeclarationDescriptor descriptor, OwnerKind kind, boolean isInsideModule) {
067        JetTypeMapperMode mapTypeMode = ownerKindToMapTypeMode(kind);
068
069        DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
070        if (containingDeclaration instanceof NamespaceDescriptor) {
071            return jvmClassNameForNamespace((NamespaceDescriptor) containingDeclaration, descriptor, isInsideModule);
072        }
073        else if (containingDeclaration instanceof ClassDescriptor) {
074            ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
075            if (classDescriptor.getKind() == ClassKind.OBJECT) {
076                mapTypeMode = JetTypeMapperMode.IMPL;
077            }
078            Type asmType = mapType(classDescriptor.getDefaultType(), mapTypeMode);
079            if (asmType.getSort() != Type.OBJECT) {
080                throw new IllegalStateException();
081            }
082            return JvmClassName.byType(asmType);
083        }
084        else if (containingDeclaration instanceof ScriptDescriptor) {
085            return classNameForScriptDescriptor(bindingContext, (ScriptDescriptor) containingDeclaration);
086        }
087        else {
088            throw new UnsupportedOperationException("don't know how to generate owner for parent " + containingDeclaration);
089        }
090    }
091
092    private static JetTypeMapperMode ownerKindToMapTypeMode(OwnerKind kind) {
093        if (kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind) {
094            return JetTypeMapperMode.IMPL;
095        }
096        else if (kind == OwnerKind.TRAIT_IMPL) {
097            return JetTypeMapperMode.TRAIT_IMPL;
098        }
099        else {
100            throw new IllegalStateException("must not call this method with kind = " + kind);
101        }
102    }
103
104    @NotNull
105    private JavaNamespaceKind getNsKind(@NotNull NamespaceDescriptor ns) {
106        JavaNamespaceKind javaNamespaceKind = bindingContext.get(JavaBindingContext.JAVA_NAMESPACE_KIND, ns);
107        Boolean src = bindingContext.get(BindingContext.NAMESPACE_IS_SRC, ns);
108
109        if (javaNamespaceKind == null && src == null) {
110            throw new IllegalStateException("unknown namespace origin: " + ns);
111        }
112
113        if (javaNamespaceKind != null) {
114            if (javaNamespaceKind == JavaNamespaceKind.CLASS_STATICS && src != null) {
115                throw new IllegalStateException(
116                        "conflicting namespace " + ns + ": it is both java statics and from src");
117            }
118            return javaNamespaceKind;
119        }
120        else {
121            return JavaNamespaceKind.PROPER;
122        }
123    }
124
125    @NotNull
126    private JvmClassName jvmClassNameForNamespace(
127            @NotNull NamespaceDescriptor namespace,
128            @NotNull DeclarationDescriptor descriptor,
129            boolean insideModule
130    ) {
131
132        StringBuilder r = new StringBuilder();
133
134        List<DeclarationDescriptor> path = DescriptorUtils.getPathWithoutRootNsAndModule(namespace);
135
136        for (DeclarationDescriptor pathElement : path) {
137            NamespaceDescriptor ns = (NamespaceDescriptor) pathElement;
138            if (r.length() > 0) {
139                JavaNamespaceKind nsKind = getNsKind((NamespaceDescriptor) ns.getContainingDeclaration());
140                if (nsKind == JavaNamespaceKind.PROPER) {
141                    r.append("/");
142                }
143                else if (nsKind == JavaNamespaceKind.CLASS_STATICS) {
144                    r.append("$");
145                }
146            }
147            r.append(ns.getName());
148        }
149
150        if (getNsKind(namespace) == JavaNamespaceKind.PROPER) {
151            if (r.length() > 0) {
152                r.append("/");
153            }
154
155            JetFile file = BindingContextUtils.getContainingFile(bindingContext, descriptor);
156            if (insideModule && file != null) {
157                String internalName = NamespaceCodegen.getNamespacePartInternalName(file);
158                r.append(internalName.substring(r.length()));
159            }
160            else {
161                r.append(PackageClassUtils.getPackageClassName(namespace.getFqName()));
162            }
163        }
164
165        if (r.length() == 0) {
166            throw new IllegalStateException("internal error: failed to generate classname for " + namespace);
167        }
168
169        return JvmClassName.byInternalName(r.toString());
170    }
171
172    @NotNull
173    public Type mapReturnType(@NotNull JetType jetType) {
174        return mapReturnType(jetType, null);
175    }
176
177    @NotNull
178    private Type mapReturnType(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor) {
179        if (jetType.equals(KotlinBuiltIns.getInstance().getUnitType())) {
180            if (signatureVisitor != null) {
181                signatureVisitor.writeAsmType(Type.VOID_TYPE, false);
182            }
183            return Type.VOID_TYPE;
184        }
185        else if (jetType.equals(KotlinBuiltIns.getInstance().getNothingType())) {
186            if (signatureVisitor != null) {
187                signatureVisitor.writeNothing(false);
188            }
189            return Type.VOID_TYPE;
190        }
191        if (jetType.equals(KotlinBuiltIns.getInstance().getNullableNothingType())) {
192            if (signatureVisitor != null) {
193                signatureVisitor.writeNothing(true);
194            }
195            return AsmTypeConstants.OBJECT_TYPE;
196        }
197        return mapType(jetType, signatureVisitor, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE);
198    }
199
200    @NotNull
201    public Type mapType(@NotNull JetType jetType, @NotNull JetTypeMapperMode kind) {
202        return mapType(jetType, null, kind);
203    }
204
205    @NotNull
206    public Type mapType(@NotNull JetType jetType) {
207        return mapType(jetType, null, JetTypeMapperMode.VALUE);
208    }
209
210    @NotNull
211    public Type mapType(@NotNull VariableDescriptor variableDescriptor) {
212        return mapType(variableDescriptor.getType(), null, JetTypeMapperMode.VALUE);
213    }
214
215    @NotNull
216    public Type mapType(@NotNull ClassifierDescriptor classifierDescriptor) {
217        return mapType(classifierDescriptor.getDefaultType());
218    }
219
220    @NotNull
221    public Type mapType(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode kind) {
222        return mapType(jetType, signatureVisitor, kind, Variance.INVARIANT);
223    }
224
225    @NotNull
226    public Type mapType(
227            @NotNull JetType jetType,
228            @Nullable BothSignatureWriter signatureVisitor,
229            @NotNull JetTypeMapperMode kind,
230            @NotNull Variance howThisTypeIsUsed
231    ) {
232        Type known = null;
233        DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
234
235        if (mapBuiltinsToJava) {
236            if (descriptor instanceof ClassDescriptor) {
237                known = KotlinToJavaTypesMap.getInstance().getJavaAnalog(jetType);
238            }
239        }
240
241        if (known != null) {
242            if (kind == JetTypeMapperMode.VALUE) {
243                return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
244            }
245            else if (kind == JetTypeMapperMode.TYPE_PARAMETER) {
246                return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed);
247            }
248            else if (kind == JetTypeMapperMode.TRAIT_IMPL) {
249                throw new IllegalStateException("TRAIT_IMPL is not possible for " + jetType);
250            }
251            else if (kind == JetTypeMapperMode.IMPL) {
252                //noinspection ConstantConditions
253                if (mapBuiltinsToJava) {
254                    // TODO: enable and fix tests
255                    //throw new IllegalStateException("must not map known type to IMPL when not compiling builtins: " + jetType);
256                }
257                return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
258            }
259            else {
260                throw new IllegalStateException("unknown kind: " + kind);
261            }
262        }
263
264        TypeConstructor constructor = jetType.getConstructor();
265        if (constructor instanceof IntersectionTypeConstructor) {
266            jetType = CommonSupertypes.commonSupertype(new ArrayList<JetType>(constructor.getSupertypes()));
267        }
268
269        if (descriptor == null) {
270            throw new UnsupportedOperationException("no descriptor for type constructor of " + jetType);
271        }
272
273        if (ErrorUtils.isError(descriptor)) {
274            if (classBuilderMode != ClassBuilderMode.SIGNATURES) {
275                throw new IllegalStateException(generateErrorMessageForErrorType(descriptor));
276            }
277            Type asmType = Type.getObjectType("error/NonExistentClass");
278            if (signatureVisitor != null) {
279                signatureVisitor.writeAsmType(asmType, true);
280            }
281            checkValidType(asmType);
282            return asmType;
283        }
284
285        if (mapBuiltinsToJava && descriptor instanceof ClassDescriptor && KotlinBuiltIns.getInstance().isArray(jetType)) {
286            if (jetType.getArguments().size() != 1) {
287                throw new UnsupportedOperationException("arrays must have one type argument");
288            }
289            TypeProjection memberProjection = jetType.getArguments().get(0);
290            JetType memberType = memberProjection.getType();
291
292            if (signatureVisitor != null) {
293                signatureVisitor.writeArrayType(jetType.isNullable(), memberProjection.getProjectionKind());
294                mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
295                signatureVisitor.writeArrayEnd();
296            }
297
298            Type r;
299            if (!isGenericsArray(jetType)) {
300                r = Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor());
301            }
302            else {
303                r = AsmTypeConstants.JAVA_ARRAY_GENERIC_TYPE;
304            }
305            checkValidType(r);
306            return r;
307        }
308
309        if (descriptor instanceof ClassDescriptor) {
310            JvmClassName name = getJvmInternalName(bindingTrace, descriptor);
311            Type asmType;
312            if (kind == JetTypeMapperMode.TRAIT_IMPL) {
313                asmType = Type.getObjectType(name.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
314            }
315            else {
316                asmType = name.getAsmType();
317            }
318            boolean forceReal = KotlinToJavaTypesMap.getInstance().isForceReal(name);
319
320            writeGenericType(signatureVisitor, asmType, jetType, forceReal, howThisTypeIsUsed);
321
322            checkValidType(asmType);
323            return asmType;
324        }
325
326        if (descriptor instanceof TypeParameterDescriptor) {
327            TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
328            Type type = mapType(typeParameterDescriptor.getUpperBoundsAsType(), kind);
329            if (signatureVisitor != null) {
330                signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable(), type);
331            }
332            checkValidType(type);
333            return type;
334        }
335
336        throw new UnsupportedOperationException("Unknown type " + jetType);
337    }
338
339    private String generateErrorMessageForErrorType(@NotNull DeclarationDescriptor descriptor) {
340        PsiElement declarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
341        PsiElement parentDeclarationElement = null;
342        if (declarationElement != null) {
343            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
344            if (containingDeclaration != null) {
345                parentDeclarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, containingDeclaration);
346            }
347        }
348
349        return String.format("Error types are not allowed when classBuilderMode = %s. For declaration %s:%s in %s:%s",
350                      classBuilderMode,
351                      declarationElement,
352                      declarationElement != null ? declarationElement.getText() : "null",
353                      parentDeclarationElement,
354                      parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
355    }
356
357    private void writeGenericType(
358            BothSignatureWriter signatureVisitor,
359            Type asmType,
360            JetType jetType,
361            boolean forceReal,
362            Variance howThisTypeIsUsed
363    ) {
364        if (signatureVisitor != null) {
365            String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType);
366            signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable(), forceReal, kotlinTypeName);
367
368            List<TypeProjection> arguments = jetType.getArguments();
369            for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
370                TypeProjection argument = arguments.get(parameter.getIndex());
371
372                Variance projectionKindForKotlin = argument.getProjectionKind();
373                Variance projectionKindForJava = getEffectiveVariance(
374                        parameter.getVariance(),
375                        projectionKindForKotlin,
376                        howThisTypeIsUsed
377                );
378                signatureVisitor.writeTypeArgument(projectionKindForKotlin, projectionKindForJava);
379
380                mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
381                signatureVisitor.writeTypeArgumentEnd();
382            }
383            signatureVisitor.writeClassEnd();
384        }
385    }
386
387    private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) {
388        // Return type must not contain wildcards
389        if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind;
390
391        if (parameterVariance == Variance.INVARIANT) {
392            return projectionKind;
393        }
394        if (projectionKind == Variance.INVARIANT) {
395            return parameterVariance;
396        }
397        if (parameterVariance == projectionKind) {
398            return parameterVariance;
399        }
400
401        // In<out X> = In<*>
402        // Out<in X> = Out<*>
403        return Variance.OUT_VARIANCE;
404    }
405
406    private Type mapKnownAsmType(
407            JetType jetType,
408            Type asmType,
409            @Nullable BothSignatureWriter signatureVisitor,
410            @NotNull Variance howThisTypeIsUsed
411    ) {
412        if (signatureVisitor != null) {
413            if (jetType.getArguments().isEmpty()) {
414                String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType);
415                signatureVisitor.writeAsmType(asmType, jetType.isNullable(), kotlinTypeName);
416            }
417            else {
418                writeGenericType(signatureVisitor, asmType, jetType, false, howThisTypeIsUsed);
419            }
420        }
421        checkValidType(asmType);
422        return asmType;
423    }
424
425    @Nullable
426    private static String getKotlinTypeNameForSignature(@NotNull JetType jetType, @NotNull Type asmType) {
427        ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
428        if (descriptor == null) return null;
429        if (asmType.getSort() != Type.OBJECT) return null;
430
431        JvmClassName jvmClassName = JvmClassName.byType(asmType);
432        if (JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmClassName.getFqName()).size() > 1) {
433            return JvmClassName.byClassDescriptor(descriptor).getSignatureName();
434        }
435        return null;
436    }
437
438    private void checkValidType(@NotNull Type type) {
439        if (!mapBuiltinsToJava) {
440            String descriptor = type.getDescriptor();
441            if (!descriptor.equals("Ljava/lang/Object;")) {
442                if (descriptor.startsWith("Ljava/")) {
443                    throw new IllegalStateException("builtins must not reference java.* classes: " + descriptor);
444                }
445            }
446        }
447    }
448
449    @NotNull
450    public CallableMethod mapToCallableMethod(
451            @NotNull FunctionDescriptor functionDescriptor,
452            boolean superCall,
453            boolean isInsideClass,
454            boolean isInsideModule,
455            OwnerKind kind
456    ) {
457        DeclarationDescriptor functionParent = functionDescriptor.getOriginal().getContainingDeclaration();
458
459        functionDescriptor = unwrapFakeOverride(functionDescriptor);
460
461        JvmMethodSignature descriptor = mapSignature(functionDescriptor.getOriginal(), true, kind);
462        JvmClassName owner;
463        JvmClassName ownerForDefaultImpl;
464        JvmClassName ownerForDefaultParam;
465        int invokeOpcode;
466        JvmClassName thisClass;
467        if (functionParent instanceof NamespaceDescriptor) {
468            assert !superCall;
469            owner = jvmClassNameForNamespace((NamespaceDescriptor) functionParent, functionDescriptor, isInsideModule);
470            ownerForDefaultImpl = ownerForDefaultParam = owner;
471            invokeOpcode = INVOKESTATIC;
472            thisClass = null;
473        }
474        else if (functionDescriptor instanceof ConstructorDescriptor) {
475            assert !superCall;
476            ClassDescriptor containingClass = (ClassDescriptor) functionParent;
477            owner = JvmClassName.byType(mapType(containingClass.getDefaultType(), JetTypeMapperMode.IMPL));
478            ownerForDefaultImpl = ownerForDefaultParam = owner;
479            invokeOpcode = INVOKESPECIAL;
480            thisClass = null;
481        }
482        else if (functionParent instanceof ScriptDescriptor) {
483            thisClass = owner =
484            ownerForDefaultParam = ownerForDefaultImpl = classNameForScriptDescriptor(bindingContext, (ScriptDescriptor) functionParent);
485            invokeOpcode = INVOKEVIRTUAL;
486        }
487        else if (functionParent instanceof ClassDescriptor) {
488
489            FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
490
491            ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
492            ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
493
494            boolean originalIsInterface = isInterface(declarationOwner);
495            boolean currentIsInterface = isInterface(currentOwner);
496
497            boolean isAccessor = isAccessor(functionDescriptor);
498
499            ClassDescriptor receiver;
500            if (currentIsInterface && !originalIsInterface) {
501                receiver = declarationOwner;
502            }
503            else {
504                receiver = currentOwner;
505            }
506
507            // TODO: TYPE_PARAMETER is hack here
508
509            boolean isInterface = originalIsInterface && currentIsInterface;
510            Type type = mapType(receiver.getDefaultType(), JetTypeMapperMode.TYPE_PARAMETER);
511            owner = JvmClassName.byType(type);
512
513            ClassDescriptor declarationOwnerForDefault = (ClassDescriptor) findBaseDeclaration(functionDescriptor).getContainingDeclaration();
514            ownerForDefaultParam = JvmClassName.byType(mapType(declarationOwnerForDefault.getDefaultType(), JetTypeMapperMode.TYPE_PARAMETER));
515            ownerForDefaultImpl = JvmClassName.byInternalName(
516                    ownerForDefaultParam.getInternalName() + (isInterface(declarationOwnerForDefault) ? JvmAbi.TRAIT_IMPL_SUFFIX : ""));
517            if (isInterface) {
518                invokeOpcode = superCall ? INVOKESTATIC : INVOKEINTERFACE;
519            }
520            else {
521                if (isAccessor) {
522                    invokeOpcode = INVOKESTATIC;
523                }
524                else {
525                    boolean isPrivateFunInvocation = isInsideClass && functionDescriptor.getVisibility() == Visibilities.PRIVATE;
526                    invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
527                }
528            }
529
530            if (isInterface && superCall) {
531                descriptor = mapSignature(functionDescriptor, false, OwnerKind.TRAIT_IMPL);
532                owner = JvmClassName.byInternalName(owner.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
533            }
534            thisClass = JvmClassName.byType(mapType(receiver.getDefaultType()));
535        }
536        else {
537            throw new UnsupportedOperationException("unknown function parent");
538        }
539
540
541        Type receiverParameterType;
542        ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getReceiverParameter();
543        if (receiverParameter != null) {
544            receiverParameterType = mapType(receiverParameter.getType());
545        }
546        else {
547            receiverParameterType = null;
548        }
549        return new CallableMethod(
550                owner, ownerForDefaultImpl, ownerForDefaultParam, descriptor, invokeOpcode,
551                thisClass, receiverParameterType, null);
552    }
553
554    public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
555        return descriptor instanceof AccessorForFunctionDescriptor ||
556               descriptor instanceof AccessorForPropertyDescriptor ||
557               descriptor instanceof AccessorForPropertyDescriptor.Getter ||
558               descriptor instanceof AccessorForPropertyDescriptor.Setter;
559    }
560
561    @NotNull
562    private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) {
563        if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
564            return function;
565        }
566        return findBaseDeclaration(function);
567    }
568
569    @NotNull
570    private static FunctionDescriptor findBaseDeclaration(@NotNull FunctionDescriptor function) {
571        if (function.getOverriddenDescriptors().isEmpty()) {
572            return function;
573        }
574        else {
575            // TODO: prefer class to interface
576            return findBaseDeclaration(function.getOverriddenDescriptors().iterator().next());
577        }
578    }
579
580    @NotNull
581    public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, boolean needGenericSignature, @NotNull OwnerKind kind) {
582        String name = f.getName().asString();
583        if (f instanceof PropertyAccessorDescriptor) {
584            boolean isGetter = f instanceof PropertyGetterDescriptor;
585            name = getPropertyAccessorName(((PropertyAccessorDescriptor) f).getCorrespondingProperty(), isGetter);
586        }
587        return mapSignature(name, f, needGenericSignature, kind);
588    }
589
590    @NotNull
591    public JvmMethodSignature mapSignature(@NotNull Name functionName, @NotNull FunctionDescriptor f) {
592        return mapSignature(functionName.asString(), f, false, OwnerKind.IMPLEMENTATION);
593    }
594
595    @NotNull
596    public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f) {
597        return mapSignature(f.getName(), f);
598    }
599
600    @NotNull
601    private JvmMethodSignature mapSignature(
602            @NotNull String methodName,
603            @NotNull FunctionDescriptor f,
604            boolean needGenericSignature,
605            @NotNull OwnerKind kind
606    ) {
607        if (kind == OwnerKind.TRAIT_IMPL) {
608            needGenericSignature = false;
609        }
610
611        BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, needGenericSignature);
612
613        writeFormalTypeParameters(f.getTypeParameters(), signatureVisitor);
614
615        signatureVisitor.writeParametersStart();
616        writeThisIfNeeded(f, kind, signatureVisitor);
617        writeReceiverIfNeeded(f.getReceiverParameter(), signatureVisitor);
618
619        for (ValueParameterDescriptor parameter : f.getValueParameters()) {
620            writeParameter(signatureVisitor, parameter.getType());
621        }
622
623        signatureVisitor.writeParametersEnd();
624
625        if (f instanceof ConstructorDescriptor) {
626            signatureVisitor.writeVoidReturn();
627        }
628        else {
629            signatureVisitor.writeReturnType();
630            JetType returnType = f.getReturnType();
631            assert returnType != null : "Function " + f + " has no return type";
632            mapReturnType(returnType, signatureVisitor);
633            signatureVisitor.writeReturnTypeEnd();
634        }
635
636        return signatureVisitor.makeJvmMethodSignature(methodName);
637    }
638
639    @Nullable
640    public String mapFieldSignature(@NotNull JetType backingFieldType) {
641        BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE, true);
642        signatureVisitor.writeFieldTypeStart();
643        mapType(backingFieldType, signatureVisitor, JetTypeMapperMode.VALUE);
644        signatureVisitor.writeFieldTypeEnd();
645        return signatureVisitor.makeJavaGenericSignature();
646    }
647
648    private void writeThisIfNeeded(
649            @NotNull CallableMemberDescriptor descriptor,
650            @NotNull OwnerKind kind,
651            @NotNull BothSignatureWriter signatureVisitor
652    ) {
653        if (kind == OwnerKind.TRAIT_IMPL) {
654            ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
655            Type type = getTraitImplThisParameterType(containingDeclaration, this);
656
657            signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS);
658            signatureVisitor.writeAsmType(type, false);
659            signatureVisitor.writeParameterTypeEnd();
660        }
661        else {
662            writeThisForAccessorIfNeeded(descriptor, signatureVisitor);
663        }
664    }
665
666    private void writeThisForAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BothSignatureWriter signatureVisitor) {
667        if (isAccessor(descriptor) && descriptor.getExpectedThisObject() != null) {
668            signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS);
669            mapType(((ClassifierDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), signatureVisitor, JetTypeMapperMode.VALUE);
670            signatureVisitor.writeParameterTypeEnd();
671        }
672    }
673
674
675    public void writeFormalTypeParameters(List<TypeParameterDescriptor> typeParameters, BothSignatureWriter signatureVisitor) {
676        if (signatureVisitor == null) {
677            return;
678        }
679
680        signatureVisitor.writeFormalTypeParametersStart();
681        for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
682            writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor);
683        }
684        signatureVisitor.writeFormalTypeParametersEnd();
685    }
686
687    private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) {
688        signatureVisitor.writeFormalTypeParameter(typeParameterDescriptor.getName().asString(), typeParameterDescriptor.getVariance(),
689                                                  typeParameterDescriptor.isReified());
690
691        classBound:
692        {
693            signatureVisitor.writeClassBound();
694
695            for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
696                if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
697                    if (!isInterface(jetType)) {
698                        mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
699                        break classBound;
700                    }
701                }
702            }
703
704            // "extends Object" is optional according to ClassFileFormat-Java5.pdf
705            // but javac complaints to signature:
706            // <P:>Ljava/lang/Object;
707            // TODO: avoid writing java/lang/Object if interface list is not empty
708        }
709        signatureVisitor.writeClassBoundEnd();
710
711        for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
712            if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
713                if (isInterface(jetType)) {
714                    signatureVisitor.writeInterfaceBound();
715                    mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
716                    signatureVisitor.writeInterfaceBoundEnd();
717                }
718            }
719            if (jetType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
720                signatureVisitor.writeInterfaceBound();
721                mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
722                signatureVisitor.writeInterfaceBoundEnd();
723            }
724        }
725
726        signatureVisitor.writeFormalTypeParameterEnd();
727    }
728
729
730    private void writeReceiverIfNeeded(@Nullable ReceiverParameterDescriptor receiver, BothSignatureWriter signatureWriter) {
731        if (receiver != null) {
732            signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
733            mapType(receiver.getType(), signatureWriter, JetTypeMapperMode.VALUE);
734            signatureWriter.writeParameterTypeEnd();
735        }
736    }
737
738    @NotNull
739    public static String getPropertyAccessorName(@NotNull PropertyDescriptor descriptor, boolean isGetter) {
740        DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
741        boolean isAnnotation = parentDescriptor instanceof ClassDescriptor &&
742                               ((ClassDescriptor) parentDescriptor).getKind() == ClassKind.ANNOTATION_CLASS;
743        return isAnnotation ? descriptor.getName().asString() :
744               isGetter ? PropertyCodegen.getterName(descriptor.getName()) : PropertyCodegen.setterName(descriptor.getName());
745    }
746
747    @NotNull
748    public JvmPropertyAccessorSignature mapGetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
749        // TODO: do not genClassOrObject generics if not needed
750        BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
751
752        writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter);
753
754        signatureWriter.writeParametersStart();
755        writeThisIfNeeded(descriptor, kind, signatureWriter);
756        writeReceiverIfNeeded(descriptor.getReceiverParameter(), signatureWriter);
757        signatureWriter.writeParametersEnd();
758
759        signatureWriter.writeReturnType();
760        mapType(descriptor.getType(), signatureWriter, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE);
761        signatureWriter.writeReturnTypeEnd();
762
763        String name = getPropertyAccessorName(descriptor, true);
764        return signatureWriter.makeJvmPropertyAccessorSignature(name, true);
765    }
766
767
768    @NotNull
769    public JvmPropertyAccessorSignature mapSetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
770        assert descriptor.isVar();
771
772        // TODO: generics signature is not always needed
773        BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
774
775        writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter);
776
777        signatureWriter.writeParametersStart();
778        writeThisIfNeeded(descriptor, kind, signatureWriter);
779        writeReceiverIfNeeded(descriptor.getReceiverParameter(), signatureWriter);
780        writeParameter(signatureWriter, descriptor.getType());
781        signatureWriter.writeParametersEnd();
782
783        signatureWriter.writeVoidReturn();
784
785        String name = getPropertyAccessorName(descriptor, false);
786        return signatureWriter.makeJvmPropertyAccessorSignature(name, false);
787    }
788
789    private void writeParameter(@NotNull BothSignatureWriter signatureWriter, @NotNull JetType outType) {
790        signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
791        mapType(outType, signatureWriter, JetTypeMapperMode.VALUE);
792        signatureWriter.writeParameterTypeEnd();
793    }
794
795    @NotNull
796    public JvmMethodSignature mapConstructorSignature(@NotNull ConstructorDescriptor descriptor) {
797        return mapConstructorSignature(descriptor, bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration()));
798    }
799
800    @NotNull
801    public JvmMethodSignature mapConstructorSignature(@NotNull ConstructorDescriptor descriptor, @Nullable CalculatedClosure closure) {
802
803        BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
804
805        // constructor type parmeters are fake
806        writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
807
808        signatureWriter.writeParametersStart();
809
810        ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
811        ClassDescriptor captureThis = closure != null ? closure.getCaptureThis() : null;
812        if (captureThis != null) {
813            signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
814            mapType(captureThis.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
815            signatureWriter.writeParameterTypeEnd();
816        }
817
818        ClassifierDescriptor captureReceiver = closure != null ? closure.getCaptureReceiver() : null;
819        if (captureReceiver != null) {
820            signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
821            mapType(captureReceiver.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
822            signatureWriter.writeParameterTypeEnd();
823        }
824
825        if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
826            signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_NAME);
827            mapType(KotlinBuiltIns.getInstance().getStringType(), signatureWriter, JetTypeMapperMode.VALUE);
828            signatureWriter.writeParameterTypeEnd();
829            signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_ORDINAL);
830            mapType(KotlinBuiltIns.getInstance().getIntType(), signatureWriter, JetTypeMapperMode.VALUE);
831            signatureWriter.writeParameterTypeEnd();
832        }
833
834        if (closure != null) {
835            for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
836                DeclarationDescriptor variableDescriptor = entry.getKey();
837                Type type = null;
838                if (variableDescriptor instanceof VariableDescriptor && !(variableDescriptor instanceof PropertyDescriptor)) {
839                    Type sharedVarType = getSharedVarType(variableDescriptor);
840                    if (sharedVarType == null) {
841                        sharedVarType = mapType(((VariableDescriptor) variableDescriptor).getType());
842                    }
843                    type = sharedVarType;
844                }
845                else if (isLocalNamedFun(variableDescriptor)) {
846                    type = classNameForAnonymousClass(bindingContext, (FunctionDescriptor) variableDescriptor).getAsmType();
847                }
848
849                if (type != null) {
850                    signatureWriter.writeParameterType(JvmMethodParameterKind.SHARED_VAR);
851                    signatureWriter.writeAsmType(type, false);
852                    signatureWriter.writeParameterTypeEnd();
853                }
854            }
855
856            JetDelegatorToSuperCall superCall = closure.getSuperCall();
857            if (superCall != null) {
858                DeclarationDescriptor superDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET,
859                                                                                                    superCall
860                                                                                                            .getCalleeExpression()
861                                                                                                            .getConstructorReferenceExpression());
862
863                if(superDescriptor instanceof ConstructorDescriptor) {
864                    ConstructorDescriptor superConstructor = (ConstructorDescriptor) superDescriptor;
865
866                    if (isObjectLiteral(bindingContext, descriptor.getContainingDeclaration())) {
867                        List<JvmMethodParameterSignature> types = mapConstructorSignature(superConstructor).getKotlinParameterTypes();
868                        if (types != null) {
869                            for (JvmMethodParameterSignature type : types) {
870                                signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_CALL_PARAM);
871                                signatureWriter.writeAsmType(type.getAsmType(), false);
872                                signatureWriter.writeParameterTypeEnd();
873                            }
874                        }
875                    }
876                }
877            }
878        }
879
880        for (ValueParameterDescriptor parameter : descriptor.getOriginal().getValueParameters()) {
881            writeParameter(signatureWriter, parameter.getType());
882        }
883
884        signatureWriter.writeParametersEnd();
885
886        signatureWriter.writeVoidReturn();
887
888        return signatureWriter.makeJvmMethodSignature("<init>");
889    }
890
891    @NotNull
892    public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
893        BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
894
895        writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
896
897        signatureWriter.writeParametersStart();
898
899        for (ScriptDescriptor importedScript : importedScripts) {
900            signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
901            ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
902            assert descriptor != null;
903            mapType(descriptor.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
904            signatureWriter.writeParameterTypeEnd();
905        }
906
907        for (ValueParameterDescriptor valueParameter : script.getValueParameters()) {
908            writeParameter(signatureWriter, valueParameter.getType());
909        }
910
911        signatureWriter.writeParametersEnd();
912
913        signatureWriter.writeVoidReturn();
914
915        return signatureWriter.makeJvmMethodSignature("<init>");
916    }
917
918    @NotNull
919    public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor) {
920        return mapToCallableMethod(descriptor, bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration()));
921    }
922
923    @NotNull
924    public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor, @Nullable CalculatedClosure closure) {
925        JvmMethodSignature method = mapConstructorSignature(descriptor, closure);
926        JetType defaultType = descriptor.getContainingDeclaration().getDefaultType();
927        Type mapped = mapType(defaultType, JetTypeMapperMode.IMPL);
928        if (mapped.getSort() != Type.OBJECT) {
929            throw new IllegalStateException("type must have been mapped to object: " + defaultType + ", actual: " + mapped);
930        }
931        JvmClassName owner = JvmClassName.byType(mapped);
932        return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL, null, null, null);
933    }
934
935
936    private static boolean isGenericsArray(JetType type) {
937        return KotlinBuiltIns.getInstance().isArray(type) &&
938               type.getArguments().get(0).getType().getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
939    }
940
941    public Type getSharedVarType(DeclarationDescriptor descriptor) {
942        if (descriptor instanceof PropertyDescriptor) {
943            return StackValue
944                    .sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
945        }
946        else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
947            return classNameForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor).getAsmType();
948        }
949        else if (descriptor instanceof FunctionDescriptor) {
950            return StackValue
951                    .sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
952        }
953        else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
954            JetType outType = ((VariableDescriptor) descriptor).getType();
955            return StackValue.sharedTypeForType(mapType(outType));
956        }
957        return null;
958    }
959
960    @NotNull
961    public CallableMethod mapToFunctionInvokeCallableMethod(@NotNull FunctionDescriptor fd) {
962        JvmMethodSignature descriptor = erasedInvokeSignature(fd);
963        JvmClassName owner = getFunctionTraitClassName(fd);
964        Type receiverParameterType;
965        ReceiverParameterDescriptor receiverParameter = fd.getOriginal().getReceiverParameter();
966        if (receiverParameter != null) {
967            receiverParameterType = mapType(receiverParameter.getType());
968        }
969        else {
970            receiverParameterType = null;
971        }
972        return new CallableMethod(owner, null, null, descriptor, INVOKEINTERFACE, owner, receiverParameterType, owner.getAsmType());
973    }
974
975    @NotNull
976    public Type expressionType(JetExpression expr) {
977        JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr);
978        return asmTypeOrVoid(type);
979    }
980
981    @NotNull
982    private Type asmTypeOrVoid(@Nullable JetType type) {
983        return type == null ? Type.VOID_TYPE : mapType(type);
984    }
985}