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