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