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