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