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