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