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