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