diff --git a/compiler/frontend/src/jet.src/README.md b/compiler/frontend/src/jet.src/README.md deleted file mode 100644 index 2aef103ac7a..00000000000 --- a/compiler/frontend/src/jet.src/README.md +++ /dev/null @@ -1,4 +0,0 @@ -These files are used only for navigation from user code in IDE. - -These files are not processed by Kotlin compiler. Compiler creates Any, Nothing, tuple and function -types on-the-fly. \ No newline at end of file diff --git a/compiler/frontend/src/jet.src/Any.jet b/compiler/frontend/src/jet/Any.jet similarity index 100% rename from compiler/frontend/src/jet.src/Any.jet rename to compiler/frontend/src/jet/Any.jet diff --git a/compiler/frontend/src/jet.src/ExtensionFunctions.jet b/compiler/frontend/src/jet/ExtensionFunctions.jet similarity index 100% rename from compiler/frontend/src/jet.src/ExtensionFunctions.jet rename to compiler/frontend/src/jet/ExtensionFunctions.jet diff --git a/compiler/frontend/src/jet.src/Functions.jet b/compiler/frontend/src/jet/Functions.jet similarity index 100% rename from compiler/frontend/src/jet.src/Functions.jet rename to compiler/frontend/src/jet/Functions.jet diff --git a/compiler/frontend/src/jet.src/Nothing.jet b/compiler/frontend/src/jet/Nothing.jet similarity index 100% rename from compiler/frontend/src/jet.src/Nothing.jet rename to compiler/frontend/src/jet/Nothing.jet diff --git a/compiler/frontend/src/jet.src/Tuples.jet b/compiler/frontend/src/jet/Tuples.jet similarity index 100% rename from compiler/frontend/src/jet.src/Tuples.jet rename to compiler/frontend/src/jet/Tuples.jet diff --git a/compiler/frontend/src/jet.src/Unit.jet b/compiler/frontend/src/jet/Unit.jet similarity index 100% rename from compiler/frontend/src/jet.src/Unit.jet rename to compiler/frontend/src/jet/Unit.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java new file mode 100644 index 00000000000..48b7a7e0270 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java @@ -0,0 +1,921 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.types.lang; + +import com.google.common.base.Predicates; +import com.google.common.collect.*; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.psi.PsiFileFactory; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.DefaultModuleConfiguration; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.jet.lang.PlatformToKotlinClassMap; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetImportDirective; +import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.ImportPath; +import org.jetbrains.jet.lang.resolve.lazy.FileBasedDeclarationProviderFactory; +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.plugin.JetFileType; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; + +import static org.jetbrains.jet.lang.types.lang.PrimitiveType.*; + +public class KotlinBuiltIns { + public static final Name UNIT_ALIAS = Name.identifier("Unit"); + public static final JetScope STUB = JetScope.EMPTY; + + private static final String BUILT_INS_PACKAGE_NAME_STRING = "jet"; + private static final Name BUILT_INS_PACKAGE_NAME = Name.identifier(BUILT_INS_PACKAGE_NAME_STRING); + public static final FqName BUILT_INS_PACKAGE_FQ_NAME = FqName.topLevel(BUILT_INS_PACKAGE_NAME); + + private static final List LIBRARY_FILES = Arrays.asList( + "jet/Library.jet", + "jet/Numbers.jet", + "jet/Ranges.jet", + "jet/Iterables.jet", + "jet/Iterators.jet", + "jet/Arrays.jet", + "jet/Enum.jet", + "jet/Collections.jet", + "jet/Any.jet", + "jet/ExtensionFunctions.jet", + "jet/Functions.jet", + "jet/Nothing.jet", + "jet/Tuples.jet", + "jet/Unit.jet" + ); + + private static final Map ALIASES = ImmutableMap.builder() + .put(new FqName("jet.Unit"), Name.identifier("Tuple0")) + .build(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private static volatile KotlinBuiltIns instance = null; + + private static volatile boolean initializing; + private static Throwable initializationFailed; + + // This method must be called at least once per application run, on any project + // before any type checking is run + public static synchronized void initialize(@NotNull Project project) { + if (instance == null) { + if (initializationFailed != null) { + throw new RuntimeException( + "builtin library initialization failed previously: " + initializationFailed, initializationFailed); + } + if (initializing) { + throw new IllegalStateException("builtin library initialization loop"); + } + initializing = true; + try { + instance = new KotlinBuiltIns(project); + instance.initialize(); + } + catch (Throwable e) { + initializationFailed = e; + throw new RuntimeException("builtin library initialization failed: " + e, e); + } + finally { + initializing = false; + } + } + } + + @NotNull // This asserts that initialize() is called before any resolution happens + public static KotlinBuiltIns getInstance() { + if (initializing) { + synchronized (KotlinBuiltIns.class) { + assert instance != null : "We are under the same lock as initializing and instance"; + return instance; + } + } + if (instance == null) { + throw new IllegalStateException("Initialize standard library first"); + } + return instance; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private final ResolveSession resolveSession; + private final ModuleDescriptor builtInsModule; + + private final ImmutableList functionClasses; + private final ImmutableSet functionClassesSet; + + private final ImmutableList extensionFunctionClasses; + private final ImmutableSet extensionFunctionClassesSet; + + @Deprecated + private final ImmutableList tupleClasses; + @Deprecated + private final ImmutableSet tupleClassesSet; + + private final EnumMap primitiveTypeToClass; + private final EnumMap primitiveTypeToArrayClass; + private final EnumMap primitiveTypeToJetType; + private final EnumMap primitiveTypeToNullableJetType; + private final EnumMap primitiveTypeToArrayJetType; + private final Map primitiveJetTypeToJetArrayType; + private final Map jetArrayTypeToPrimitiveJetType; + + private KotlinBuiltIns(@NotNull Project project) { + try { + this.builtInsModule = new ModuleDescriptor(Name.special("")); + this.resolveSession = createLazyResolveSession(project); + + this.functionClasses = computeIndexedClasses("Function", getFunctionTraitCount()); + this.functionClassesSet = ImmutableSet.copyOf(functionClasses); + this.extensionFunctionClasses = computeIndexedClasses("ExtensionFunction", getFunctionTraitCount()); + this.extensionFunctionClassesSet = ImmutableSet.copyOf(extensionFunctionClasses); + this.tupleClasses = computeIndexedClasses("Tuple", getFunctionTraitCount()); + this.tupleClassesSet = ImmutableSet.copyOf(tupleClasses); + + this.primitiveTypeToClass = new EnumMap(PrimitiveType.class); + this.primitiveTypeToJetType = new EnumMap(PrimitiveType.class); + this.primitiveTypeToNullableJetType = new EnumMap(PrimitiveType.class); + this.primitiveTypeToArrayClass = new EnumMap(PrimitiveType.class); + this.primitiveTypeToArrayJetType = new EnumMap(PrimitiveType.class); + this.primitiveJetTypeToJetArrayType = new HashMap(); + this.jetArrayTypeToPrimitiveJetType = new HashMap(); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + catch (ProcessCanceledException e) { + throw e; + } + } + + private void initialize() { + for (PrimitiveType primitive : PrimitiveType.values()) { + makePrimitive(primitive); + } + resolveSession.forceResolveAll(); + } + + @NotNull + private ResolveSession createLazyResolveSession(@NotNull Project project) throws IOException { + List files = loadResourcesAsJetFiles(project, LIBRARY_FILES); + return new ResolveSession( + project, + builtInsModule, + new SpecialModuleConfiguration(project), + new FileBasedDeclarationProviderFactory(files), + new Function() { + @Override + public Name fun(FqName name) { + return ALIASES.get(name); + } + }, + Predicates.in(Sets.newHashSet(new FqNameUnsafe("jet.Any"), new FqNameUnsafe("jet.Nothing")))); + } + + @NotNull + private List loadResourcesAsJetFiles(@NotNull Project project, @NotNull List libraryFiles) + throws IOException, ProcessCanceledException + { + List files = new LinkedList(); + for(String path : libraryFiles) { + InputStream stream = KotlinBuiltIns.class.getClassLoader().getResourceAsStream(path); + + if (stream == null) { + throw new IllegalStateException("Resource not found in classpath: " + path); + } + + //noinspection IOResourceOpenedButNotSafelyClosed + JetFile file = (JetFile) PsiFileFactory.getInstance(project).createFileFromText(path, + JetFileType.INSTANCE, FileUtil.loadTextAndClose(new InputStreamReader(stream))); + files.add(file); + } + return files; + } + + private static class SpecialModuleConfiguration implements ModuleConfiguration { + + private final Project project; + + private SpecialModuleConfiguration(@NotNull Project project) { + this.project = project; + } + + @Override + public void addDefaultImports(@NotNull Collection directives) { + for (ImportPath defaultJetImport : DefaultModuleConfiguration.DEFAULT_JET_IMPORTS) { + directives.add(JetPsiFactory.createImportDirective(project, defaultJetImport)); + } + } + + @Override + public void extendNamespaceScope(@NotNull BindingTrace trace, + @NotNull NamespaceDescriptor namespaceDescriptor, + @NotNull WritableScope namespaceMemberScope) { + // DO nothing + } + + @NotNull + @Override + public PlatformToKotlinClassMap getPlatformToKotlinClassMap() { + return PlatformToKotlinClassMap.EMPTY; + } + } + + private void makePrimitive(PrimitiveType primitiveType) { + ClassDescriptor clazz = (ClassDescriptor) getBuiltInsScope().getClassifier(primitiveType.getTypeName()); + ClassDescriptor arrayClazz = (ClassDescriptor) getBuiltInsScope().getClassifier(primitiveType.getArrayTypeName()); + JetTypeImpl type = new JetTypeImpl(clazz); + JetTypeImpl arrayType = new JetTypeImpl(arrayClazz); + + primitiveTypeToClass.put(primitiveType, clazz); + primitiveTypeToJetType.put(primitiveType, type); + primitiveTypeToNullableJetType.put(primitiveType, TypeUtils.makeNullable(type)); + primitiveTypeToArrayClass.put(primitiveType, arrayClazz); + primitiveTypeToArrayJetType.put(primitiveType, arrayType); + primitiveJetTypeToJetArrayType.put(type, arrayType); + jetArrayTypeToPrimitiveJetType.put(arrayType, type); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @NotNull + public ModuleDescriptor getBuiltInsModule() { + return builtInsModule; + } + + @NotNull + public NamespaceDescriptor getBuiltInsPackage() { + NamespaceDescriptor namespace = getBuiltInsModule().getRootNamespace().getMemberScope().getNamespace(BUILT_INS_PACKAGE_NAME); + assert namespace != null : "Built ins namespace not found: " + BUILT_INS_PACKAGE_NAME; + return namespace; + } + + @NotNull + public FqName getBuiltInsPackageFqName() { + return getBuiltInsPackage().getQualifiedName(); + } + + @NotNull + public Collection getAllBuiltInClasses() { + // TODO: used once, but incorrectly in JetShortNamesCache + return getStandardClassesScope().getAllDescriptors(); + } + + @Deprecated + @NotNull + public JetScope getStandardClassesScope() { + // TODO: this is more than standard classes + // TODO: the only usage makes no sense for lazily loaded library + return getBuiltInsScope(); + } + + @NotNull + public JetScope getBuiltInsScope() { + return getBuiltInsPackage().getMemberScope(); + } + + public boolean isStandardClass(@NotNull FqName fqName) { + // TODO: this seems to be wrong for ranges, and will certainly be wrong upon renaming jet -> kotlin + return getBuiltInsPackageFqName().equals(fqName.parent()); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // GET CLASS + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @NotNull + private ClassDescriptor getBuiltInClassByName(@NotNull String simpleName) { + ClassifierDescriptor classifier = getBuiltInsScope().getClassifier(Name.identifier(simpleName)); + assert classifier instanceof ClassDescriptor : "Must be a class descriptor " + simpleName + ", but was " + classifier; + return (ClassDescriptor) classifier; + } + + // Special + + @NotNull + public ClassDescriptor getAny() { + return getBuiltInClassByName("Any"); + } + + @NotNull + public ClassDescriptor getNothing() { + return getBuiltInClassByName("Nothing"); + } + + // Primitive + + @NotNull + public ClassDescriptor getPrimitiveClassDescriptor(@NotNull PrimitiveType type) { + return getBuiltInClassByName(type.getTypeName().getName()); + } + + @NotNull + public ClassDescriptor getByte() { + return getPrimitiveClassDescriptor(BYTE); + } + + @NotNull + public ClassDescriptor getShort() { + return getPrimitiveClassDescriptor(SHORT); + } + + @NotNull + public ClassDescriptor getInt() { + return getPrimitiveClassDescriptor(INT); + } + + @NotNull + public ClassDescriptor getLong() { + return getPrimitiveClassDescriptor(LONG); + } + + @NotNull + public ClassDescriptor getFloat() { + return getPrimitiveClassDescriptor(FLOAT); + } + + @NotNull + public ClassDescriptor getDouble() { + return getPrimitiveClassDescriptor(DOUBLE); + } + + @NotNull + public ClassDescriptor getChar() { + return getPrimitiveClassDescriptor(CHAR); + } + + @NotNull + public ClassDescriptor getBoolean() { + return getPrimitiveClassDescriptor(BOOLEAN); + } + + // Recognized + + @NotNull + public Set getIntegralRanges() { + return ImmutableSet.of( + getBuiltInClassByName("ByteRange"), + getBuiltInClassByName("ShortRange"), + getBuiltInClassByName("CharRange"), + getBuiltInClassByName("IntRange"), + getBuiltInClassByName("LongRange") + ); + } + + @NotNull + public ClassDescriptor getArray() { + return getBuiltInClassByName("Array"); + } + + @NotNull + public ClassDescriptor getPrimitiveArrayClassDescriptor(@NotNull PrimitiveType type) { + return getBuiltInClassByName(type.getArrayTypeName().getName()); + } + + @NotNull + public ClassDescriptor getNumber() { + return getBuiltInClassByName("Number"); + } + + @NotNull + public ClassDescriptor getFunction(int parameterCount) { + return getBuiltInClassByName("Function" + parameterCount); + } + + @NotNull + public ClassDescriptor getExtensionFunction(int parameterCount) { + return getBuiltInClassByName("ExtensionFunction" + parameterCount); + } + + @NotNull + public ClassDescriptor getThrowable() { + return getBuiltInClassByName("Throwable"); + } + + @NotNull + public ClassDescriptor getDataClassAnnotation() { + return getBuiltInClassByName("data"); + } + + @NotNull + public ClassDescriptor getVolatileAnnotationClass() { + return getBuiltInClassByName("volatile"); + } + + @NotNull + public ClassDescriptor getString() { + return getBuiltInClassByName("String"); + } + + @NotNull + public ClassDescriptor getCharSequence() { + return getBuiltInClassByName("CharSequence"); + } + + @NotNull + public ClassDescriptor getComparable() { + return getBuiltInClassByName("Comparable"); + } + + @NotNull + public ClassDescriptor getEnum() { + return getBuiltInClassByName("Enum"); + } + + @NotNull + public ClassDescriptor getAnnotation() { + return getBuiltInClassByName("Annotation"); + } + + @NotNull + public ClassDescriptor getIterator() { + return getBuiltInClassByName("Iterator"); + } + + @NotNull + public ClassDescriptor getIterable() { + return getBuiltInClassByName("Iterable"); + } + + @NotNull + public ClassDescriptor getMutableIterable() { + return getBuiltInClassByName("MutableIterable"); + } + + @NotNull + public ClassDescriptor getMutableIterator() { + return getBuiltInClassByName("MutableIterator"); + } + + @NotNull + public ClassDescriptor getCollection() { + return getBuiltInClassByName("Collection"); + } + + @NotNull + public ClassDescriptor getMutableCollection() { + return getBuiltInClassByName("MutableCollection"); + } + + @NotNull + public ClassDescriptor getList() { + return getBuiltInClassByName("List"); + } + + @NotNull + public ClassDescriptor getMutableList() { + return getBuiltInClassByName("MutableList"); + } + + @NotNull + public ClassDescriptor getSet() { + return getBuiltInClassByName("Set"); + } + + @NotNull + public ClassDescriptor getMutableSet() { + return getBuiltInClassByName("MutableSet"); + } + + @NotNull + public ClassDescriptor getMap() { + return getBuiltInClassByName("Map"); + } + + @NotNull + public ClassDescriptor getMutableMap() { + return getBuiltInClassByName("MutableMap"); + } + + @NotNull + public ClassDescriptor getMapEntry() { + return DescriptorUtils.getInnerClassByName(getBuiltInClassByName("Map"), "Entry"); + } + + @NotNull + public ClassDescriptor getMutableMapEntry() { + return DescriptorUtils.getInnerClassByName(getBuiltInClassByName("MutableMap"), "MutableEntry"); + } + + @NotNull + public ClassDescriptor getListIterator() { + return getBuiltInClassByName("ListIterator"); + } + + @NotNull + public ClassDescriptor getMutableListIterator() { + return getBuiltInClassByName("MutableListIterator"); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // GET TYPE + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @NotNull + private JetType getBuiltInTypeByClassName(@NotNull String classSimpleName) { + // TODO + return new JetTypeImpl(getBuiltInClassByName(classSimpleName)); + } + + // Special + + @NotNull + public JetType getNothingType() { + return getBuiltInTypeByClassName("Nothing"); + } + + @NotNull + public JetType getNullableNothingType() { + // TODO + return TypeUtils.makeNullable(getNothingType()); + } + + @NotNull + public JetType getAnyType() { + return getBuiltInTypeByClassName("Any"); + } + + @NotNull + public JetType getNullableAnyType() { + // TODO + return TypeUtils.makeNullable(getAnyType()); + } + + // Primitive + + @NotNull + public JetType getPrimitiveJetType(@NotNull PrimitiveType type) { + // TODO + return new JetTypeImpl(getPrimitiveClassDescriptor(type)); + } + + @NotNull + public JetType getNullablePrimitiveJetType(@NotNull PrimitiveType primitiveType) { + return primitiveTypeToNullableJetType.get(primitiveType); + } + + @NotNull + public JetType getByteType() { + return getPrimitiveJetType(BYTE); + } + + @NotNull + public JetType getShortType() { + return getPrimitiveJetType(SHORT); + } + + @NotNull + public JetType getIntType() { + return getPrimitiveJetType(INT); + } + + @NotNull + public JetType getLongType() { + return getPrimitiveJetType(LONG); + } + + @NotNull + public JetType getFloatType() { + return getPrimitiveJetType(FLOAT); + } + + @NotNull + public JetType getDoubleType() { + return getPrimitiveJetType(DOUBLE); + } + + @NotNull + public JetType getCharType() { + return getPrimitiveJetType(CHAR); + } + + @NotNull + public JetType getBooleanType() { + return getPrimitiveJetType(BOOLEAN); + } + + // Recognized + + @NotNull + public JetType getUnitType() { + return getBuiltInTypeByClassName("Unit"); + } + + @NotNull + public JetType getStringType() { + return getBuiltInTypeByClassName("String"); + } + + @NotNull + public JetType getArrayElementType(@NotNull JetType arrayType) { + // make non-null? + if (arrayType.getConstructor().getDeclarationDescriptor() == getArray()) { + if (arrayType.getArguments().size() != 1) { + throw new IllegalStateException(); + } + return arrayType.getArguments().get(0).getType(); + } + JetType primitiveType = jetArrayTypeToPrimitiveJetType.get(arrayType); + if (primitiveType == null) { + throw new IllegalStateException("not array: " + arrayType); + } + return primitiveType; + } + + @NotNull + public JetType getPrimitiveArrayJetType(@NotNull PrimitiveType primitiveType) { + return primitiveTypeToArrayJetType.get(primitiveType); + } + + /** + * @return null if not primitive + */ + @Nullable + public JetType getPrimitiveArrayJetTypeByPrimitiveJetType(@NotNull JetType jetType) { + return primitiveJetTypeToJetArrayType.get(jetType); + } + + @NotNull + public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) { + List types = Collections.singletonList(new TypeProjection(projectionType, argument)); + return new JetTypeImpl( + Collections.emptyList(), + getArray().getTypeConstructor(), + false, + types, + getArray().getMemberScope(types) + ); + } + + @NotNull + public JetType getArrayType(@NotNull JetType argument) { + return getArrayType(Variance.INVARIANT, argument); + } + + @NotNull + public JetType getEnumType(@NotNull JetType argument) { + Variance projectionType = Variance.INVARIANT; + List types = Collections.singletonList(new TypeProjection(projectionType, argument)); + return new JetTypeImpl( + Collections.emptyList(), + getEnum().getTypeConstructor(), + false, + types, + getEnum().getMemberScope(types) + ); + } + + @NotNull + public JetType getAnnotationType() { + return getBuiltInTypeByClassName("Annotation"); + } + + @NotNull + public JetType getFunctionType( + @NotNull List annotations, + @Nullable JetType receiverType, + @NotNull List parameterTypes, + @NotNull JetType returnType + ) { + List arguments = new ArrayList(); + if (receiverType != null) { + arguments.add(defaultProjection(receiverType)); + } + for (JetType parameterType : parameterTypes) { + arguments.add(defaultProjection(parameterType)); + } + arguments.add(defaultProjection(returnType)); + int size = parameterTypes.size(); + ClassDescriptor classDescriptor = receiverType == null ? getFunction(size) : getExtensionFunction(size); + TypeConstructor constructor = classDescriptor.getTypeConstructor(); + return new JetTypeImpl(annotations, constructor, false, arguments, classDescriptor.getMemberScope(arguments)); + } + + private TypeProjection defaultProjection(JetType returnType) { + return new TypeProjection(Variance.INVARIANT, returnType); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // IS TYPE + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public boolean isArray(@NotNull JetType type) { + return getArray().equals(type.getConstructor().getDeclarationDescriptor()); + } + + // Functions + + public int getFunctionTraitCount() { + return 23; + } + + @NotNull + private ImmutableList computeIndexedClasses(@NotNull String prefix, int count) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (int i = 0; i < count; i++) { + builder.add(getBuiltInClassByName(prefix + i)); + } + return builder.build(); + } + + public boolean isFunctionType(@NotNull JetType type) { + DeclarationDescriptor constructor = type.getConstructor().getDeclarationDescriptor(); + return functionClassesSet.contains(constructor) || extensionFunctionClassesSet.contains(constructor); + } + + @Nullable + public JetType getReceiverType(@NotNull JetType type) { + assert isFunctionType(type) : type; + if (extensionFunctionClassesSet.contains(type.getConstructor().getDeclarationDescriptor())) { + return type.getArguments().get(0).getType(); + } + return null; + } + + @NotNull + public List getValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull JetType type) { + assert isFunctionType(type); + List valueParameters = Lists.newArrayList(); + List parameterTypes = getParameterTypeProjectionsFromFunctionType(type); + for (int i = 0; i < parameterTypes.size(); i++) { + TypeProjection parameterType = parameterTypes.get(i); + ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl( + functionDescriptor, i, Collections.emptyList(), + Name.identifier("p" + (i + 1)), false, parameterType.getType(), false, null); + valueParameters.add(valueParameterDescriptor); + } + return valueParameters; + } + + @NotNull + public JetType getReturnTypeFromFunctionType(@NotNull JetType type) { + assert isFunctionType(type); + List arguments = type.getArguments(); + return arguments.get(arguments.size() - 1).getType(); + } + + @NotNull + public List getParameterTypeProjectionsFromFunctionType(@NotNull JetType type) { + assert isFunctionType(type); + List arguments = type.getArguments(); + int first = extensionFunctionClassesSet.contains(type.getConstructor().getDeclarationDescriptor()) ? 1 : 0; + int last = arguments.size() - 2; + List parameterTypes = Lists.newArrayList(); + for (int i = first; i <= last; i++) { + parameterTypes.add(arguments.get(i)); + } + return parameterTypes; + } + + // Recognized & special + + public boolean isNothing(@NotNull JetType type) { + return isNothingOrNullableNothing(type) + && !type.isNullable(); + } + + public boolean isNullableNothing(@NotNull JetType type) { + return isNothingOrNullableNothing(type) + && type.isNullable(); + } + + public boolean isNothingOrNullableNothing(@NotNull JetType type) { + return !(type instanceof NamespaceType) + && type.getConstructor() == getNothing().getTypeConstructor(); + } + + public boolean isAny(@NotNull JetType type) { + return !(type instanceof NamespaceType) && + type.getConstructor() == getAny().getTypeConstructor(); + } + + public boolean isUnit(@NotNull JetType type) { + return !(type instanceof NamespaceType) && + type.getConstructor() == getUnitType().getConstructor(); + } + + public boolean isData(@NotNull ClassDescriptor classDescriptor) { + return containsAnnotation(classDescriptor, getDataClassAnnotation()); + } + + private boolean containsAnnotation(DeclarationDescriptor descriptor, ClassDescriptor annotationClass) { + List annotations = descriptor.getOriginal().getAnnotations(); + if (annotations != null) { + for (AnnotationDescriptor annotation : annotations) { + if (annotationClass.equals(annotation.getType().getConstructor().getDeclarationDescriptor())) { + return true; + } + } + } + return false; + } + + public boolean isVolatile(@NotNull PropertyDescriptor descriptor) { + return containsAnnotation(descriptor, getVolatileAnnotationClass()); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @NotNull + public JetType getDefaultBound() { + return getNullableAnyType(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // TUPLES + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + @Deprecated + @NotNull + public List getTupleElementTypes(@NotNull JetType type) { + assert isTupleType(type); + List result = Lists.newArrayList(); + for (TypeProjection typeProjection : type.getArguments()) { + result.add(typeProjection.getType()); + } + return result; + } + + @NotNull + @Deprecated + public ClassDescriptor getTuple(int size) { + return getBuiltInClassByName("Tuple" + size); + } + + @Deprecated + public boolean isTupleType(@NotNull JetType type) { + return tupleClassesSet.contains(type.getConstructor().getDeclarationDescriptor()); + } + + @NotNull + @Deprecated + public JetType getTupleType(@NotNull List arguments) { + return getTupleType(Collections.emptyList(), arguments); + } + + @NotNull + @Deprecated + public JetType getTupleType(@NotNull JetType... arguments) { + return getTupleType(Collections.emptyList(), Arrays.asList(arguments)); + } + + @Deprecated + private JetType getTupleType(List annotations, List arguments) { + if (annotations.isEmpty() && arguments.isEmpty()) { + return getUnitType(); + } + ClassDescriptor tuple = getTuple(arguments.size()); + List typeArguments = toProjections(arguments); + return new JetTypeImpl(annotations, tuple.getTypeConstructor(), false, typeArguments, tuple.getMemberScope(typeArguments)); + } + + private List toProjections(List arguments) { + List result = new ArrayList(); + for (JetType argument : arguments) { + result.add(new TypeProjection(Variance.OUT_VARIANCE, argument)); + } + return result; + } +}