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