JetStandardLibrary factored out of JetStandardClasses. JetSemanticServices added
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user