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
017package org.jetbrains.jet.lang.types.lang;
018
019import com.google.common.base.Predicates;
020import com.google.common.collect.ImmutableSet;
021import com.google.common.collect.Lists;
022import com.google.common.collect.Sets;
023import com.intellij.openapi.progress.ProcessCanceledException;
024import com.intellij.openapi.project.Project;
025import com.intellij.openapi.util.io.FileUtil;
026import com.intellij.openapi.util.text.StringUtil;
027import com.intellij.psi.PsiFileFactory;
028import com.intellij.util.LocalTimeCounter;
029import org.jetbrains.annotations.NotNull;
030import org.jetbrains.annotations.Nullable;
031import org.jetbrains.jet.lang.DefaultModuleConfiguration;
032import org.jetbrains.jet.lang.ModuleConfiguration;
033import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
034import org.jetbrains.jet.lang.descriptors.*;
035import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
036import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
037import org.jetbrains.jet.lang.psi.JetFile;
038import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
039import org.jetbrains.jet.lang.resolve.BindingTraceContext;
040import org.jetbrains.jet.lang.resolve.DescriptorUtils;
041import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
042import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
043import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
044import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
045import org.jetbrains.jet.lang.resolve.name.FqName;
046import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
047import org.jetbrains.jet.lang.resolve.name.Name;
048import org.jetbrains.jet.lang.resolve.scopes.JetScope;
049import org.jetbrains.jet.lang.types.*;
050import org.jetbrains.jet.plugin.JetFileType;
051
052import java.io.IOException;
053import java.io.InputStream;
054import java.io.InputStreamReader;
055import java.util.*;
056
057import static org.jetbrains.jet.lang.types.lang.PrimitiveType.*;
058
059public 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}