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