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