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