JetStandardLibrary factored out of JetStandardClasses. JetSemanticServices added

This commit is contained in:
Andrey Breslav
2011-02-28 20:25:40 +03:00
parent 33bee035da
commit 2811094d32
21 changed files with 805 additions and 909 deletions
@@ -4,6 +4,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -18,10 +19,12 @@ import java.util.List;
public class FunctionCodegen {
private final ClassVisitor v;
private final BindingContext bindingContext;
private final JetStandardLibrary standardLibrary;
public FunctionCodegen(ClassVisitor v, BindingContext bindingContext) {
public FunctionCodegen(ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.v = v;
this.bindingContext = bindingContext;
this.standardLibrary = standardLibrary;
}
public void gen(JetFunction f, JetNamespace owner) {
@@ -38,7 +41,7 @@ public class FunctionCodegen {
if (type.equals(JetStandardClasses.getUnitType())) {
returnType = Type.VOID_TYPE;
}
else if (type.equals(JetStandardClasses.getIntType())) {
else if (type.equals(standardLibrary.getIntType())) {
returnType = Type.getType(Integer.class);
}
else {
@@ -1,12 +1,12 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
@@ -19,12 +19,12 @@ public class NamespaceCodegen {
public NamespaceCodegen() {
}
public void generate(JetNamespace namespace, ClassVisitor v) {
public void generate(JetNamespace namespace, ClassVisitor v, JetSemanticServices semanticServices) {
List<JetDeclaration> declarations = namespace.getDeclarations();
BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations);
BindingContext bindingContext = new TopDownAnalyzer(semanticServices).process(semanticServices.getStandardLibrary().getLibraryScope(), declarations);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, bindingContext);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, semanticServices.getStandardLibrary(), bindingContext);
v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC,
getJVMClassName(namespace),
@@ -0,0 +1,37 @@
package org.jetbrains.jet.lang;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.types.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
/**
* @author abreslav
*/
public class JetSemanticServices {
private final JetStandardLibrary standardLibrary;
private final JetTypeInferrer typeInferrer;
private final ClassDescriptorResolver classDescriptorResolver;
public JetSemanticServices(JetStandardLibrary standardLibrary) {
this.standardLibrary = standardLibrary;
this.typeInferrer = new JetTypeInferrer(BindingTrace.DUMMY, this);
this.classDescriptorResolver = new ClassDescriptorResolver(this);
}
public JetStandardLibrary getStandardLibrary() {
return standardLibrary;
}
public JetTypeInferrer getTypeInferrer() {
return typeInferrer;
}
public ClassDescriptorResolver getClassDescriptorResolver() {
return classDescriptorResolver;
}
public JetTypeInferrer getTypeInferrer(BindingTrace trace) {
return new JetTypeInferrer(trace, this);
}
}
@@ -5,9 +5,6 @@ import com.intellij.lang.annotation.Annotator;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.FileContentsResolver;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
/**
* @author abreslav
@@ -18,7 +15,7 @@ public class JetPsiChecker implements Annotator {
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (element instanceof JetFile) {
JetFile file = (JetFile) element;
JetScope jetScope = FileContentsResolver.INSTANCE.resolveFileContents(JetStandardClasses.STANDARD_CLASSES, file);
// JetScope jetScope = FileContentsResolver.INSTANCE.resolveFileContents(JetStandardClasses.STANDARD_CLASSES, file);
}
}
}
@@ -14,4 +14,6 @@ public interface BindingContext {
Type getExpressionType(JetExpression expression);
DeclarationDescriptor resolve(JetReferenceExpression referenceExpression);
JetScope getTopLevelScope();
}
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
@@ -12,9 +13,12 @@ import java.util.*;
* @author abreslav
*/
public class ClassDescriptorResolver {
public static final ClassDescriptorResolver INSTANCE = new ClassDescriptorResolver();
private ClassDescriptorResolver() {}
private final JetSemanticServices semanticServices;
public ClassDescriptorResolver(JetSemanticServices semanticServices) {
this.semanticServices = semanticServices;
}
@Nullable
public ClassDescriptor resolveClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement) {
@@ -126,7 +130,7 @@ public class ClassDescriptorResolver {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null : "No type, no body"; // TODO
// TODO : Recursion possible
returnType = JetTypeChecker.INSTANCE.getType(parameterScope, bodyExpression, function.hasBlockBody());
returnType = semanticServices.getTypeInferrer().getType(parameterScope, bodyExpression, function.hasBlockBody());
}
return new FunctionDescriptorImpl(
@@ -213,7 +217,7 @@ public class ClassDescriptorResolver {
TypeResolver.INSTANCE.resolveType(scope, parameter.getTypeReference()));
}
public static PropertyDescriptor resolvePropertyDescriptor(@NotNull JetScope scope, JetProperty property) {
public PropertyDescriptor resolvePropertyDescriptor(@NotNull JetScope scope, JetProperty property) {
// TODO : receiver?
JetTypeReference propertyTypeRef = property.getPropertyTypeRef();
@@ -222,7 +226,7 @@ public class ClassDescriptorResolver {
JetExpression initializer = property.getInitializer();
assert initializer != null;
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
type = JetTypeChecker.INSTANCE.getType(scope, initializer, false);
type = semanticServices.getTypeInferrer().getType(scope, initializer, false);
} else {
type = TypeResolver.INSTANCE.resolveType(scope, propertyTypeRef);
}
@@ -1,20 +0,0 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
/**
* @author abreslav
*/
public class FileContentsResolver {
public static final FileContentsResolver INSTANCE = new FileContentsResolver();
private FileContentsResolver() {}
@NotNull
public JetScope resolveFileContents(@NotNull JetScope scope, @NotNull JetFile file) {
return new LazyScope(scope, file.getRootNamespace().getDeclarations());
}
}
@@ -1,87 +0,0 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class LazyClassDescriptor implements ClassDescriptor {
private final JetScope outerScope;
private JetClass declaration;
private TypeConstructor typeConstructor;
private LazyScope unsubstitutedMemberScope;
private List<Attribute> attributes;
private WritableScope parameterScope;
private List<TypeParameterDescriptor> typeParameterDescriptors;
public LazyClassDescriptor(@NotNull JetScope scope, @NotNull JetClass klass) {
this.declaration = klass;
this.outerScope = scope;
}
@Override
public List<Attribute> getAttributes() {
if (attributes == null) {
attributes = AttributeResolver.INSTANCE.resolveAttributes(declaration.getModifierList());
}
return attributes;
}
@Override
public String getName() {
return declaration.getName();
}
@NotNull
@Override
public TypeConstructor getTypeConstructor() {
if (typeConstructor == null) {
List<TypeParameterDescriptor> typeParameters = getTypeParameters();
List<JetDelegationSpecifier> delegationSpecifiers = declaration.getDelegationSpecifiers();
// TODO : assuming that the hierarchy is acyclic
// TODO : cannot inherit from an inner class
Collection<? extends Type> superclasses = delegationSpecifiers.isEmpty()
? Collections.singleton(JetStandardClasses.getAnyType())
: ClassDescriptorResolver.resolveTypes(getTypeParameterScope(), delegationSpecifiers);
boolean open = declaration.hasModifier(JetTokens.OPEN_KEYWORD);
typeConstructor = new TypeConstructor(getAttributes(), !open, getName(), typeParameters, superclasses);
}
return typeConstructor;
}
public WritableScope getTypeParameterScope() {
getTypeParameters();
return parameterScope;
}
private List<TypeParameterDescriptor> getTypeParameters() {
if (parameterScope == null) {
parameterScope = new WritableScope(outerScope);
typeParameterDescriptors = ClassDescriptorResolver.INSTANCE.resolveTypeParameters(parameterScope, declaration.getTypeParameters());
}
return typeParameterDescriptors;
}
@Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
if (unsubstitutedMemberScope == null) {
unsubstitutedMemberScope = new LazyScope(getTypeParameterScope(), declaration.getDeclarations());
}
List<TypeParameterDescriptor> parameters = getTypeConstructor().getParameters();
if (parameters.isEmpty()) {
return unsubstitutedMemberScope;
}
Map<TypeConstructor,TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(parameters, typeArguments);
return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext);
}
}
@@ -1,85 +0,0 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetVisitor;
import org.jetbrains.jet.lang.types.ClassDescriptor;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.FunctionGroup;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class LazyScope extends JetScopeAdapter {
private final List<JetDeclaration> declarations;
private Map<String, ClassDescriptor> classDescriptors;
private Map<String, WritableFunctionGroup> functionGroups;
public LazyScope(JetScope scope, List<JetDeclaration> declarations) {
super(scope);
this.declarations = declarations;
}
private Map<String, ClassDescriptor> getClassDescriptors() {
if (classDescriptors == null) {
classDescriptors = new HashMap<String, ClassDescriptor>();
for (JetDeclaration declaration : declarations) {
declaration.accept(new JetVisitor() {
@Override
public void visitClass(JetClass klass) {
classDescriptors.put(klass.getName(), new LazyClassDescriptor(LazyScope.this, klass));
}
});
}
}
return classDescriptors;
}
@Override
public ClassDescriptor getClass(String name) {
ClassDescriptor classDescriptor = getClassDescriptors().get(name);
if (classDescriptor != null) {
return classDescriptor;
}
return super.getClass(name);
}
private Map<String, WritableFunctionGroup> getFunctionGroups() {
if (functionGroups == null) {
functionGroups = new HashMap<String, WritableFunctionGroup>();
for (JetDeclaration declaration : declarations) {
declaration.accept(new JetVisitor() {
@Override
public void visitFunction(JetFunction function) {
FunctionDescriptor functionDescriptor = ClassDescriptorResolver.INSTANCE.resolveFunctionDescriptor(LazyScope.this, function);
String name = functionDescriptor.getName();
WritableFunctionGroup group = functionGroups.get(name);
if (group == null) {
group = new WritableFunctionGroup(name);
functionGroups.put(name, group);
}
group.addFunction(functionDescriptor);
}
});
}
}
return functionGroups;
}
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
WritableFunctionGroup group = getFunctionGroups().get(name);
if (!group.isEmpty()) {
return group;
}
return super.getFunctionGroup(name);
}
}
@@ -13,6 +13,7 @@ import java.util.Map;
* @author abreslav
*/
public class OverloadResolver {
public static final OverloadResolver INSTANCE = new OverloadResolver();
private OverloadResolver() {}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
@@ -11,15 +12,21 @@ import java.util.*;
*/
public class TopDownAnalyzer {
private final WritableBindingContext context = new WritableBindingContext();
private final Map<JetClass, MutableClassDescriptor> classes = new LinkedHashMap<JetClass, MutableClassDescriptor>();
private final Map<JetFunction, FunctionDescriptor> functions = new HashMap<JetFunction, FunctionDescriptor>();
private Map<JetProperty, PropertyDescriptor> properties = new HashMap<JetProperty, PropertyDescriptor>();
private final Map<JetDeclaration, WritableScope> declaringScopes = new HashMap<JetDeclaration, WritableScope>();
private Map<JetExpression, Type> expressionTypes = new HashMap<JetExpression, Type>();
private Map<JetReferenceExpression,DeclarationDescriptor> resolutionResults = new HashMap<JetReferenceExpression, DeclarationDescriptor>();
private final JetSemanticServices semanticServices;
public TopDownAnalyzer(JetSemanticServices semanticServices) {
this.semanticServices = semanticServices;
}
public BindingContext process(@NotNull JetScope outerScope, @NotNull List<JetDeclaration> declarations) {
WritableScope toplevelScope = new WritableScope(outerScope);
final WritableScope toplevelScope = new WritableScope(outerScope);
collectTypeDeclarators(toplevelScope, declarations);
resolveTypeDeclarations();
collectBehaviorDeclarators(toplevelScope, declarations);
@@ -43,7 +50,7 @@ public class TopDownAnalyzer {
@Override
public PropertyDescriptor getPropertyDescriptor(JetProperty declaration) {
throw new UnsupportedOperationException(); // TODO
return properties.get(declaration);
}
@Override
@@ -55,6 +62,11 @@ public class TopDownAnalyzer {
public DeclarationDescriptor resolve(JetReferenceExpression referenceExpression) {
return resolutionResults.get(referenceExpression);
}
@Override
public JetScope getTopLevelScope() {
return toplevelScope;
}
};
}
@@ -107,7 +119,7 @@ public class TopDownAnalyzer {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass jetClass = entry.getKey();
MutableClassDescriptor descriptor = entry.getValue();
ClassDescriptorResolver.INSTANCE.resolveMutableClassDescriptor(declaringScopes.get(jetClass), jetClass, descriptor);
semanticServices.getClassDescriptorResolver().resolveMutableClassDescriptor(declaringScopes.get(jetClass), jetClass, descriptor);
}
}
@@ -153,13 +165,16 @@ public class TopDownAnalyzer {
private void processFunction(@NotNull WritableScope declaringScope, JetFunction function) {
declaringScopes.put(function, declaringScope);
FunctionDescriptor descriptor = ClassDescriptorResolver.INSTANCE.resolveFunctionDescriptor(declaringScope, function);
FunctionDescriptor descriptor = semanticServices.getClassDescriptorResolver().resolveFunctionDescriptor(declaringScope, function);
declaringScope.addFunctionDescriptor(descriptor);
functions.put(function, descriptor);
}
private void processProperty(JetScope declaringScope, JetProperty property) {
throw new UnsupportedOperationException(); // TODO
private void processProperty(WritableScope declaringScope, JetProperty property) {
declaringScopes.put(property, declaringScope);
PropertyDescriptor descriptor = semanticServices.getClassDescriptorResolver().resolvePropertyDescriptor(declaringScope, property);
declaringScope.addPropertyDescriptor(descriptor);
properties.put(property, descriptor);
}
private void processClassObject(JetClassObject classObject) {
@@ -184,12 +199,15 @@ public class TopDownAnalyzer {
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
}
resolveExpression(parameterScope, function.getBodyExpression(), true);
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
resolveExpression(parameterScope, bodyExpression, true);
}
}
}
private void resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock) {
new JetTypeChecker(new TypeCheckerTrace() {
semanticServices.getTypeInferrer(new BindingTrace() {
@Override
public void recordExpressionType(JetExpression expression, Type type) {
expressionTypes.put(expression, type);
@@ -1,39 +0,0 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
/**
* @author abreslav
*/
public class WritableBindingContext implements BindingContext {
@Override
public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public ClassDescriptor getClassDescriptor(JetClass declaration) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public FunctionDescriptor getFunctionDescriptor(JetFunction declaration) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public PropertyDescriptor getPropertyDescriptor(JetProperty declaration) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public Type getExpressionType(JetExpression expression) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public DeclarationDescriptor resolve(JetReferenceExpression referenceExpression) {
throw new UnsupportedOperationException(); // TODO
}
}
@@ -6,8 +6,8 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
/**
* @author abreslav
*/
public interface TypeCheckerTrace {
TypeCheckerTrace DUMMY = new TypeCheckerTrace() {
public interface BindingTrace {
BindingTrace DUMMY = new BindingTrace() {
@Override
public void recordExpressionType(JetExpression expression, Type type) {
}
@@ -1,20 +1,10 @@
package org.jetbrains.jet.lang.types;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiFileFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetFileType;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.FileContentsResolver;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.WritableScope;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
@@ -151,84 +141,18 @@ public class JetStandardClasses {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final JetScope PREDEFINED_SCOPE;
static {
WritableScope writableScope = new WritableScope(JetScope.EMPTY);
PREDEFINED_SCOPE = writableScope;
writableScope.addClassDescriptor(ANY);
writableScope.addClassDescriptor(NOTHING_CLASS);
for (ClassDescriptor classDescriptor : TUPLE) {
writableScope.addClassDescriptor(classDescriptor);
}
writableScope.addClassAlias("Unit", getTuple(0));
for (ClassDescriptor classDescriptor : FUNCTION) {
writableScope.addClassDescriptor(classDescriptor);
}
for (ClassDescriptor classDescriptor : RECEIVER_FUNCTION) {
writableScope.addClassDescriptor(classDescriptor);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final JetScope LIBRARY_SCOPE;
static {
// TODO : review
Project project = ProjectManager.getInstance().getDefaultProject();
InputStream stream = JetStandardClasses.class.getClassLoader().getResourceAsStream("jet/lang/Library.jet");
try {
//noinspection IOResourceOpenedButNotSafelyClosed
JetFile file = (JetFile) PsiFileFactory.getInstance(project).createFileFromText("Library.jet",
JetFileType.INSTANCE, FileUtil.loadTextAndClose(new InputStreamReader(stream)));
LIBRARY_SCOPE = FileContentsResolver.INSTANCE.resolveFileContents(PREDEFINED_SCOPE, file);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
private static final ClassDescriptor BYTE = LIBRARY_SCOPE.getClass("Byte");
@NotNull
private static final ClassDescriptor CHAR = LIBRARY_SCOPE.getClass("Char");
@NotNull
private static final ClassDescriptor SHORT = LIBRARY_SCOPE.getClass("Short");
@NotNull
private static final ClassDescriptor INT = LIBRARY_SCOPE.getClass("Int");
@NotNull
private static final ClassDescriptor LONG = LIBRARY_SCOPE.getClass("Long");
@NotNull
private static final ClassDescriptor FLOAT = LIBRARY_SCOPE.getClass("Float");
@NotNull
private static final ClassDescriptor DOUBLE = LIBRARY_SCOPE.getClass("Double");
@NotNull
private static final ClassDescriptor BOOLEAN = LIBRARY_SCOPE.getClass("Boolean");
@NotNull
private static final ClassDescriptor STRING = LIBRARY_SCOPE.getClass("String");
private static final Type BYTE_TYPE = new TypeImpl(getByte());
private static final Type CHAR_TYPE = new TypeImpl(getChar());
private static final Type SHORT_TYPE = new TypeImpl(getShort());
private static final Type INT_TYPE = new TypeImpl(getInt());
private static final Type LONG_TYPE = new TypeImpl(getLong());
private static final Type FLOAT_TYPE = new TypeImpl(getFloat());
private static final Type DOUBLE_TYPE = new TypeImpl(getDouble());
private static final Type BOOLEAN_TYPE = new TypeImpl(getBoolean());
private static final Type STRING_TYPE = new TypeImpl(getString());
private static final Type UNIT_TYPE = new TypeImpl(getTuple(0));
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public static final JetScope STANDARD_CLASSES;
/*package*/ static final JetScope STANDARD_CLASSES;
static {
WritableScope writableScope = new WritableScope(LIBRARY_SCOPE);
WritableScope writableScope = new WritableScope(JetScope.EMPTY);
STANDARD_CLASSES = writableScope;
writableScope.addClassAlias("Unit", getTuple(0));
Field[] declaredFields = JetStandardClasses.class.getDeclaredFields();
for (Field field : declaredFields) {
if ((field.getModifiers() & Modifier.STATIC) == 0) {
@@ -271,51 +195,6 @@ public class JetStandardClasses {
return NULLABLE_ANY_TYPE;
}
@NotNull
public static ClassDescriptor getByte() {
return BYTE;
}
@NotNull
public static ClassDescriptor getChar() {
return CHAR;
}
@NotNull
public static ClassDescriptor getShort() {
return SHORT;
}
@NotNull
public static ClassDescriptor getInt() {
return INT;
}
@NotNull
public static ClassDescriptor getLong() {
return LONG;
}
@NotNull
public static ClassDescriptor getFloat() {
return FLOAT;
}
@NotNull
public static ClassDescriptor getDouble() {
return DOUBLE;
}
@NotNull
public static ClassDescriptor getBoolean() {
return BOOLEAN;
}
@NotNull
public static ClassDescriptor getString() {
return STRING;
}
@NotNull
public static ClassDescriptor getNothing() {
return NOTHING_CLASS;
@@ -336,42 +215,6 @@ public class JetStandardClasses {
return RECEIVER_FUNCTION[parameterCount];
}
public static Type getIntType() {
return INT_TYPE;
}
public static Type getLongType() {
return LONG_TYPE;
}
public static Type getDoubleType() {
return DOUBLE_TYPE;
}
public static Type getFloatType() {
return FLOAT_TYPE;
}
public static Type getCharType() {
return CHAR_TYPE;
}
public static Type getBooleanType() {
return BOOLEAN_TYPE;
}
public static Type getStringType() {
return STRING_TYPE;
}
public static Type getByteType() {
return BYTE_TYPE;
}
public static Type getShortType() {
return SHORT_TYPE;
}
public static Type getUnitType() {
return UNIT_TYPE;
}
@@ -0,0 +1,166 @@
package org.jetbrains.jet.lang.types;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiFileFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetFileType;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* @author abreslav
*/
public class JetStandardLibrary {
private final JetScope libraryScope;
private final ClassDescriptor byteClass;
private final ClassDescriptor charClass;
private final ClassDescriptor shortClass;
private final ClassDescriptor intClass;
private final ClassDescriptor longClass;
private final ClassDescriptor floatClass;
private final ClassDescriptor doubleClass;
private final ClassDescriptor booleanClass;
private final ClassDescriptor stringClass;
private final Type byteType;
private final Type charType;
private final Type shortType;
private final Type intType;
private final Type longType;
private final Type floatType;
private final Type doubleType;
private final Type booleanType;
private final Type stringType;
public JetStandardLibrary(@NotNull Project project) {
// TODO : review
InputStream stream = JetStandardClasses.class.getClassLoader().getResourceAsStream("jet/lang/Library.jet");
try {
//noinspection IOResourceOpenedButNotSafelyClosed
JetFile file = (JetFile) PsiFileFactory.getInstance(project).createFileFromText("Library.jet",
JetFileType.INSTANCE, FileUtil.loadTextAndClose(new InputStreamReader(stream)));
JetSemanticServices bootstrappingSemanticServices = new JetSemanticServices(this);
TopDownAnalyzer bootstrappingTDA = new TopDownAnalyzer(bootstrappingSemanticServices);
BindingContext bindingContext = bootstrappingTDA.process(JetStandardClasses.STANDARD_CLASSES, file.getRootNamespace().getDeclarations());
this.libraryScope = bindingContext.getTopLevelScope();
this.byteClass = libraryScope.getClass("Byte");
this.charClass = libraryScope.getClass("Char");
this.shortClass = libraryScope.getClass("Short");
this.intClass = libraryScope.getClass("Int");
this.longClass = libraryScope.getClass("Long");
this.floatClass = libraryScope.getClass("Float");
this.doubleClass = libraryScope.getClass("Double");
this.booleanClass = libraryScope.getClass("Boolean");
this.stringClass = libraryScope.getClass("String");
this.byteType = new TypeImpl(getByte());
this.charType = new TypeImpl(getChar());
this.shortType = new TypeImpl(getShort());
this.intType = new TypeImpl(getInt());
this.longType = new TypeImpl(getLong());
this.floatType = new TypeImpl(getFloat());
this.doubleType = new TypeImpl(getDouble());
this.booleanType = new TypeImpl(getBoolean());
this.stringType = new TypeImpl(getString());
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public JetScope getLibraryScope() {
return libraryScope;
}
@NotNull
public ClassDescriptor getByte() {
return byteClass;
}
@NotNull
public ClassDescriptor getChar() {
return charClass;
}
@NotNull
public ClassDescriptor getShort() {
return shortClass;
}
@NotNull
public ClassDescriptor getInt() {
return intClass;
}
@NotNull
public ClassDescriptor getLong() {
return longClass;
}
@NotNull
public ClassDescriptor getFloat() {
return floatClass;
}
@NotNull
public ClassDescriptor getDouble() {
return doubleClass;
}
@NotNull
public ClassDescriptor getBoolean() {
return booleanClass;
}
@NotNull
public ClassDescriptor getString() {
return stringClass;
}
public Type getIntType() {
return intType;
}
public Type getLongType() {
return longType;
}
public Type getDoubleType() {
return doubleType;
}
public Type getFloatType() {
return floatType;
}
public Type getCharType() {
return charType;
}
public Type getBooleanType() {
return booleanType;
}
public Type getStringType() {
return stringType;
}
public Type getByteType() {
return byteType;
}
public Type getShortType() {
return shortType;
}
}
@@ -1,12 +1,7 @@
package org.jetbrains.jet.lang.types;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.*;
@@ -14,429 +9,10 @@ import java.util.*;
* @author abreslav
*/
public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker(TypeCheckerTrace.DUMMY);
private final TypeCheckerTrace trace;
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
public JetTypeChecker(TypeCheckerTrace trace) {
this.trace = trace;
}
/*
: "new" constructorInvocation
: objectLiteral
: SimpleName
: "typeof" "(" expression ")"
: functionLiteral
: declaration
: "namespace" // for the root namespace
*/
public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
final Type[] result = new Type[1];
expression.accept(new JetVisitor() {
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
// TODO : other members
// TODO : type substitutions???
PropertyDescriptor property = scope.getProperty(expression.getReferencedName());
trace.recordResolutionResult(expression, property);
if (property != null) {
result[0] = property.getType();
}
}
@Override
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
if (preferBlock && !expression.hasParameterSpecification()) {
result[0] = getBlockReturnedType(scope, expression.getBody());
return;
}
JetTypeReference returnTypeRef = expression.getReturnTypeRef();
JetTypeReference receiverTypeRef = expression.getReceiverTypeRef();
final Type receiverType;
if (receiverTypeRef != null) {
receiverType = TypeResolver.INSTANCE.resolveType(scope, receiverTypeRef);
} else {
receiverType = scope.getThisType();
}
List<JetElement> body = expression.getBody();
final Map<String, PropertyDescriptor> parameterDescriptors = new HashMap<String, PropertyDescriptor>();
List<Type> parameterTypes = new ArrayList<Type>();
for (JetParameter parameter : expression.getParameters()) {
JetTypeReference typeReference = parameter.getTypeReference();
if (typeReference == null) {
throw new UnsupportedOperationException("Type inference for parameters is not implemented yet");
}
PropertyDescriptor propertyDescriptor = ClassDescriptorResolver.INSTANCE.resolvePropertyDescriptor(scope, parameter);
parameterDescriptors.put(parameter.getName(), propertyDescriptor);
parameterTypes.add(propertyDescriptor.getType());
}
Type returnType;
if (returnTypeRef != null) {
returnType = TypeResolver.INSTANCE.resolveType(scope, returnTypeRef);
} else {
WritableScope writableScope = new WritableScope(scope);
for (PropertyDescriptor propertyDescriptor : parameterDescriptors.values()) {
writableScope.addPropertyDescriptor(propertyDescriptor);
}
writableScope.setThisType(receiverType);
returnType = getBlockReturnedType(writableScope, body);
}
result[0] = JetStandardClasses.getFunctionType(null, receiverTypeRef == null ? null : receiverType, parameterTypes, returnType);
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
result[0] = getType(scope, expression.getExpression(), false);
}
@Override
public void visitConstantExpression(JetConstantExpression expression) {
IElementType elementType = expression.getNode().getElementType();
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
result[0] = JetStandardClasses.getIntType();
} else if (elementType == JetNodeTypes.LONG_CONSTANT) {
result[0] = JetStandardClasses.getLongType();
} else if (elementType == JetNodeTypes.FLOAT_CONSTANT) {
String text = expression.getText();
assert text.length() > 0;
char lastChar = text.charAt(text.length() - 1);
if (lastChar == 'f' || lastChar == 'F') {
result[0] = JetStandardClasses.getFloatType();
} else {
result[0] = JetStandardClasses.getDoubleType();
}
} else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) {
result[0] = JetStandardClasses.getBooleanType();
} else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) {
result[0] = JetStandardClasses.getCharType();
} else if (elementType == JetNodeTypes.STRING_CONSTANT) {
result[0] = JetStandardClasses.getStringType();
} else if (elementType == JetNodeTypes.NULL) {
result[0] = JetStandardClasses.getNullableNothingType();
} else {
throw new IllegalArgumentException("Unsupported constant: " + expression);
}
}
@Override
public void visitThrowExpression(JetThrowExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitReturnExpression(JetReturnExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitBreakExpression(JetBreakExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitContinueExpression(JetContinueExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitTypeofExpression(JetTypeofExpression expression) {
throw new UnsupportedOperationException("Return some reflection interface"); // TODO
}
@Override
public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
if (expression.getOperationSign() == JetTokens.COLON) {
Type actualType = getType(scope, expression.getLeft(), false);
Type expectedType = TypeResolver.INSTANCE.resolveType(scope, expression.getRight());
if (isSubtypeOf(actualType, expectedType)) {
result[0] = expectedType;
return;
} else {
// TODO
throw new UnsupportedOperationException("Type mismatch: expected " + expectedType + " but found " + actualType);
}
}
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitIfExpression(JetIfExpression expression) {
// TODO : check condition type
// TODO : change types according to is and nullability checks
JetExpression elseBranch = expression.getElse();
if (elseBranch == null) {
// TODO : type-check the branch
result[0] = JetStandardClasses.getUnitType();
} else {
Type thenType = getType(scope, expression.getThen(), true);
Type elseType = getType(scope, elseBranch, true);
result[0] = commonSupertype(Arrays.asList(thenType, elseType));
}
}
@Override
public void visitWhenExpression(JetWhenExpression expression) {
// TODO :change scope according to the bound value in the when header
List<Type> expressions = new ArrayList<Type>();
collectAllReturnTypes(expression, scope, expressions);
result[0] = commonSupertype(expressions);
}
@Override
public void visitTryExpression(JetTryExpression expression) {
JetExpression tryBlock = expression.getTryBlock();
List<JetCatchClause> catchClauses = expression.getCatchClauses();
JetFinallySection finallyBlock = expression.getFinallyBlock();
List<Type> types = new ArrayList<Type>();
if (finallyBlock == null) {
for (JetCatchClause catchClause : catchClauses) {
// TODO: change scope here
types.add(getType(scope, catchClause.getCatchBody(), true));
}
} else {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
}
types.add(getType(scope, tryBlock, true));
result[0] = commonSupertype(types);
}
@Override
public void visitTupleExpression(JetTupleExpression expression) {
List<JetExpression> entries = expression.getEntries();
List<Type> types = new ArrayList<Type>();
for (JetExpression entry : entries) {
types.add(getType(scope, entry, false));
}
// TODO : labels
result[0] = JetStandardClasses.getTupleType(types);
}
@Override
public void visitThisExpression(JetThisExpression expression) {
// TODO : qualified this, e.g. Foo.this<Bar>
Type thisType = scope.getThisType();
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
// This cast must be safe (assuming the PSI doesn't contain errors)
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = TypeResolver.INSTANCE.resolveClass(scope, typeElement);
Collection<? extends Type> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.getSubstitutionContext(thisType);
for (Type declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result[0] = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break;
}
}
assert result[0] != null;
} else {
result[0] = thisType;
}
}
@Override
public void visitBlockExpression(JetBlockExpression expression) {
result[0] = getBlockReturnedType(scope, expression.getStatements());
}
@Override
public void visitLoopExpression(JetLoopExpression expression) {
result[0] = JetStandardClasses.getUnitType();
}
@Override
public void visitNewExpression(JetNewExpression expression) {
// TODO : type argument inference
JetTypeReference typeReference = expression.getTypeReference();
result[0] = TypeResolver.INSTANCE.resolveType(scope, typeReference);
}
@Override
public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) {
// TODO : functions
JetExpression receiverExpression = expression.getReceiverExpression();
JetExpression selectorExpression = expression.getSelectorExpression();
Type receiverType = getType(scope, receiverExpression, false);
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType);
result[0] = getType(compositeScope, selectorExpression, false);
}
@Override
public void visitCallExpression(JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression();
// 1) ends with a name -> (scope, name) to look up
// 2) ends with something else -> just check types
// TODO : check somewhere that these are NOT projections
List<JetTypeProjection> typeArguments = expression.getTypeArguments();
List<JetArgument> valueArguments = expression.getValueArguments();
boolean someNamed = false;
for (JetArgument argument : valueArguments) {
if (argument.isNamed()) {
someNamed = true;
break;
}
}
List<JetExpression> functionLiteralArguments = expression.getFunctionLiteralArguments();
// JetExpression functionLiteralArgument = functionLiteralArguments.isEmpty() ? null : functionLiteralArguments.get(0);
// TODO : must be a check
assert functionLiteralArguments.size() <= 1;
OverloadDomain overloadDomain = getOverloadDomain(scope, calleeExpression);
if (someNamed) {
// TODO : check that all are named
throw new UnsupportedOperationException(); // TODO
// result[0] = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument);
} else {
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
for (JetArgument argument : valueArguments) {
positionedValueArguments.add(argument.getArgumentExpression());
}
positionedValueArguments.addAll(functionLiteralArguments);
List<Type> types = new ArrayList<Type>();
for (JetTypeProjection projection : typeArguments) {
// TODO : check that there's no projection
types.add(TypeResolver.INSTANCE.resolveType(scope, projection.getTypeReference()));
}
List<Type> valueArgumentTypes = new ArrayList<Type>();
for (JetExpression valueArgument : positionedValueArguments) {
valueArgumentTypes.add(getType(scope, valueArgument, false));
}
FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes);
if (functionDescriptor != null) {
result[0] = functionDescriptor.getUnsubstitutedReturnType();
}
}
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem);
}
});
trace.recordExpressionType(expression, result[0]);
return result[0];
}
private OverloadDomain getOverloadDomain(final JetScope scope, JetExpression calleeExpression) {
final OverloadDomain[] result = new OverloadDomain[1];
final JetReferenceExpression[] reference = new JetReferenceExpression[1];
calleeExpression.accept(new JetVisitor() {
@Override
public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) {
// a#b -- create a domain for all overloads of b in a
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitPredicateExpression(JetPredicateExpression expression) {
// overload lookup for checking, but the type is receiver's type + nullable
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitQualifiedExpression(JetQualifiedExpression expression) {
// . or ?.
JetExpression selectorExpression = expression.getSelectorExpression();
if (selectorExpression instanceof JetReferenceExpression) {
JetReferenceExpression referenceExpression = (JetReferenceExpression) selectorExpression;
Type receiverType = getType(scope, expression.getReceiverExpression(), false);
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression;
} else {
throw new UnsupportedOperationException(); // TODO
}
}
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
// a -- create a hierarchical lookup domain for this.a
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName());
reference[0] = expression;
}
@Override
public void visitExpression(JetExpression expression) {
// <e> create a dummy domain for the type of e
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem);
}
});
return new OverloadDomain() {
@Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType);
trace.recordResolutionResult(reference[0], descriptor);
return descriptor;
}
@Override
public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
trace.recordResolutionResult(reference[0], descriptor);
return descriptor;
}
};
}
private Type getBlockReturnedType(@NotNull JetScope outerScope, List<JetElement> block) {
if (block.isEmpty()) {
return JetStandardClasses.getUnitType();
} else {
WritableScope scope = new WritableScope(outerScope);
for (JetElement statement : block) {
// TODO: consider other declarations
if (statement instanceof JetProperty) {
JetProperty property = (JetProperty) statement;
scope.addPropertyDescriptor(ClassDescriptorResolver.resolvePropertyDescriptor(scope, property));
}
}
JetElement lastElement = block.get(block.size() - 1);
if (lastElement instanceof JetExpression) {
JetExpression expression = (JetExpression) lastElement;
return getType(scope, expression, true);
}
// TODO: functions, classes, etc.
throw new IllegalArgumentException("Last item in the block must be an expression");
}
}
private void collectAllReturnTypes(JetWhenExpression whenExpression, JetScope scope, List<Type> result) {
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetWhenExpression subWhen = entry.getSubWhen();
if (subWhen != null) {
collectAllReturnTypes(subWhen, scope, result);
} else {
JetExpression resultExpression = entry.getExpression();
if (resultExpression != null) {
result.add(getType(scope, resultExpression, true));
}
}
}
}
private JetTypeChecker() {}
public Type commonSupertype(Collection<Type> types) {
Collection<Type> typeSet = new HashSet<Type>(types);
@@ -0,0 +1,444 @@
package org.jetbrains.jet.lang.types;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
/**
* @author abreslav
*/
public class JetTypeInferrer {
private final BindingTrace trace;
private final JetSemanticServices semanticServices;
public JetTypeInferrer(BindingTrace trace, JetSemanticServices semanticServices) {
this.trace = trace;
this.semanticServices = semanticServices;
}
/*
: "new" constructorInvocation
: objectLiteral
: SimpleName
: "typeof" "(" expression ")"
: functionLiteral
: declaration
: "namespace" // for the root namespace
*/
public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
final Type[] result = new Type[1];
expression.accept(new JetVisitor() {
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
// TODO : other members
// TODO : type substitutions???
PropertyDescriptor property = scope.getProperty(expression.getReferencedName());
trace.recordResolutionResult(expression, property);
if (property != null) {
result[0] = property.getType();
}
}
@Override
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
if (preferBlock && !expression.hasParameterSpecification()) {
result[0] = getBlockReturnedType(scope, expression.getBody());
return;
}
JetTypeReference returnTypeRef = expression.getReturnTypeRef();
JetTypeReference receiverTypeRef = expression.getReceiverTypeRef();
final Type receiverType;
if (receiverTypeRef != null) {
receiverType = TypeResolver.INSTANCE.resolveType(scope, receiverTypeRef);
} else {
receiverType = scope.getThisType();
}
List<JetElement> body = expression.getBody();
final Map<String, PropertyDescriptor> parameterDescriptors = new HashMap<String, PropertyDescriptor>();
List<Type> parameterTypes = new ArrayList<Type>();
for (JetParameter parameter : expression.getParameters()) {
JetTypeReference typeReference = parameter.getTypeReference();
if (typeReference == null) {
throw new UnsupportedOperationException("Type inference for parameters is not implemented yet");
}
PropertyDescriptor propertyDescriptor = semanticServices.getClassDescriptorResolver().resolvePropertyDescriptor(scope, parameter);
parameterDescriptors.put(parameter.getName(), propertyDescriptor);
parameterTypes.add(propertyDescriptor.getType());
}
Type returnType;
if (returnTypeRef != null) {
returnType = TypeResolver.INSTANCE.resolveType(scope, returnTypeRef);
} else {
WritableScope writableScope = new WritableScope(scope);
for (PropertyDescriptor propertyDescriptor : parameterDescriptors.values()) {
writableScope.addPropertyDescriptor(propertyDescriptor);
}
writableScope.setThisType(receiverType);
returnType = getBlockReturnedType(writableScope, body);
}
result[0] = JetStandardClasses.getFunctionType(null, receiverTypeRef == null ? null : receiverType, parameterTypes, returnType);
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
result[0] = getType(scope, expression.getExpression(), false);
}
@Override
public void visitConstantExpression(JetConstantExpression expression) {
IElementType elementType = expression.getNode().getElementType();
JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary();
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
result[0] = standardLibrary.getIntType();
} else if (elementType == JetNodeTypes.LONG_CONSTANT) {
result[0] = standardLibrary.getLongType();
} else if (elementType == JetNodeTypes.FLOAT_CONSTANT) {
String text = expression.getText();
assert text.length() > 0;
char lastChar = text.charAt(text.length() - 1);
if (lastChar == 'f' || lastChar == 'F') {
result[0] = standardLibrary.getFloatType();
} else {
result[0] = standardLibrary.getDoubleType();
}
} else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) {
result[0] = standardLibrary.getBooleanType();
} else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) {
result[0] = standardLibrary.getCharType();
} else if (elementType == JetNodeTypes.STRING_CONSTANT) {
result[0] = standardLibrary.getStringType();
} else if (elementType == JetNodeTypes.NULL) {
result[0] = JetStandardClasses.getNullableNothingType();
} else {
throw new IllegalArgumentException("Unsupported constant: " + expression);
}
}
@Override
public void visitThrowExpression(JetThrowExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitReturnExpression(JetReturnExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitBreakExpression(JetBreakExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitContinueExpression(JetContinueExpression expression) {
result[0] = JetStandardClasses.getNothingType();
}
@Override
public void visitTypeofExpression(JetTypeofExpression expression) {
throw new UnsupportedOperationException("Return some reflection interface"); // TODO
}
@Override
public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
if (expression.getOperationSign() == JetTokens.COLON) {
Type actualType = getType(scope, expression.getLeft(), false);
Type expectedType = TypeResolver.INSTANCE.resolveType(scope, expression.getRight());
if (JetTypeChecker.INSTANCE.isSubtypeOf(actualType, expectedType)) {
result[0] = expectedType;
return;
} else {
// TODO
throw new UnsupportedOperationException("Type mismatch: expected " + expectedType + " but found " + actualType);
}
}
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitIfExpression(JetIfExpression expression) {
// TODO : check condition type
// TODO : change types according to is and nullability checks
JetExpression elseBranch = expression.getElse();
if (elseBranch == null) {
// TODO : type-check the branch
result[0] = JetStandardClasses.getUnitType();
} else {
Type thenType = getType(scope, expression.getThen(), true);
Type elseType = getType(scope, elseBranch, true);
result[0] = JetTypeChecker.INSTANCE.commonSupertype(Arrays.asList(thenType, elseType));
}
}
@Override
public void visitWhenExpression(JetWhenExpression expression) {
// TODO :change scope according to the bound value in the when header
List<Type> expressions = new ArrayList<Type>();
collectAllReturnTypes(expression, scope, expressions);
result[0] = JetTypeChecker.INSTANCE.commonSupertype(expressions);
}
@Override
public void visitTryExpression(JetTryExpression expression) {
JetExpression tryBlock = expression.getTryBlock();
List<JetCatchClause> catchClauses = expression.getCatchClauses();
JetFinallySection finallyBlock = expression.getFinallyBlock();
List<Type> types = new ArrayList<Type>();
if (finallyBlock == null) {
for (JetCatchClause catchClause : catchClauses) {
// TODO: change scope here
types.add(getType(scope, catchClause.getCatchBody(), true));
}
} else {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
}
types.add(getType(scope, tryBlock, true));
result[0] = JetTypeChecker.INSTANCE.commonSupertype(types);
}
@Override
public void visitTupleExpression(JetTupleExpression expression) {
List<JetExpression> entries = expression.getEntries();
List<Type> types = new ArrayList<Type>();
for (JetExpression entry : entries) {
types.add(getType(scope, entry, false));
}
// TODO : labels
result[0] = JetStandardClasses.getTupleType(types);
}
@Override
public void visitThisExpression(JetThisExpression expression) {
// TODO : qualified this, e.g. Foo.this<Bar>
Type thisType = scope.getThisType();
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
// This cast must be safe (assuming the PSI doesn't contain errors)
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = TypeResolver.INSTANCE.resolveClass(scope, typeElement);
Collection<? extends Type> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.getSubstitutionContext(thisType);
for (Type declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result[0] = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break;
}
}
assert result[0] != null;
} else {
result[0] = thisType;
}
}
@Override
public void visitBlockExpression(JetBlockExpression expression) {
result[0] = getBlockReturnedType(scope, expression.getStatements());
}
@Override
public void visitLoopExpression(JetLoopExpression expression) {
result[0] = JetStandardClasses.getUnitType();
}
@Override
public void visitNewExpression(JetNewExpression expression) {
// TODO : type argument inference
JetTypeReference typeReference = expression.getTypeReference();
result[0] = TypeResolver.INSTANCE.resolveType(scope, typeReference);
}
@Override
public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) {
// TODO : functions
JetExpression receiverExpression = expression.getReceiverExpression();
JetExpression selectorExpression = expression.getSelectorExpression();
Type receiverType = getType(scope, receiverExpression, false);
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType);
result[0] = getType(compositeScope, selectorExpression, false);
}
@Override
public void visitCallExpression(JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression();
// 1) ends with a name -> (scope, name) to look up
// 2) ends with something else -> just check types
// TODO : check somewhere that these are NOT projections
List<JetTypeProjection> typeArguments = expression.getTypeArguments();
List<JetArgument> valueArguments = expression.getValueArguments();
boolean someNamed = false;
for (JetArgument argument : valueArguments) {
if (argument.isNamed()) {
someNamed = true;
break;
}
}
List<JetExpression> functionLiteralArguments = expression.getFunctionLiteralArguments();
// JetExpression functionLiteralArgument = functionLiteralArguments.isEmpty() ? null : functionLiteralArguments.get(0);
// TODO : must be a check
assert functionLiteralArguments.size() <= 1;
OverloadDomain overloadDomain = getOverloadDomain(scope, calleeExpression);
if (someNamed) {
// TODO : check that all are named
throw new UnsupportedOperationException(); // TODO
// result[0] = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument);
} else {
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
for (JetArgument argument : valueArguments) {
positionedValueArguments.add(argument.getArgumentExpression());
}
positionedValueArguments.addAll(functionLiteralArguments);
List<Type> types = new ArrayList<Type>();
for (JetTypeProjection projection : typeArguments) {
// TODO : check that there's no projection
types.add(TypeResolver.INSTANCE.resolveType(scope, projection.getTypeReference()));
}
List<Type> valueArgumentTypes = new ArrayList<Type>();
for (JetExpression valueArgument : positionedValueArguments) {
valueArgumentTypes.add(getType(scope, valueArgument, false));
}
FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes);
if (functionDescriptor != null) {
result[0] = functionDescriptor.getUnsubstitutedReturnType();
}
}
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem);
}
});
trace.recordExpressionType(expression, result[0]);
return result[0];
}
private OverloadDomain getOverloadDomain(final JetScope scope, JetExpression calleeExpression) {
final OverloadDomain[] result = new OverloadDomain[1];
final JetReferenceExpression[] reference = new JetReferenceExpression[1];
calleeExpression.accept(new JetVisitor() {
@Override
public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) {
// a#b -- create a domain for all overloads of b in a
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitPredicateExpression(JetPredicateExpression expression) {
// overload lookup for checking, but the type is receiver's type + nullable
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitQualifiedExpression(JetQualifiedExpression expression) {
// . or ?.
JetExpression selectorExpression = expression.getSelectorExpression();
if (selectorExpression instanceof JetReferenceExpression) {
JetReferenceExpression referenceExpression = (JetReferenceExpression) selectorExpression;
Type receiverType = getType(scope, expression.getReceiverExpression(), false);
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression;
} else {
throw new UnsupportedOperationException(); // TODO
}
}
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
// a -- create a hierarchical lookup domain for this.a
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName());
reference[0] = expression;
}
@Override
public void visitExpression(JetExpression expression) {
// <e> create a dummy domain for the type of e
throw new UnsupportedOperationException(); // TODO
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem);
}
});
return new OverloadDomain() {
@Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<Type> typeArguments, @NotNull Map<String, Type> valueArgumentTypes, @Nullable Type functionLiteralArgumentType) {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType);
trace.recordResolutionResult(reference[0], descriptor);
return descriptor;
}
@Override
public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List<Type> typeArguments, @NotNull List<Type> positionedValueArgumentTypes) {
FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
trace.recordResolutionResult(reference[0], descriptor);
return descriptor;
}
};
}
private Type getBlockReturnedType(@NotNull JetScope outerScope, List<JetElement> block) {
if (block.isEmpty()) {
return JetStandardClasses.getUnitType();
} else {
WritableScope scope = new WritableScope(outerScope);
for (JetElement statement : block) {
// TODO: consider other declarations
if (statement instanceof JetProperty) {
JetProperty property = (JetProperty) statement;
scope.addPropertyDescriptor(semanticServices.getClassDescriptorResolver().resolvePropertyDescriptor(scope, property));
}
}
JetElement lastElement = block.get(block.size() - 1);
if (lastElement instanceof JetExpression) {
JetExpression expression = (JetExpression) lastElement;
return getType(scope, expression, true);
}
// TODO: functions, classes, etc.
throw new IllegalArgumentException("Last item in the block must be an expression");
}
}
private void collectAllReturnTypes(JetWhenExpression whenExpression, JetScope scope, List<Type> result) {
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetWhenExpression subWhen = entry.getSubWhen();
if (subWhen != null) {
collectAllReturnTypes(subWhen, scope, result);
} else {
JetExpression resultExpression = entry.getExpression();
if (resultExpression != null) {
result.add(getType(scope, resultExpression, true));
}
}
}
}
}
@@ -31,7 +31,11 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor function : possiblyApplicableFunctions) {
result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function));
if (substitutionContext.isEmpty()) {
result.add(function);
} else {
result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function));
}
}
return result;
}
@@ -1,8 +1,10 @@
package org.jetbrains.jet.codegen;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.parsing.JetParsingTest;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.util.TraceClassVisitor;
@@ -60,7 +62,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
StringWriter writer = new StringWriter();
JetFile jetFile = (JetFile) myFixture.getFile();
JetNamespace namespace = jetFile.getRootNamespace();
codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer)));
codegen.generate(namespace, new TraceClassVisitor(new PrintWriter(writer)), new JetSemanticServices(new JetStandardLibrary(getProject())));
return writer.toString();
}
@@ -68,7 +70,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase {
JetFile jetFile = (JetFile) myFixture.getFile();
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
final JetNamespace namespace = jetFile.getRootNamespace();
codegen.generate(namespace, writer);
codegen.generate(namespace, writer, new JetSemanticServices(new JetStandardLibrary(getProject())));
final byte[] data = writer.toByteArray();
MyClassLoader classLoader = new MyClassLoader(NamespaceGenTest.class.getClassLoader());
final Class aClass = classLoader.doDefineClass(NamespaceCodegen.getJVMClassName(namespace).replace("/", "."), data);
@@ -3,6 +3,7 @@ package org.jetbrains.jet.resolve;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*;
@@ -18,6 +19,13 @@ import java.util.List;
* @author abreslav
*/
public class JetResolveTest extends LightDaemonAnalyzerTestCase {
private JetStandardLibrary library;
@Override
public void setUp() throws Exception {
super.setUp();
library = new JetStandardLibrary(getProject());
}
@Override
protected String getTestDataPath() {
@@ -31,7 +39,7 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
public void testBasic() throws Exception {
JetFile jetFile = JetChangeUtil.createFile(getProject(), FileUtil.loadTextAndClose(new FileReader(getTestDataPath() + "/resolve/Basic.jet")));
List<JetDeclaration> declarations = jetFile.getRootNamespace().getDeclarations();
BindingContext bindingContext = new TopDownAnalyzer().process(JetStandardClasses.STANDARD_CLASSES, declarations);
BindingContext bindingContext = new TopDownAnalyzer(new JetSemanticServices(library)).process(library.getLibraryScope(), declarations);
JetClass classADecl = (JetClass) declarations.get(0);
ClassDescriptor classA = bindingContext.getClassDescriptor(classADecl);
@@ -41,26 +49,30 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
ClassDescriptor classB = membersOfA.getClass("B");
assertNotNull(classB);
FunctionGroup fooFG = membersOfA.getFunctionGroup("foo");
assertFalse(fooFG.isEmpty());
{
FunctionGroup fooFG = membersOfA.getFunctionGroup("foo");
assertFalse(fooFG.isEmpty());
}
assertReturnType(membersOfA, "foo", JetStandardClasses.getIntType());
assertReturnType(membersOfA, "foo", library.getIntType());
assertReturnType(membersOfA, "foo1", new TypeImpl(classB));
assertReturnType(membersOfA, "fooB", JetStandardClasses.getIntType());
assertReturnType(membersOfA, "fooB", library.getIntType());
JetFunction fooDecl = (JetFunction) classADecl.getDeclarations().get(1);
Type expressionType = bindingContext.getExpressionType(fooDecl.getBodyExpression());
assertEquals(JetStandardClasses.getIntType(), expressionType);
DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression());
assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve);
assertEquals(library.getIntType(), expressionType);
{
JetFunction fooBDecl = (JetFunction) classADecl.getDeclarations().get(2);
JetCallExpression fooBBody = (JetCallExpression) fooBDecl.getBodyExpression();
JetReferenceExpression refToFoo = (JetReferenceExpression) fooBBody.getCalleeExpression();
FunctionDescriptor mustBeFoo = (FunctionDescriptor) bindingContext.resolve(refToFoo);
assertSame(bindingContext.getFunctionDescriptor(fooDecl), FunctionDescriptorUtil.getOriginal(mustBeFoo));
DeclarationDescriptor resolve = bindingContext.resolve((JetReferenceExpression) fooDecl.getBodyExpression());
assertSame(bindingContext.getFunctionDescriptor(fooDecl).getUnsubstitutedValueParameters().get(0), resolve);
}
{
JetFunction fooBDecl = (JetFunction) classADecl.getDeclarations().get(2);
JetCallExpression fooBBody = (JetCallExpression) fooBDecl.getBodyExpression();
JetReferenceExpression refToFoo = (JetReferenceExpression) fooBBody.getCalleeExpression();
FunctionDescriptor mustBeFoo = (FunctionDescriptor) bindingContext.resolve(refToFoo);
assertSame(bindingContext.getFunctionDescriptor(fooDecl), FunctionDescriptorUtil.getOriginal(mustBeFoo));
}
{
@@ -69,8 +81,8 @@ public class JetResolveTest extends LightDaemonAnalyzerTestCase {
JetDotQualifiedExpression qualifiedPlus = (JetDotQualifiedExpression) fooIntBody.getCalleeExpression();
JetReferenceExpression refToPlus = (JetReferenceExpression) qualifiedPlus.getSelectorExpression();
FunctionDescriptor mustBePlus = (FunctionDescriptor) bindingContext.resolve(refToPlus);
FunctionGroup plusGroup = JetStandardClasses.getInt().getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup("plus");
Collection<FunctionDescriptor> pluses = plusGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(JetStandardClasses.getIntType()));
FunctionGroup plusGroup = library.getInt().getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup("plus");
Collection<FunctionDescriptor> pluses = plusGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(library.getIntType()));
FunctionDescriptor intPlus = null;
for (FunctionDescriptor plus : pluses) {
intPlus = plus;
@@ -4,19 +4,37 @@ import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.JetChangeUtil;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author abreslav
*/
public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
private JetStandardLibrary library;
private JetSemanticServices semanticServices;
private ClassDefinitions classDefinitions;
@Override
public void setUp() throws Exception {
super.setUp();
library = new JetStandardLibrary(getProject());
semanticServices = new JetSemanticServices(library);
classDefinitions = new ClassDefinitions();
}
@Override
protected String getTestDataPath() {
return getHomeDirectory() + "/idea/testData";
@@ -27,31 +45,31 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
}
public void testConstants() throws Exception {
assertType("1", JetStandardClasses.getIntType());
assertType("0x1", JetStandardClasses.getIntType());
assertType("0X1", JetStandardClasses.getIntType());
assertType("0b1", JetStandardClasses.getIntType());
assertType("0B1", JetStandardClasses.getIntType());
assertType("1", library.getIntType());
assertType("0x1", library.getIntType());
assertType("0X1", library.getIntType());
assertType("0b1", library.getIntType());
assertType("0B1", library.getIntType());
assertType("1l", JetStandardClasses.getLongType());
assertType("1L", JetStandardClasses.getLongType());
assertType("1l", library.getLongType());
assertType("1L", library.getLongType());
assertType("1.0", JetStandardClasses.getDoubleType());
assertType("1.0d", JetStandardClasses.getDoubleType());
assertType("1.0D", JetStandardClasses.getDoubleType());
assertType("0x1.fffffffffffffp1023", JetStandardClasses.getDoubleType());
assertType("1.0", library.getDoubleType());
assertType("1.0d", library.getDoubleType());
assertType("1.0D", library.getDoubleType());
assertType("0x1.fffffffffffffp1023", library.getDoubleType());
assertType("1.0f", JetStandardClasses.getFloatType());
assertType("1.0F", JetStandardClasses.getFloatType());
assertType("0x1.fffffffffffffp1023f", JetStandardClasses.getFloatType());
assertType("1.0f", library.getFloatType());
assertType("1.0F", library.getFloatType());
assertType("0x1.fffffffffffffp1023f", library.getFloatType());
assertType("true", JetStandardClasses.getBooleanType());
assertType("false", JetStandardClasses.getBooleanType());
assertType("true", library.getBooleanType());
assertType("false", library.getBooleanType());
assertType("'d'", JetStandardClasses.getCharType());
assertType("'d'", library.getCharType());
assertType("\"d\"", JetStandardClasses.getStringType());
assertType("\"\"\"d\"\"\"", JetStandardClasses.getStringType());
assertType("\"d\"", library.getStringType());
assertType("\"\"\"d\"\"\"", library.getStringType());
assertType("()", JetStandardClasses.getUnitType());
@@ -61,7 +79,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public void testTupleConstants() throws Exception {
assertType("()", JetStandardClasses.getUnitType());
assertType("(1, 'a')", JetStandardClasses.getTupleType(JetStandardClasses.getIntType(), JetStandardClasses.getCharType()));
assertType("(1, 'a')", JetStandardClasses.getTupleType(library.getIntType(), library.getCharType()));
}
public void testJumps() throws Exception {
@@ -384,11 +402,11 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
// public void testImplicitConversions() throws Exception {
// }
//
private static void assertSubtype(String type1, String type2) {
private void assertSubtype(String type1, String type2) {
assertSubtypingRelation(type1, type2, true);
}
private static void assertNotSubtype(String type1, String type2) {
private void assertNotSubtype(String type1, String type2) {
assertSubtypingRelation(type1, type2, false);
}
@@ -401,7 +419,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertTrue(result + " != " + expected, TypeImpl.equalTypes(result, makeType(expected)));
}
private static void assertSubtypingRelation(String type1, String type2, boolean expected) {
private void assertSubtypingRelation(String type1, String type2, boolean expected) {
Type typeNode1 = makeType(type1);
Type typeNode2 = makeType(type2);
boolean result = JetTypeChecker.INSTANCE.isSubtypeOf(
@@ -411,37 +429,37 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertTrue(typeNode1 + " is " + modifier + "a subtype of " + typeNode2, result == expected);
}
private static void assertConvertibleTo(String expression, Type type) {
private void assertConvertibleTo(String expression, Type type) {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertTrue(
expression + " must be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
}
private static void assertNotConvertibleTo(String expression, Type type) {
private void assertNotConvertibleTo(String expression, Type type) {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertFalse(
expression + " must not be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
}
private static void assertType(String expression, Type expectedType) {
private void assertType(String expression, Type expectedType) {
Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = JetTypeChecker.INSTANCE.getType(ClassDefinitions.BASIC_SCOPE, jetExpression, false);
Type type = semanticServices.getTypeInferrer().getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
assertTrue(type + " != " + expectedType, TypeImpl.equalTypes(type, expectedType));
}
private void assertErrorType(String expression) {
Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = JetTypeChecker.INSTANCE.getType(ClassDefinitions.BASIC_SCOPE, jetExpression, false);
Type type = semanticServices.getTypeInferrer().getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
assertTrue("Error type expected but " + type + " returned", ErrorType.isErrorType(type));
}
private static void assertType(String contextType, String expression, String expectedType) {
private void assertType(String contextType, String expression, String expectedType) {
final Type thisType = makeType(contextType);
JetScope scope = new JetScopeAdapter(ClassDefinitions.BASIC_SCOPE) {
JetScope scope = new JetScopeAdapter(classDefinitions.BASIC_SCOPE) {
@NotNull
@Override
public Type getThisType() {
@@ -451,29 +469,29 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertType(scope, expression, expectedType);
}
private static void assertType(String expression, String expectedTypeStr) {
assertType(ClassDefinitions.BASIC_SCOPE, expression, expectedTypeStr);
private void assertType(String expression, String expectedTypeStr) {
assertType(classDefinitions.BASIC_SCOPE, expression, expectedTypeStr);
}
private static void assertType(JetScope scope, String expression, String expectedTypeStr) {
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = JetTypeChecker.INSTANCE.getType(scope, jetExpression, false);
Type type = semanticServices.getTypeInferrer().getType(scope, jetExpression, false);
Type expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
assertEquals(expectedType, type);
}
private static Type makeType(String typeStr) {
return makeType(ClassDefinitions.BASIC_SCOPE, typeStr);
private Type makeType(String typeStr) {
return makeType(classDefinitions.BASIC_SCOPE, typeStr);
}
private static Type makeType(JetScope scope, String typeStr) {
return TypeResolver.INSTANCE.resolveType(scope, JetChangeUtil.createType(getProject(), typeStr));
}
private static class ClassDefinitions {
private static Map<String, ClassDescriptor> CLASSES = new HashMap<String, ClassDescriptor>();
private static String[] CLASS_DECLARATIONS = {
private class ClassDefinitions {
private Map<String, ClassDescriptor> CLASSES = new HashMap<String, ClassDescriptor>();
private String[] CLASS_DECLARATIONS = {
"open class Base_T<T>",
"open class Derived_T<T> : Base_T<T>",
"open class DDerived_T<T> : Derived_T<T>",
@@ -492,20 +510,20 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
"fun f<E>(a : E) : T {} " +
"}"
};
private static String[] FUNCTION_DECLARATIONS = {
private String[] FUNCTION_DECLARATIONS = {
"fun f() : Unit {}",
"fun f(a : Int) : Int {a}",
"fun f(a : Float, b : Int) : Float {a}",
"fun f<T>(a : Float) : T {a}",
};
public static JetScope BASIC_SCOPE = new JetScopeAdapter(JetStandardClasses.STANDARD_CLASSES) {
public JetScope BASIC_SCOPE = new JetScopeAdapter(library.getLibraryScope()) {
@Override
public ClassDescriptor getClass(String name) {
if (CLASSES.isEmpty()) {
for (String classDeclaration : CLASS_DECLARATIONS) {
JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration);
ClassDescriptor classDescriptor = ClassDescriptorResolver.INSTANCE.resolveClassDescriptor(this, classElement);
ClassDescriptor classDescriptor = semanticServices.getClassDescriptorResolver().resolveClassDescriptor(this, classElement);
CLASSES.put(classDescriptor.getName(), classDescriptor);
}
}
@@ -521,7 +539,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public FunctionGroup getFunctionGroup(@NotNull String name) {
WritableFunctionGroup writableFunctionGroup = new WritableFunctionGroup(name);
for (String funDecl : FUNCTION_DECLARATIONS) {
FunctionDescriptor functionDescriptor = ClassDescriptorResolver.INSTANCE.resolveFunctionDescriptor(this, JetChangeUtil.createFunction(getProject(), funDecl));
FunctionDescriptor functionDescriptor = semanticServices.getClassDescriptorResolver().resolveFunctionDescriptor(this, JetChangeUtil.createFunction(getProject(), funDecl));
if (name.equals(functionDescriptor.getName())) {
writableFunctionGroup.addFunction(functionDescriptor);
}