001    /*
002     * Copyright 2010-2015 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.kotlin.builtins;
018    
019    import kotlin.KotlinPackage;
020    import kotlin.jvm.functions.Function1;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory;
024    import org.jetbrains.kotlin.descriptors.*;
025    import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl;
027    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
028    import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl;
029    import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
030    import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
031    import org.jetbrains.kotlin.name.FqName;
032    import org.jetbrains.kotlin.name.FqNameUnsafe;
033    import org.jetbrains.kotlin.name.Name;
034    import org.jetbrains.kotlin.resolve.DescriptorUtils;
035    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
036    import org.jetbrains.kotlin.resolve.scopes.JetScope;
037    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
038    import org.jetbrains.kotlin.types.*;
039    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
040    
041    import java.io.InputStream;
042    import java.util.*;
043    
044    import static kotlin.KotlinPackage.*;
045    import static org.jetbrains.kotlin.builtins.PrimitiveType.*;
046    import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName;
047    
048    public class KotlinBuiltIns {
049        public static final Name BUILT_INS_PACKAGE_NAME = Name.identifier("kotlin");
050        public static final FqName BUILT_INS_PACKAGE_FQ_NAME = FqName.topLevel(BUILT_INS_PACKAGE_NAME);
051    
052        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
053    
054        private static volatile KotlinBuiltIns instance = null;
055    
056        private static volatile boolean initializing;
057        private static Throwable initializationFailed;
058    
059        private static synchronized void initialize() {
060            if (instance == null) {
061                if (initializationFailed != null) {
062                    throw new IllegalStateException(
063                            "Built-in library initialization failed previously: " + initializationFailed, initializationFailed
064                    );
065                }
066                if (initializing) {
067                    throw new IllegalStateException("Built-in library initialization loop");
068                }
069                initializing = true;
070                try {
071                    instance = new KotlinBuiltIns();
072                    instance.doInitialize();
073                }
074                catch (Throwable e) {
075                    initializationFailed = e;
076                    throw new IllegalStateException("Built-in library initialization failed. " +
077                                                    "Please ensure you have kotlin-runtime.jar in the classpath: " + e, e);
078                }
079                finally {
080                    initializing = false;
081                }
082            }
083        }
084    
085        @NotNull
086        public static KotlinBuiltIns getInstance() {
087            if (initializing) {
088                synchronized (KotlinBuiltIns.class) {
089                    assert instance != null : "Built-ins are not initialized (note: We are under the same lock as initializing and instance)";
090                    return instance;
091                }
092            }
093            if (instance == null) {
094                initialize();
095            }
096            return instance;
097        }
098    
099        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100    
101        private final ModuleDescriptorImpl builtInsModule;
102        private final BuiltinsPackageFragment builtinsPackageFragment;
103    
104        private final Map<PrimitiveType, JetType> primitiveTypeToArrayJetType;
105        private final Map<JetType, JetType> primitiveJetTypeToJetArrayType;
106        private final Map<JetType, JetType> jetArrayTypeToPrimitiveJetType;
107    
108        public static final FqNames FQ_NAMES = new FqNames();
109    
110        private KotlinBuiltIns() {
111            LockBasedStorageManager storageManager = new LockBasedStorageManager();
112            builtInsModule = new ModuleDescriptorImpl(
113                    Name.special("<built-ins module>"), storageManager, ModuleParameters.Empty.INSTANCE$
114            );
115    
116            PackageFragmentProvider packageFragmentProvider = BuiltinsPackage.createBuiltInPackageFragmentProvider(
117                    storageManager, builtInsModule,
118                    setOf(BUILT_INS_PACKAGE_FQ_NAME, BuiltinsPackage.getKOTLIN_REFLECT_FQ_NAME()),
119                    new BuiltInFictitiousFunctionClassFactory(storageManager, builtInsModule),
120                    new Function1<String, InputStream>() {
121                        @Override
122                        public InputStream invoke(String path) {
123                            return KotlinBuiltIns.class.getClassLoader().getResourceAsStream(path);
124                        }
125                    }
126            );
127    
128            builtInsModule.initialize(packageFragmentProvider);
129            builtInsModule.addDependencyOnModule(builtInsModule);
130            builtInsModule.seal();
131    
132            builtinsPackageFragment = (BuiltinsPackageFragment) single(packageFragmentProvider.getPackageFragments(BUILT_INS_PACKAGE_FQ_NAME));
133    
134            primitiveTypeToArrayJetType = new EnumMap<PrimitiveType, JetType>(PrimitiveType.class);
135            primitiveJetTypeToJetArrayType = new HashMap<JetType, JetType>();
136            jetArrayTypeToPrimitiveJetType = new HashMap<JetType, JetType>();
137        }
138    
139        private void doInitialize() {
140            for (PrimitiveType primitive : PrimitiveType.values()) {
141                makePrimitive(primitive);
142            }
143        }
144    
145        private void makePrimitive(@NotNull PrimitiveType primitiveType) {
146            JetType type = getBuiltInTypeByClassName(primitiveType.getTypeName().asString());
147            JetType arrayType = getBuiltInTypeByClassName(primitiveType.getArrayTypeName().asString());
148    
149            primitiveTypeToArrayJetType.put(primitiveType, arrayType);
150            primitiveJetTypeToJetArrayType.put(type, arrayType);
151            jetArrayTypeToPrimitiveJetType.put(arrayType, type);
152        }
153    
154        public static class FqNames {
155            public final FqNameUnsafe any = fqNameUnsafe("Any");
156            public final FqNameUnsafe nothing = fqNameUnsafe("Nothing");
157            public final FqNameUnsafe cloneable = fqNameUnsafe("Cloneable");
158            public final FqNameUnsafe suppress = fqNameUnsafe("suppress");
159            public final FqNameUnsafe unit = fqNameUnsafe("Unit");
160            public final FqNameUnsafe string = fqNameUnsafe("String");
161            public final FqNameUnsafe array = fqNameUnsafe("Array");
162    
163            public final FqNameUnsafe _boolean = fqNameUnsafe("Boolean");
164            public final FqNameUnsafe _char = fqNameUnsafe("Char");
165            public final FqNameUnsafe _byte = fqNameUnsafe("Byte");
166            public final FqNameUnsafe _short = fqNameUnsafe("Short");
167            public final FqNameUnsafe _int = fqNameUnsafe("Int");
168            public final FqNameUnsafe _long = fqNameUnsafe("Long");
169            public final FqNameUnsafe _float = fqNameUnsafe("Float");
170            public final FqNameUnsafe _double = fqNameUnsafe("Double");
171    
172            public final FqName data = fqName("data");
173            public final FqName deprecated = fqName("deprecated");
174            public final FqName tailRecursive = fqName("tailRecursive");
175            public final FqName inline = fqName("inline");
176            public final FqName noinline = fqName("noinline");
177            public final FqName inlineOptions = fqName("inlineOptions");
178            public final FqName extension = fqName("extension");
179    
180            public final FqNameUnsafe kClass = new FqName("kotlin.reflect.KClass").toUnsafe();
181    
182            public final Map<FqNameUnsafe, PrimitiveType> fqNameToPrimitiveType;
183            public final Map<FqNameUnsafe, PrimitiveType> arrayClassFqNameToPrimitiveType;
184            {
185                fqNameToPrimitiveType = new HashMap<FqNameUnsafe, PrimitiveType>(0);
186                arrayClassFqNameToPrimitiveType = new HashMap<FqNameUnsafe, PrimitiveType>(0);
187                for (PrimitiveType primitiveType : PrimitiveType.values()) {
188                    fqNameToPrimitiveType.put(fqNameUnsafe(primitiveType.getTypeName().asString()), primitiveType);
189                    arrayClassFqNameToPrimitiveType.put(fqNameUnsafe(primitiveType.getArrayTypeName().asString()), primitiveType);
190                }
191            }
192    
193            @NotNull
194            private static FqNameUnsafe fqNameUnsafe(@NotNull String simpleName) {
195                return fqName(simpleName).toUnsafe();
196            }
197    
198            @NotNull
199            private static FqName fqName(@NotNull String simpleName) {
200                return BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(simpleName));
201            }
202        }
203    
204        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205    
206        @NotNull
207        public ModuleDescriptorImpl getBuiltInsModule() {
208            return builtInsModule;
209        }
210    
211        @NotNull
212        public PackageFragmentDescriptor getBuiltInsPackageFragment() {
213            return builtinsPackageFragment;
214        }
215    
216        @NotNull
217        public JetScope getBuiltInsPackageScope() {
218            return builtinsPackageFragment.getMemberScope();
219        }
220    
221        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
222    
223        // GET CLASS
224    
225        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
226    
227        @NotNull
228        public ClassDescriptor getBuiltInClassByName(@NotNull Name simpleName) {
229            ClassifierDescriptor classifier = getBuiltInsPackageFragment().getMemberScope().getClassifier(simpleName);
230            assert classifier instanceof ClassDescriptor : "Must be a class descriptor " + simpleName + ", but was " + classifier;
231            return (ClassDescriptor) classifier;
232        }
233    
234        @NotNull
235        private ClassDescriptor getBuiltInClassByName(@NotNull String simpleName) {
236            return getBuiltInClassByName(Name.identifier(simpleName));
237        }
238    
239        // Special
240    
241        @NotNull
242        public ClassDescriptor getAny() {
243            return getBuiltInClassByName("Any");
244        }
245    
246        @NotNull
247        public ClassDescriptor getNothing() {
248            return getBuiltInClassByName("Nothing");
249        }
250    
251        // Primitive
252    
253        @NotNull
254        public ClassDescriptor getPrimitiveClassDescriptor(@NotNull PrimitiveType type) {
255            return getBuiltInClassByName(type.getTypeName().asString());
256        }
257    
258        @NotNull
259        public ClassDescriptor getByte() {
260            return getPrimitiveClassDescriptor(BYTE);
261        }
262    
263        @NotNull
264        public ClassDescriptor getShort() {
265            return getPrimitiveClassDescriptor(SHORT);
266        }
267    
268        @NotNull
269        public ClassDescriptor getInt() {
270            return getPrimitiveClassDescriptor(INT);
271        }
272    
273        @NotNull
274        public ClassDescriptor getLong() {
275            return getPrimitiveClassDescriptor(LONG);
276        }
277    
278        @NotNull
279        public ClassDescriptor getFloat() {
280            return getPrimitiveClassDescriptor(FLOAT);
281        }
282    
283        @NotNull
284        public ClassDescriptor getDouble() {
285            return getPrimitiveClassDescriptor(DOUBLE);
286        }
287    
288        @NotNull
289        public ClassDescriptor getChar() {
290            return getPrimitiveClassDescriptor(CHAR);
291        }
292    
293        @NotNull
294        public ClassDescriptor getBoolean() {
295            return getPrimitiveClassDescriptor(BOOLEAN);
296        }
297    
298        // Recognized
299    
300        @NotNull
301        public Set<DeclarationDescriptor> getIntegralRanges() {
302            return KotlinPackage.<DeclarationDescriptor>setOf(
303                    getBuiltInClassByName("ByteRange"),
304                    getBuiltInClassByName("ShortRange"),
305                    getBuiltInClassByName("CharRange"),
306                    getBuiltInClassByName("IntRange")
307            );
308        }
309    
310        @NotNull
311        public ClassDescriptor getArray() {
312            return getBuiltInClassByName("Array");
313        }
314    
315        @NotNull
316        public ClassDescriptor getPrimitiveArrayClassDescriptor(@NotNull PrimitiveType type) {
317            return getBuiltInClassByName(type.getArrayTypeName().asString());
318        }
319    
320        @NotNull
321        public ClassDescriptor getNumber() {
322            return getBuiltInClassByName("Number");
323        }
324    
325        @NotNull
326        public ClassDescriptor getUnit() {
327            return getBuiltInClassByName("Unit");
328        }
329    
330        @NotNull
331        public ClassDescriptor getFunction(int parameterCount) {
332            return getBuiltInClassByName("Function" + parameterCount);
333        }
334    
335        /**
336         * @return the descriptor representing the class kotlin.Function{parameterCount + 1}
337         * @deprecated there are no ExtensionFunction classes anymore, use {@link #getFunction(int)} instead
338         */
339        @Deprecated
340        @NotNull
341        public ClassDescriptor getExtensionFunction(int parameterCount) {
342            return getBuiltInClassByName("Function" + (parameterCount + 1));
343        }
344    
345        @NotNull
346        public ClassDescriptor getThrowable() {
347            return getBuiltInClassByName("Throwable");
348        }
349    
350        @NotNull
351        public ClassDescriptor getCloneable() {
352            return getBuiltInClassByName("Cloneable");
353        }
354    
355        @NotNull
356        public ClassDescriptor getDataClassAnnotation() {
357            return getBuiltInClassByName("data");
358        }
359    
360        @NotNull
361        public ClassDescriptor getDeprecatedAnnotation() {
362            return getBuiltInClassByName("deprecated");
363        }
364    
365        @NotNull
366        public ClassDescriptor getString() {
367            return getBuiltInClassByName("String");
368        }
369    
370        @NotNull
371        public ClassDescriptor getCharSequence() {
372            return getBuiltInClassByName("CharSequence");
373        }
374    
375        @NotNull
376        public ClassDescriptor getComparable() {
377            return getBuiltInClassByName("Comparable");
378        }
379    
380        @NotNull
381        public ClassDescriptor getEnum() {
382            return getBuiltInClassByName("Enum");
383        }
384    
385        @NotNull
386        public ClassDescriptor getAnnotation() {
387            return getBuiltInClassByName("Annotation");
388        }
389    
390        @NotNull
391        public ClassDescriptor getIterator() {
392            return getBuiltInClassByName("Iterator");
393        }
394    
395        @NotNull
396        public ClassDescriptor getIterable() {
397            return getBuiltInClassByName("Iterable");
398        }
399    
400        @NotNull
401        public ClassDescriptor getMutableIterable() {
402            return getBuiltInClassByName("MutableIterable");
403        }
404    
405        @NotNull
406        public ClassDescriptor getMutableIterator() {
407            return getBuiltInClassByName("MutableIterator");
408        }
409    
410        @NotNull
411        public ClassDescriptor getCollection() {
412            return getBuiltInClassByName("Collection");
413        }
414    
415        @NotNull
416        public ClassDescriptor getMutableCollection() {
417            return getBuiltInClassByName("MutableCollection");
418        }
419    
420        @NotNull
421        public ClassDescriptor getList() {
422            return getBuiltInClassByName("List");
423        }
424    
425        @NotNull
426        public ClassDescriptor getMutableList() {
427            return getBuiltInClassByName("MutableList");
428        }
429    
430        @NotNull
431        public ClassDescriptor getSet() {
432            return getBuiltInClassByName("Set");
433        }
434    
435        @NotNull
436        public ClassDescriptor getMutableSet() {
437            return getBuiltInClassByName("MutableSet");
438        }
439    
440        @NotNull
441        public ClassDescriptor getMap() {
442            return getBuiltInClassByName("Map");
443        }
444    
445        @NotNull
446        public ClassDescriptor getMutableMap() {
447            return getBuiltInClassByName("MutableMap");
448        }
449    
450        @NotNull
451        public ClassDescriptor getMapEntry() {
452            ClassDescriptor classDescriptor = DescriptorUtils.getInnerClassByName(getMap(), "Entry");
453            assert classDescriptor != null : "Can't find Map.Entry";
454            return classDescriptor;
455        }
456    
457        @NotNull
458        public ClassDescriptor getMutableMapEntry() {
459            ClassDescriptor classDescriptor = DescriptorUtils.getInnerClassByName(getMutableMap(), "MutableEntry");
460            assert classDescriptor != null : "Can't find MutableMap.MutableEntry";
461            return classDescriptor;
462        }
463    
464        @NotNull
465        public ClassDescriptor getListIterator() {
466            return getBuiltInClassByName("ListIterator");
467        }
468    
469        @NotNull
470        public ClassDescriptor getMutableListIterator() {
471            return getBuiltInClassByName("MutableListIterator");
472        }
473    
474        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
475    
476        // GET TYPE
477    
478        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
479    
480        @NotNull
481        private JetType getBuiltInTypeByClassName(@NotNull String classSimpleName) {
482            return getBuiltInClassByName(classSimpleName).getDefaultType();
483        }
484    
485        // Special
486    
487        @NotNull
488        public JetType getNothingType() {
489            return getNothing().getDefaultType();
490        }
491    
492        @NotNull
493        public JetType getNullableNothingType() {
494            return TypeUtils.makeNullable(getNothingType());
495        }
496    
497        @NotNull
498        public JetType getAnyType() {
499            return getAny().getDefaultType();
500        }
501    
502        @NotNull
503        public JetType getNullableAnyType() {
504            return TypeUtils.makeNullable(getAnyType());
505        }
506    
507        // Primitive
508    
509        @NotNull
510        public JetType getPrimitiveJetType(@NotNull PrimitiveType type) {
511            return getPrimitiveClassDescriptor(type).getDefaultType();
512        }
513    
514        @NotNull
515        public JetType getByteType() {
516            return getPrimitiveJetType(BYTE);
517        }
518    
519        @NotNull
520        public JetType getShortType() {
521            return getPrimitiveJetType(SHORT);
522        }
523    
524        @NotNull
525        public JetType getIntType() {
526            return getPrimitiveJetType(INT);
527        }
528    
529        @NotNull
530        public JetType getLongType() {
531            return getPrimitiveJetType(LONG);
532        }
533    
534        @NotNull
535        public JetType getFloatType() {
536            return getPrimitiveJetType(FLOAT);
537        }
538    
539        @NotNull
540        public JetType getDoubleType() {
541            return getPrimitiveJetType(DOUBLE);
542        }
543    
544        @NotNull
545        public JetType getCharType() {
546            return getPrimitiveJetType(CHAR);
547        }
548    
549        @NotNull
550        public JetType getBooleanType() {
551            return getPrimitiveJetType(BOOLEAN);
552        }
553    
554        // Recognized
555    
556        @NotNull
557        public JetType getUnitType() {
558            return getUnit().getDefaultType();
559        }
560    
561        @NotNull
562        public JetType getStringType() {
563            return getString().getDefaultType();
564        }
565    
566        @NotNull
567        public JetType getArrayElementType(@NotNull JetType arrayType) {
568            if (isArray(arrayType)) {
569                if (arrayType.getArguments().size() != 1) {
570                    throw new IllegalStateException();
571                }
572                return arrayType.getArguments().get(0).getType();
573            }
574            JetType primitiveType = jetArrayTypeToPrimitiveJetType.get(TypeUtils.makeNotNullable(arrayType));
575            if (primitiveType == null) {
576                throw new IllegalStateException("not array: " + arrayType);
577            }
578            return primitiveType;
579        }
580    
581        @NotNull
582        public JetType getPrimitiveArrayJetType(@NotNull PrimitiveType primitiveType) {
583            return primitiveTypeToArrayJetType.get(primitiveType);
584        }
585    
586        /**
587         * @return {@code null} if not primitive
588         */
589        @Nullable
590        public JetType getPrimitiveArrayJetTypeByPrimitiveJetType(@NotNull JetType jetType) {
591            return primitiveJetTypeToJetArrayType.get(jetType);
592        }
593    
594        @Nullable
595        public static PrimitiveType getPrimitiveTypeByFqName(@NotNull FqNameUnsafe primitiveClassFqName) {
596            return FQ_NAMES.fqNameToPrimitiveType.get(primitiveClassFqName);
597        }
598    
599        @Nullable
600        public static PrimitiveType getPrimitiveTypeByArrayClassFqName(@NotNull FqNameUnsafe primitiveArrayClassFqName) {
601            return FQ_NAMES.arrayClassFqNameToPrimitiveType.get(primitiveArrayClassFqName);
602        }
603    
604        @NotNull
605        public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) {
606            List<TypeProjectionImpl> types = Collections.singletonList(new TypeProjectionImpl(projectionType, argument));
607            return new JetTypeImpl(
608                    Annotations.EMPTY,
609                    getArray().getTypeConstructor(),
610                    false,
611                    types,
612                    getArray().getMemberScope(types)
613            );
614        }
615    
616        @NotNull
617        public JetType getEnumType(@NotNull JetType argument) {
618            Variance projectionType = Variance.INVARIANT;
619            List<TypeProjectionImpl> types = Collections.singletonList(new TypeProjectionImpl(projectionType, argument));
620            return new JetTypeImpl(
621                    Annotations.EMPTY,
622                    getEnum().getTypeConstructor(),
623                    false,
624                    types,
625                    getEnum().getMemberScope(types)
626            );
627        }
628    
629        @NotNull
630        public JetType getAnnotationType() {
631            return getAnnotation().getDefaultType();
632        }
633    
634        @NotNull
635        public ClassDescriptor getPropertyMetadata() {
636            return getBuiltInClassByName("PropertyMetadata");
637        }
638    
639        @NotNull
640        public ClassDescriptor getPropertyMetadataImpl() {
641            return getBuiltInClassByName("PropertyMetadataImpl");
642        }
643    
644        @NotNull
645        public AnnotationDescriptor createExtensionAnnotation() {
646            return new AnnotationDescriptorImpl(getBuiltInClassByName("extension").getDefaultType(),
647                                                Collections.<ValueParameterDescriptor, CompileTimeConstant<?>>emptyMap());
648        }
649    
650        private static boolean isTypeAnnotatedWithExtension(@NotNull JetType type) {
651            return type.getAnnotations().findAnnotation(FQ_NAMES.extension) != null;
652        }
653    
654        @NotNull
655        public JetType getFunctionType(
656                @NotNull Annotations annotations,
657                @Nullable JetType receiverType,
658                @NotNull List<JetType> parameterTypes,
659                @NotNull JetType returnType
660        ) {
661            List<TypeProjection> arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType);
662            int size = parameterTypes.size();
663            ClassDescriptor classDescriptor = receiverType == null ? getFunction(size) : getExtensionFunction(size);
664            TypeConstructor constructor = classDescriptor.getTypeConstructor();
665    
666            Annotations typeAnnotations = receiverType == null ? annotations : addExtensionAnnotation(annotations);
667    
668            return new JetTypeImpl(typeAnnotations, constructor, false, arguments, classDescriptor.getMemberScope(arguments));
669        }
670    
671        @NotNull
672        private Annotations addExtensionAnnotation(@NotNull Annotations annotations) {
673            if (annotations.findAnnotation(FQ_NAMES.extension) != null) return annotations;
674    
675            // TODO: preserve laziness of given annotations
676            return new AnnotationsImpl(plus(annotations, listOf(createExtensionAnnotation())));
677        }
678    
679        @NotNull
680        public static List<TypeProjection> getFunctionTypeArgumentProjections(
681                @Nullable JetType receiverType,
682                @NotNull List<JetType> parameterTypes,
683                @NotNull JetType returnType
684        ) {
685            List<TypeProjection> arguments = new ArrayList<TypeProjection>();
686            if (receiverType != null) {
687                arguments.add(defaultProjection(receiverType));
688            }
689            for (JetType parameterType : parameterTypes) {
690                arguments.add(defaultProjection(parameterType));
691            }
692            arguments.add(defaultProjection(returnType));
693            return arguments;
694        }
695    
696        private static TypeProjection defaultProjection(JetType returnType) {
697            return new TypeProjectionImpl(Variance.INVARIANT, returnType);
698        }
699    
700        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
701    
702        // IS TYPE
703    
704        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
705    
706        public static boolean isArray(@NotNull JetType type) {
707            return isConstructedFromGivenClass(type, FQ_NAMES.array);
708        }
709    
710        public static boolean isPrimitiveArray(@NotNull JetType type) {
711            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
712            return descriptor != null && getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null;
713        }
714    
715        public static boolean isPrimitiveType(@NotNull JetType type) {
716            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
717            return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor);
718        }
719    
720        public static boolean isPrimitiveClass(@NotNull ClassDescriptor descriptor) {
721            return getPrimitiveTypeByFqName(getFqName(descriptor)) != null;
722        }
723    
724        // Functions
725    
726        public static boolean isFunctionOrExtensionFunctionType(@NotNull JetType type) {
727            return isFunctionType(type) || isExtensionFunctionType(type);
728        }
729    
730        public static boolean isFunctionType(@NotNull JetType type) {
731            if (isExactFunctionType(type)) return true;
732    
733            for (JetType superType : type.getConstructor().getSupertypes()) {
734                if (isFunctionType(superType)) return true;
735            }
736    
737            return false;
738        }
739    
740        public static boolean isExtensionFunctionType(@NotNull JetType type) {
741            if (isExactExtensionFunctionType(type)) return true;
742    
743            for (JetType superType : type.getConstructor().getSupertypes()) {
744                if (isExtensionFunctionType(superType)) return true;
745            }
746    
747            return false;
748        }
749    
750        public static boolean isExactFunctionOrExtensionFunctionType(@NotNull JetType type) {
751            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
752            return descriptor != null && isNumberedFunctionClassFqName(getFqName(descriptor));
753        }
754    
755        public static boolean isExactFunctionType(@NotNull JetType type) {
756            return isExactFunctionOrExtensionFunctionType(type) && !isTypeAnnotatedWithExtension(type);
757        }
758    
759        public static boolean isExactExtensionFunctionType(@NotNull JetType type) {
760            return isExactFunctionOrExtensionFunctionType(type) && isTypeAnnotatedWithExtension(type);
761        }
762    
763        /**
764         * @return true if this is an FQ name of a fictitious class representing the function type,
765         * e.g. kotlin.Function1 (but NOT kotlin.reflect.KFunction1)
766         */
767        public static boolean isNumberedFunctionClassFqName(@NotNull FqNameUnsafe fqName) {
768            List<Name> segments = fqName.pathSegments();
769            if (segments.size() != 2) return false;
770    
771            if (!BUILT_INS_PACKAGE_NAME.equals(first(segments))) return false;
772    
773            String shortName = last(segments).asString();
774            return BuiltInFictitiousFunctionClassFactory.parseClassName(shortName, BUILT_INS_PACKAGE_FQ_NAME) != null;
775        }
776    
777        @Nullable
778        public static JetType getReceiverType(@NotNull JetType type) {
779            assert isFunctionOrExtensionFunctionType(type) : type;
780            if (isExtensionFunctionType(type)) {
781                // TODO: this is incorrect when a class extends from an extension function and swaps type arguments
782                return type.getArguments().get(0).getType();
783            }
784            return null;
785        }
786    
787        @NotNull
788        public static List<ValueParameterDescriptor> getValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull JetType type) {
789            assert isFunctionOrExtensionFunctionType(type);
790            List<TypeProjection> parameterTypes = getParameterTypeProjectionsFromFunctionType(type);
791            List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(parameterTypes.size());
792            for (int i = 0; i < parameterTypes.size(); i++) {
793                TypeProjection parameterType = parameterTypes.get(i);
794                ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(
795                        functionDescriptor, null, i, Annotations.EMPTY,
796                        Name.identifier("p" + (i + 1)), parameterType.getType(), false, null, SourceElement.NO_SOURCE
797                );
798                valueParameters.add(valueParameterDescriptor);
799            }
800            return valueParameters;
801        }
802    
803        @NotNull
804        public static JetType getReturnTypeFromFunctionType(@NotNull JetType type) {
805            assert isFunctionOrExtensionFunctionType(type);
806            List<TypeProjection> arguments = type.getArguments();
807            return arguments.get(arguments.size() - 1).getType();
808        }
809    
810        @NotNull
811        public static List<TypeProjection> getParameterTypeProjectionsFromFunctionType(@NotNull JetType type) {
812            assert isFunctionOrExtensionFunctionType(type);
813            List<TypeProjection> arguments = type.getArguments();
814            int first = isExtensionFunctionType(type) ? 1 : 0;
815            int last = arguments.size() - 2;
816            List<TypeProjection> parameterTypes = new ArrayList<TypeProjection>(last - first + 1);
817            for (int i = first; i <= last; i++) {
818                parameterTypes.add(arguments.get(i));
819            }
820            return parameterTypes;
821        }
822    
823        // Recognized & special
824    
825        private static boolean isConstructedFromGivenClass(@NotNull JetType type, @NotNull FqNameUnsafe fqName) {
826            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
827            return descriptor != null && fqName.equals(getFqName(descriptor));
828        }
829    
830        private static boolean isNotNullConstructedFromGivenClass(@NotNull JetType type, @NotNull FqNameUnsafe fqName) {
831            return !type.isMarkedNullable() && isConstructedFromGivenClass(type, fqName);
832        }
833    
834        public static boolean isSpecialClassWithNoSupertypes(@NotNull ClassDescriptor descriptor) {
835            FqNameUnsafe fqName = getFqName(descriptor);
836            return FQ_NAMES.any.equals(fqName) || FQ_NAMES.nothing.equals(fqName);
837        }
838    
839        public static boolean isAny(@NotNull ClassDescriptor descriptor) {
840            return isAny(getFqName(descriptor));
841        }
842    
843        public static boolean isBoolean(@NotNull JetType type) {
844            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._boolean);
845        }
846    
847        public static boolean isBoolean(@NotNull ClassDescriptor classDescriptor) {
848            return FQ_NAMES._boolean.equals(getFqName(classDescriptor));
849        }
850    
851        public static boolean isChar(@NotNull JetType type) {
852            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._char);
853        }
854    
855        public static boolean isInt(@NotNull JetType type) {
856            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._int);
857        }
858    
859        public static boolean isByte(@NotNull JetType type) {
860            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._byte);
861        }
862    
863        public static boolean isLong(@NotNull JetType type) {
864            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._long);
865        }
866    
867        public static boolean isShort(@NotNull JetType type) {
868            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._short);
869        }
870    
871        public static boolean isFloat(@NotNull JetType type) {
872            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._float);
873        }
874    
875        public static boolean isDouble(@NotNull JetType type) {
876            return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._double);
877        }
878    
879        private static boolean isConstructedFromGivenClassAndNotNullable(@NotNull JetType type, @NotNull FqNameUnsafe fqName) {
880            return isConstructedFromGivenClass(type, fqName) && !type.isMarkedNullable();
881        }
882    
883        public static boolean isAny(@NotNull FqNameUnsafe fqName) {
884            return FQ_NAMES.any.equals(fqName);
885        }
886    
887        public static boolean isNothing(@NotNull JetType type) {
888            return isNothingOrNullableNothing(type)
889                   && !type.isMarkedNullable();
890        }
891    
892        public static boolean isNullableNothing(@NotNull JetType type) {
893            return isNothingOrNullableNothing(type)
894                   && type.isMarkedNullable();
895        }
896    
897        public static boolean isNothingOrNullableNothing(@NotNull JetType type) {
898            return isConstructedFromGivenClass(type, FQ_NAMES.nothing);
899        }
900    
901        public static boolean isAnyOrNullableAny(@NotNull JetType type) {
902            return isConstructedFromGivenClass(type, FQ_NAMES.any);
903        }
904    
905        public static boolean isNullableAny(@NotNull JetType type) {
906            return isAnyOrNullableAny(type) && type.isMarkedNullable();
907        }
908    
909        public static boolean isUnit(@NotNull JetType type) {
910            return isNotNullConstructedFromGivenClass(type, FQ_NAMES.unit);
911        }
912    
913        public boolean isBooleanOrSubtype(@NotNull JetType type) {
914            return JetTypeChecker.DEFAULT.isSubtypeOf(type, getBooleanType());
915        }
916    
917        public static boolean isString(@Nullable JetType type) {
918            return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.string);
919        }
920    
921        public static boolean isKClass(@NotNull ClassDescriptor descriptor) {
922            return FQ_NAMES.kClass.equals(getFqName(descriptor));
923        }
924    
925        public static boolean isNonPrimitiveArray(@NotNull ClassDescriptor descriptor) {
926            return FQ_NAMES.array.equals(getFqName(descriptor));
927        }
928    
929        public static boolean isCloneable(@NotNull ClassDescriptor descriptor) {
930            return FQ_NAMES.cloneable.equals(getFqName(descriptor));
931        }
932    
933        public static boolean isData(@NotNull ClassDescriptor classDescriptor) {
934            return containsAnnotation(classDescriptor, FQ_NAMES.data);
935        }
936    
937        public static boolean isDeprecated(@NotNull DeclarationDescriptor declarationDescriptor) {
938            return containsAnnotation(declarationDescriptor, FQ_NAMES.deprecated);
939        }
940    
941        public static boolean isTailRecursive(@NotNull DeclarationDescriptor declarationDescriptor) {
942            return containsAnnotation(declarationDescriptor, FQ_NAMES.tailRecursive);
943        }
944    
945        /** Checks that the symbol represented by the descriptor is annotated with the {@code kotlin.noinline} annotation */
946        public static boolean isNoinline(@NotNull DeclarationDescriptor descriptor) {
947            return containsAnnotation(descriptor, FQ_NAMES.noinline);
948        }
949    
950        public static boolean isSuppressAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
951            return isConstructedFromGivenClass(annotationDescriptor.getType(), FQ_NAMES.suppress);
952        }
953    
954        private static boolean containsAnnotation(DeclarationDescriptor descriptor, FqName annotationClassFqName) {
955            return descriptor.getOriginal().getAnnotations().findAnnotation(annotationClassFqName) != null;
956        }
957    
958        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
959    
960        @NotNull
961        public JetType getDefaultBound() {
962            return getNullableAnyType();
963        }
964    
965        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
966    
967        // GET FUNCTION
968    
969        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
970    
971        @NotNull
972        public FunctionDescriptor getIdentityEquals() {
973            return KotlinPackage.first(getBuiltInsPackageFragment().getMemberScope().getFunctions(Name.identifier("identityEquals")));
974        }
975    }