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