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, false);
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            return mapType(jetType, signatureVisitor, kind, howThisTypeIsUsed, false);
232        }
233    
234        @NotNull
235        public Type mapType(
236                @NotNull JetType jetType,
237                @Nullable BothSignatureWriter signatureVisitor,
238                @NotNull JetTypeMapperMode kind,
239                @NotNull Variance howThisTypeIsUsed,
240                boolean arrayParameter
241        ) {
242            Type known = null;
243            DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
244    
245            if (mapBuiltinsToJava) {
246                if (descriptor instanceof ClassDescriptor) {
247                    known = KotlinToJavaTypesMap.getInstance().getJavaAnalog(jetType);
248                }
249            }
250    
251            if (known != null) {
252                if (kind == JetTypeMapperMode.VALUE) {
253                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
254                }
255                else if (kind == JetTypeMapperMode.TYPE_PARAMETER) {
256                    return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed, arrayParameter);
257                }
258                else if (kind == JetTypeMapperMode.TRAIT_IMPL) {
259                    throw new IllegalStateException("TRAIT_IMPL is not possible for " + jetType);
260                }
261                else if (kind == JetTypeMapperMode.IMPL) {
262                    //noinspection ConstantConditions
263                    if (mapBuiltinsToJava) {
264                        // TODO: enable and fix tests
265                        //throw new IllegalStateException("must not map known type to IMPL when not compiling builtins: " + jetType);
266                    }
267                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
268                }
269                else {
270                    throw new IllegalStateException("unknown kind: " + kind);
271                }
272            }
273    
274            TypeConstructor constructor = jetType.getConstructor();
275            if (constructor instanceof IntersectionTypeConstructor) {
276                jetType = CommonSupertypes.commonSupertype(new ArrayList<JetType>(constructor.getSupertypes()));
277            }
278    
279            if (descriptor == null) {
280                throw new UnsupportedOperationException("no descriptor for type constructor of " + jetType);
281            }
282    
283            if (ErrorUtils.isError(descriptor)) {
284                if (classBuilderMode != ClassBuilderMode.SIGNATURES) {
285                    throw new IllegalStateException(generateErrorMessageForErrorType(descriptor));
286                }
287                Type asmType = Type.getObjectType("error/NonExistentClass");
288                if (signatureVisitor != null) {
289                    signatureVisitor.writeAsmType(asmType, true);
290                }
291                checkValidType(asmType);
292                return asmType;
293            }
294    
295            if (mapBuiltinsToJava && descriptor instanceof ClassDescriptor && KotlinBuiltIns.getInstance().isArray(jetType)) {
296                if (jetType.getArguments().size() != 1) {
297                    throw new UnsupportedOperationException("arrays must have one type argument");
298                }
299                TypeProjection memberProjection = jetType.getArguments().get(0);
300                JetType memberType = memberProjection.getType();
301    
302                if (signatureVisitor != null) {
303                    signatureVisitor.writeArrayType(jetType.isNullable(), memberProjection.getProjectionKind());
304                    mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER, memberProjection.getProjectionKind(), true);
305                    signatureVisitor.writeArrayEnd();
306                }
307    
308                Type r;
309                if (!isGenericsArray(jetType)) {
310                    r = Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor());
311                }
312                else {
313                    r = AsmTypeConstants.JAVA_ARRAY_GENERIC_TYPE;
314                }
315                checkValidType(r);
316                return r;
317            }
318    
319            if (descriptor instanceof ClassDescriptor) {
320                JvmClassName name = getJvmInternalName(bindingTrace, descriptor);
321                Type asmType;
322                if (kind == JetTypeMapperMode.TRAIT_IMPL) {
323                    asmType = Type.getObjectType(name.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
324                }
325                else {
326                    asmType = name.getAsmType();
327                }
328                boolean forceReal = KotlinToJavaTypesMap.getInstance().isForceReal(name);
329    
330                writeGenericType(signatureVisitor, asmType, jetType, forceReal, howThisTypeIsUsed);
331    
332                checkValidType(asmType);
333                return asmType;
334            }
335    
336            if (descriptor instanceof TypeParameterDescriptor) {
337                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
338                Type type = mapType(typeParameterDescriptor.getUpperBoundsAsType(), kind);
339                if (signatureVisitor != null) {
340                    signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable(), type);
341                }
342                checkValidType(type);
343                return type;
344            }
345    
346            throw new UnsupportedOperationException("Unknown type " + jetType);
347        }
348    
349        private String generateErrorMessageForErrorType(@NotNull DeclarationDescriptor descriptor) {
350            PsiElement declarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
351            PsiElement parentDeclarationElement = null;
352            if (declarationElement != null) {
353                DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
354                if (containingDeclaration != null) {
355                    parentDeclarationElement = BindingContextUtils.descriptorToDeclaration(bindingContext, containingDeclaration);
356                }
357            }
358    
359            return String.format("Error types are not allowed when classBuilderMode = %s. For declaration %s:%s in %s:%s",
360                          classBuilderMode,
361                          declarationElement,
362                          declarationElement != null ? declarationElement.getText() : "null",
363                          parentDeclarationElement,
364                          parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
365        }
366    
367        private void writeGenericType(
368                BothSignatureWriter signatureVisitor,
369                Type asmType,
370                JetType jetType,
371                boolean forceReal,
372                Variance howThisTypeIsUsed
373        ) {
374            if (signatureVisitor != null) {
375                String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType);
376                signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable(), forceReal, kotlinTypeName);
377    
378                List<TypeProjection> arguments = jetType.getArguments();
379                for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
380                    TypeProjection argument = arguments.get(parameter.getIndex());
381    
382                    Variance projectionKindForKotlin = argument.getProjectionKind();
383                    Variance projectionKindForJava = getEffectiveVariance(
384                            parameter.getVariance(),
385                            projectionKindForKotlin,
386                            howThisTypeIsUsed
387                    );
388                    signatureVisitor.writeTypeArgument(projectionKindForKotlin, projectionKindForJava);
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
435                        && (howThisTypeIsUsed == Variance.IN_VARIANCE)) {
436                        asmType = AsmTypeConstants.OBJECT_TYPE;
437                    }
438                    String kotlinTypeName = getKotlinTypeNameForSignature(jetType, asmType, arrayParameter);
439                    signatureVisitor.writeAsmType(asmType, jetType.isNullable(), kotlinTypeName);
440                }
441                else {
442                    writeGenericType(signatureVisitor, asmType, jetType, false, howThisTypeIsUsed);
443                }
444            }
445            checkValidType(asmType);
446            return asmType;
447        }
448    
449        @Nullable
450        private static String getKotlinTypeNameForSignature(@NotNull JetType jetType, @NotNull Type asmType) {
451            return getKotlinTypeNameForSignature(jetType, asmType, false);
452        }
453    
454        @Nullable
455        private static String getKotlinTypeNameForSignature(@NotNull JetType jetType, @NotNull Type asmType, boolean arrayParameter) {
456            ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
457            if (descriptor == null) return null;
458            if (asmType.getSort() != Type.OBJECT) return null;
459    
460            JvmClassName jvmClassName = JvmClassName.byType(asmType);
461            if ((arrayParameter && JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmClassName.getFqName()).size() >= 1)
462                || ((!arrayParameter) && JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmClassName.getFqName()).size() > 1)) {
463                return JvmClassName.byClassDescriptor(descriptor).getSignatureName();
464            }
465            return null;
466        }
467    
468        private void checkValidType(@NotNull Type type) {
469            if (!mapBuiltinsToJava) {
470                String descriptor = type.getDescriptor();
471                if (!descriptor.equals("Ljava/lang/Object;")) {
472                    if (descriptor.startsWith("Ljava/")) {
473                        throw new IllegalStateException("builtins must not reference java.* classes: " + descriptor);
474                    }
475                }
476            }
477        }
478    
479        @NotNull
480        public CallableMethod mapToCallableMethod(
481                @NotNull FunctionDescriptor functionDescriptor,
482                boolean superCall,
483                boolean isInsideClass,
484                boolean isInsideModule,
485                OwnerKind kind
486        ) {
487            DeclarationDescriptor functionParent = functionDescriptor.getOriginal().getContainingDeclaration();
488    
489            functionDescriptor = unwrapFakeOverride(functionDescriptor);
490    
491            JvmMethodSignature descriptor = mapSignature(functionDescriptor.getOriginal(), true, kind);
492            JvmClassName owner;
493            JvmClassName ownerForDefaultImpl;
494            JvmClassName ownerForDefaultParam;
495            int invokeOpcode;
496            JvmClassName thisClass;
497            if (functionParent instanceof NamespaceDescriptor) {
498                assert !superCall;
499                owner = jvmClassNameForNamespace((NamespaceDescriptor) functionParent, functionDescriptor, isInsideModule);
500                ownerForDefaultImpl = ownerForDefaultParam = owner;
501                invokeOpcode = INVOKESTATIC;
502                thisClass = null;
503            }
504            else if (functionDescriptor instanceof ConstructorDescriptor) {
505                assert !superCall;
506                ClassDescriptor containingClass = (ClassDescriptor) functionParent;
507                owner = JvmClassName.byType(mapType(containingClass.getDefaultType(), JetTypeMapperMode.IMPL));
508                ownerForDefaultImpl = ownerForDefaultParam = owner;
509                invokeOpcode = INVOKESPECIAL;
510                thisClass = null;
511            }
512            else if (functionParent instanceof ScriptDescriptor) {
513                thisClass = owner =
514                ownerForDefaultParam = ownerForDefaultImpl = classNameForScriptDescriptor(bindingContext, (ScriptDescriptor) functionParent);
515                invokeOpcode = INVOKEVIRTUAL;
516            }
517            else if (functionParent instanceof ClassDescriptor) {
518    
519                FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
520    
521                ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
522                ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
523    
524                boolean originalIsInterface = isInterface(declarationOwner);
525                boolean currentIsInterface = isInterface(currentOwner);
526    
527                boolean isAccessor = isAccessor(functionDescriptor);
528    
529                ClassDescriptor receiver;
530                if (currentIsInterface && !originalIsInterface) {
531                    receiver = declarationOwner;
532                }
533                else {
534                    receiver = currentOwner;
535                }
536    
537                // TODO: TYPE_PARAMETER is hack here
538    
539                boolean isInterface = originalIsInterface && currentIsInterface;
540                Type type = mapType(receiver.getDefaultType(), JetTypeMapperMode.TYPE_PARAMETER);
541                owner = JvmClassName.byType(type);
542    
543                ClassDescriptor declarationOwnerForDefault = (ClassDescriptor) findBaseDeclaration(functionDescriptor).getContainingDeclaration();
544                ownerForDefaultParam = JvmClassName.byType(mapType(declarationOwnerForDefault.getDefaultType(), JetTypeMapperMode.TYPE_PARAMETER));
545                ownerForDefaultImpl = JvmClassName.byInternalName(
546                        ownerForDefaultParam.getInternalName() + (isInterface(declarationOwnerForDefault) ? JvmAbi.TRAIT_IMPL_SUFFIX : ""));
547                if (isInterface) {
548                    invokeOpcode = superCall ? INVOKESTATIC : INVOKEINTERFACE;
549                }
550                else {
551                    if (isAccessor) {
552                        invokeOpcode = INVOKESTATIC;
553                    }
554                    else {
555                        boolean isPrivateFunInvocation = isInsideClass && functionDescriptor.getVisibility() == Visibilities.PRIVATE;
556                        invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
557                    }
558                }
559    
560                if (isInterface && superCall) {
561                    descriptor = mapSignature(functionDescriptor, false, OwnerKind.TRAIT_IMPL);
562                    owner = JvmClassName.byInternalName(owner.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
563                }
564                thisClass = JvmClassName.byType(mapType(receiver.getDefaultType()));
565            }
566            else {
567                throw new UnsupportedOperationException("unknown function parent");
568            }
569    
570    
571            Type receiverParameterType;
572            ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getReceiverParameter();
573            if (receiverParameter != null) {
574                receiverParameterType = mapType(receiverParameter.getType());
575            }
576            else {
577                receiverParameterType = null;
578            }
579            return new CallableMethod(
580                    owner, ownerForDefaultImpl, ownerForDefaultParam, descriptor, invokeOpcode,
581                    thisClass, receiverParameterType, null);
582        }
583    
584        public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
585            return descriptor instanceof AccessorForFunctionDescriptor ||
586                   descriptor instanceof AccessorForPropertyDescriptor ||
587                   descriptor instanceof AccessorForPropertyDescriptor.Getter ||
588                   descriptor instanceof AccessorForPropertyDescriptor.Setter;
589        }
590    
591        @NotNull
592        private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) {
593            if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
594                return function;
595            }
596            return findBaseDeclaration(function);
597        }
598    
599        @NotNull
600        private static FunctionDescriptor findBaseDeclaration(@NotNull FunctionDescriptor function) {
601            if (function.getOverriddenDescriptors().isEmpty()) {
602                return function;
603            }
604            else {
605                // TODO: prefer class to interface
606                return findBaseDeclaration(function.getOverriddenDescriptors().iterator().next());
607            }
608        }
609    
610        @NotNull
611        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, boolean needGenericSignature, @NotNull OwnerKind kind) {
612            String name = f.getName().asString();
613            if (f instanceof PropertyAccessorDescriptor) {
614                boolean isGetter = f instanceof PropertyGetterDescriptor;
615                name = getPropertyAccessorName(((PropertyAccessorDescriptor) f).getCorrespondingProperty(), isGetter);
616            }
617            return mapSignature(name, f, needGenericSignature, kind);
618        }
619    
620        @NotNull
621        public JvmMethodSignature mapSignature(@NotNull Name functionName, @NotNull FunctionDescriptor f) {
622            return mapSignature(functionName.asString(), f, false, OwnerKind.IMPLEMENTATION);
623        }
624    
625        @NotNull
626        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f) {
627            return mapSignature(f.getName(), f);
628        }
629    
630        @NotNull
631        private JvmMethodSignature mapSignature(
632                @NotNull String methodName,
633                @NotNull FunctionDescriptor f,
634                boolean needGenericSignature,
635                @NotNull OwnerKind kind
636        ) {
637            if (kind == OwnerKind.TRAIT_IMPL) {
638                needGenericSignature = false;
639            }
640    
641            BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, needGenericSignature);
642    
643            writeFormalTypeParameters(f.getTypeParameters(), signatureVisitor);
644    
645            signatureVisitor.writeParametersStart();
646            writeThisIfNeeded(f, kind, signatureVisitor);
647            writeReceiverIfNeeded(f.getReceiverParameter(), signatureVisitor);
648    
649            for (ValueParameterDescriptor parameter : f.getValueParameters()) {
650                writeParameter(signatureVisitor, parameter.getType());
651            }
652    
653            signatureVisitor.writeParametersEnd();
654    
655            if (f instanceof ConstructorDescriptor) {
656                signatureVisitor.writeVoidReturn();
657            }
658            else {
659                signatureVisitor.writeReturnType();
660                JetType returnType = f.getReturnType();
661                assert returnType != null : "Function " + f + " has no return type";
662                mapReturnType(returnType, signatureVisitor);
663                signatureVisitor.writeReturnTypeEnd();
664            }
665    
666            return signatureVisitor.makeJvmMethodSignature(methodName);
667        }
668    
669        @Nullable
670        public String mapFieldSignature(@NotNull JetType backingFieldType) {
671            BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE, true);
672            signatureVisitor.writeFieldTypeStart();
673            mapType(backingFieldType, signatureVisitor, JetTypeMapperMode.VALUE);
674            signatureVisitor.writeFieldTypeEnd();
675            return signatureVisitor.makeJavaGenericSignature();
676        }
677    
678        private void writeThisIfNeeded(
679                @NotNull CallableMemberDescriptor descriptor,
680                @NotNull OwnerKind kind,
681                @NotNull BothSignatureWriter signatureVisitor
682        ) {
683            if (kind == OwnerKind.TRAIT_IMPL) {
684                ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
685                Type type = getTraitImplThisParameterType(containingDeclaration, this);
686    
687                signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS);
688                signatureVisitor.writeAsmType(type, false);
689                signatureVisitor.writeParameterTypeEnd();
690            }
691            else {
692                writeThisForAccessorIfNeeded(descriptor, signatureVisitor);
693            }
694        }
695    
696        private void writeThisForAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BothSignatureWriter signatureVisitor) {
697            if (isAccessor(descriptor) && descriptor.getExpectedThisObject() != null) {
698                signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS);
699                mapType(((ClassifierDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), signatureVisitor, JetTypeMapperMode.VALUE);
700                signatureVisitor.writeParameterTypeEnd();
701            }
702        }
703    
704    
705        public void writeFormalTypeParameters(List<TypeParameterDescriptor> typeParameters, BothSignatureWriter signatureVisitor) {
706            if (signatureVisitor == null) {
707                return;
708            }
709    
710            signatureVisitor.writeFormalTypeParametersStart();
711            for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
712                writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor);
713            }
714            signatureVisitor.writeFormalTypeParametersEnd();
715        }
716    
717        private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) {
718            signatureVisitor.writeFormalTypeParameter(typeParameterDescriptor.getName().asString(), typeParameterDescriptor.getVariance(),
719                                                      typeParameterDescriptor.isReified());
720    
721            classBound:
722            {
723                signatureVisitor.writeClassBound();
724    
725                for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
726                    if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
727                        if (!isInterface(jetType)) {
728                            mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
729                            break classBound;
730                        }
731                    }
732                }
733    
734                // "extends Object" is optional according to ClassFileFormat-Java5.pdf
735                // but javac complaints to signature:
736                // <P:>Ljava/lang/Object;
737                // TODO: avoid writing java/lang/Object if interface list is not empty
738            }
739            signatureVisitor.writeClassBoundEnd();
740    
741            for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
742                if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
743                    if (isInterface(jetType)) {
744                        signatureVisitor.writeInterfaceBound();
745                        mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
746                        signatureVisitor.writeInterfaceBoundEnd();
747                    }
748                }
749                if (jetType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
750                    signatureVisitor.writeInterfaceBound();
751                    mapType(jetType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
752                    signatureVisitor.writeInterfaceBoundEnd();
753                }
754            }
755    
756            signatureVisitor.writeFormalTypeParameterEnd();
757        }
758    
759    
760        private void writeReceiverIfNeeded(@Nullable ReceiverParameterDescriptor receiver, BothSignatureWriter signatureWriter) {
761            if (receiver != null) {
762                signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
763                mapType(receiver.getType(), signatureWriter, JetTypeMapperMode.VALUE);
764                signatureWriter.writeParameterTypeEnd();
765            }
766        }
767    
768        @NotNull
769        public static String getPropertyAccessorName(@NotNull PropertyDescriptor descriptor, boolean isGetter) {
770            DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
771            boolean isAnnotation = parentDescriptor instanceof ClassDescriptor &&
772                                   ((ClassDescriptor) parentDescriptor).getKind() == ClassKind.ANNOTATION_CLASS;
773            return isAnnotation ? descriptor.getName().asString() :
774                   isGetter ? PropertyCodegen.getterName(descriptor.getName()) : PropertyCodegen.setterName(descriptor.getName());
775        }
776    
777        @NotNull
778        public JvmPropertyAccessorSignature mapGetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
779            // TODO: do not genClassOrObject generics if not needed
780            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
781    
782            writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter);
783    
784            signatureWriter.writeParametersStart();
785            writeThisIfNeeded(descriptor, kind, signatureWriter);
786            writeReceiverIfNeeded(descriptor.getReceiverParameter(), signatureWriter);
787            signatureWriter.writeParametersEnd();
788    
789            signatureWriter.writeReturnType();
790            mapType(descriptor.getType(), signatureWriter, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE);
791            signatureWriter.writeReturnTypeEnd();
792    
793            String name = getPropertyAccessorName(descriptor, true);
794            return signatureWriter.makeJvmPropertyAccessorSignature(name, true);
795        }
796    
797    
798        @NotNull
799        public JvmPropertyAccessorSignature mapSetterSignature(PropertyDescriptor descriptor, OwnerKind kind) {
800            assert descriptor.isVar();
801    
802            // TODO: generics signature is not always needed
803            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
804    
805            writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter);
806    
807            signatureWriter.writeParametersStart();
808            writeThisIfNeeded(descriptor, kind, signatureWriter);
809            writeReceiverIfNeeded(descriptor.getReceiverParameter(), signatureWriter);
810            writeParameter(signatureWriter, descriptor.getType());
811            signatureWriter.writeParametersEnd();
812    
813            signatureWriter.writeVoidReturn();
814    
815            String name = getPropertyAccessorName(descriptor, false);
816            return signatureWriter.makeJvmPropertyAccessorSignature(name, false);
817        }
818    
819        private void writeParameter(@NotNull BothSignatureWriter signatureWriter, @NotNull JetType outType) {
820            signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
821            mapType(outType, signatureWriter, JetTypeMapperMode.VALUE);
822            signatureWriter.writeParameterTypeEnd();
823        }
824    
825        @NotNull
826        public JvmMethodSignature mapConstructorSignature(@NotNull ConstructorDescriptor descriptor) {
827            return mapConstructorSignature(descriptor, bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration()));
828        }
829    
830        @NotNull
831        public JvmMethodSignature mapConstructorSignature(@NotNull ConstructorDescriptor descriptor, @Nullable CalculatedClosure closure) {
832    
833            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
834    
835            // constructor type parmeters are fake
836            writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
837    
838            signatureWriter.writeParametersStart();
839    
840            ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
841            ClassDescriptor captureThis = getExpectedThisObjectForConstructorCall(descriptor, closure);
842            if (captureThis != null) {
843                signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
844                mapType(captureThis.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
845                signatureWriter.writeParameterTypeEnd();
846            }
847    
848            ClassifierDescriptor captureReceiver = closure != null ? closure.getCaptureReceiver() : null;
849            if (captureReceiver != null) {
850                signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
851                mapType(captureReceiver.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
852                signatureWriter.writeParameterTypeEnd();
853            }
854    
855            if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
856                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_NAME);
857                mapType(KotlinBuiltIns.getInstance().getStringType(), signatureWriter, JetTypeMapperMode.VALUE);
858                signatureWriter.writeParameterTypeEnd();
859                signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_ORDINAL);
860                mapType(KotlinBuiltIns.getInstance().getIntType(), signatureWriter, JetTypeMapperMode.VALUE);
861                signatureWriter.writeParameterTypeEnd();
862            }
863    
864            if (closure != null) {
865                for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
866                    DeclarationDescriptor variableDescriptor = entry.getKey();
867                    Type type = null;
868                    if (variableDescriptor instanceof VariableDescriptor && !(variableDescriptor instanceof PropertyDescriptor)) {
869                        Type sharedVarType = getSharedVarType(variableDescriptor);
870                        if (sharedVarType == null) {
871                            sharedVarType = mapType(((VariableDescriptor) variableDescriptor).getType());
872                        }
873                        type = sharedVarType;
874                    }
875                    else if (isLocalNamedFun(variableDescriptor)) {
876                        type = classNameForAnonymousClass(bindingContext, (FunctionDescriptor) variableDescriptor).getAsmType();
877                    }
878    
879                    if (type != null) {
880                        signatureWriter.writeParameterType(JvmMethodParameterKind.SHARED_VAR);
881                        signatureWriter.writeAsmType(type, false);
882                        signatureWriter.writeParameterTypeEnd();
883                    }
884                }
885    
886                JetDelegatorToSuperCall superCall = closure.getSuperCall();
887                if (superCall != null) {
888                    DeclarationDescriptor superDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET,
889                                                                                                        superCall
890                                                                                                                .getCalleeExpression()
891                                                                                                                .getConstructorReferenceExpression());
892    
893                    if(superDescriptor instanceof ConstructorDescriptor) {
894                        ConstructorDescriptor superConstructor = (ConstructorDescriptor) superDescriptor;
895    
896                        if (isObjectLiteral(bindingContext, descriptor.getContainingDeclaration())) {
897                            List<JvmMethodParameterSignature> types = mapConstructorSignature(superConstructor).getKotlinParameterTypes();
898                            if (types != null) {
899                                for (JvmMethodParameterSignature type : types) {
900                                    signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_CALL_PARAM);
901                                    signatureWriter.writeAsmType(type.getAsmType(), false);
902                                    signatureWriter.writeParameterTypeEnd();
903                                }
904                            }
905                        }
906                    }
907                }
908            }
909    
910            for (ValueParameterDescriptor parameter : descriptor.getOriginal().getValueParameters()) {
911                writeParameter(signatureWriter, parameter.getType());
912            }
913    
914            signatureWriter.writeParametersEnd();
915    
916            signatureWriter.writeVoidReturn();
917    
918            return signatureWriter.makeJvmMethodSignature("<init>");
919        }
920    
921        @NotNull
922        public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
923            BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
924    
925            writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
926    
927            signatureWriter.writeParametersStart();
928    
929            for (ScriptDescriptor importedScript : importedScripts) {
930                signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
931                ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
932                assert descriptor != null;
933                mapType(descriptor.getDefaultType(), signatureWriter, JetTypeMapperMode.VALUE);
934                signatureWriter.writeParameterTypeEnd();
935            }
936    
937            for (ValueParameterDescriptor valueParameter : script.getValueParameters()) {
938                writeParameter(signatureWriter, valueParameter.getType());
939            }
940    
941            signatureWriter.writeParametersEnd();
942    
943            signatureWriter.writeVoidReturn();
944    
945            return signatureWriter.makeJvmMethodSignature("<init>");
946        }
947    
948        @NotNull
949        public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor) {
950            return mapToCallableMethod(descriptor, bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration()));
951        }
952    
953        @NotNull
954        public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor, @Nullable CalculatedClosure closure) {
955            JvmMethodSignature method = mapConstructorSignature(descriptor, closure);
956            JetType defaultType = descriptor.getContainingDeclaration().getDefaultType();
957            Type mapped = mapType(defaultType, JetTypeMapperMode.IMPL);
958            if (mapped.getSort() != Type.OBJECT) {
959                throw new IllegalStateException("type must have been mapped to object: " + defaultType + ", actual: " + mapped);
960            }
961            JvmClassName owner = JvmClassName.byType(mapped);
962            return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL, null, null, null);
963        }
964    
965    
966        private static boolean isGenericsArray(JetType type) {
967            return KotlinBuiltIns.getInstance().isArray(type) &&
968                   type.getArguments().get(0).getType().getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
969        }
970    
971        public Type getSharedVarType(DeclarationDescriptor descriptor) {
972            if (descriptor instanceof PropertyDescriptor) {
973                return StackValue
974                        .sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
975            }
976            else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
977                return classNameForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor).getAsmType();
978            }
979            else if (descriptor instanceof FunctionDescriptor) {
980                return StackValue
981                        .sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
982            }
983            else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
984                JetType outType = ((VariableDescriptor) descriptor).getType();
985                return StackValue.sharedTypeForType(mapType(outType));
986            }
987            return null;
988        }
989    
990        @NotNull
991        public CallableMethod mapToFunctionInvokeCallableMethod(@NotNull FunctionDescriptor fd) {
992            JvmMethodSignature descriptor = erasedInvokeSignature(fd);
993            JvmClassName owner = getFunctionTraitClassName(fd);
994            Type receiverParameterType;
995            ReceiverParameterDescriptor receiverParameter = fd.getOriginal().getReceiverParameter();
996            if (receiverParameter != null) {
997                receiverParameterType = mapType(receiverParameter.getType());
998            }
999            else {
1000                receiverParameterType = null;
1001            }
1002            return new CallableMethod(owner, null, null, descriptor, INVOKEINTERFACE, owner, receiverParameterType, owner.getAsmType());
1003        }
1004    
1005        @NotNull
1006        public Type expressionType(JetExpression expr) {
1007            JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr);
1008            return asmTypeOrVoid(type);
1009        }
1010    
1011        @NotNull
1012        private Type asmTypeOrVoid(@Nullable JetType type) {
1013            return type == null ? Type.VOID_TYPE : mapType(type);
1014        }
1015    }