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