diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index fabc8c5aa7a..63544a5c48b 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -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 { diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index dab4e766022..9481b8b05f8 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -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 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), diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java new file mode 100644 index 00000000000..d040a5115bc --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -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); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index ec18fb469d0..cd6e21d1ff6 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -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); } } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index c93fd6f03e1..6a6903d35ee 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -14,4 +14,6 @@ public interface BindingContext { Type getExpressionType(JetExpression expression); DeclarationDescriptor resolve(JetReferenceExpression referenceExpression); + + JetScope getTopLevelScope(); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 711fe1a62b5..86cb4eaec1e 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -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); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/FileContentsResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/FileContentsResolver.java deleted file mode 100644 index 129f0b4c783..00000000000 --- a/idea/src/org/jetbrains/jet/lang/resolve/FileContentsResolver.java +++ /dev/null @@ -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()); - } - -} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/LazyClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/LazyClassDescriptor.java deleted file mode 100644 index 8ac02aeb774..00000000000 --- a/idea/src/org/jetbrains/jet/lang/resolve/LazyClassDescriptor.java +++ /dev/null @@ -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 attributes; - private WritableScope parameterScope; - private List typeParameterDescriptors; - - public LazyClassDescriptor(@NotNull JetScope scope, @NotNull JetClass klass) { - this.declaration = klass; - this.outerScope = scope; - } - - @Override - public List 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 typeParameters = getTypeParameters(); - List delegationSpecifiers = declaration.getDelegationSpecifiers(); - // TODO : assuming that the hierarchy is acyclic - // TODO : cannot inherit from an inner class - Collection 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 getTypeParameters() { - if (parameterScope == null) { - parameterScope = new WritableScope(outerScope); - typeParameterDescriptors = ClassDescriptorResolver.INSTANCE.resolveTypeParameters(parameterScope, declaration.getTypeParameters()); - } - return typeParameterDescriptors; - } - - @Override - public JetScope getMemberScope(List typeArguments) { - if (unsubstitutedMemberScope == null) { - unsubstitutedMemberScope = new LazyScope(getTypeParameterScope(), declaration.getDeclarations()); - } - List parameters = getTypeConstructor().getParameters(); - if (parameters.isEmpty()) { - return unsubstitutedMemberScope; - } - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(parameters, typeArguments); - return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext); - } -} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java b/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java deleted file mode 100644 index e016220ca07..00000000000 --- a/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java +++ /dev/null @@ -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 declarations; - - private Map classDescriptors; - private Map functionGroups; - - public LazyScope(JetScope scope, List declarations) { - super(scope); - this.declarations = declarations; - } - - private Map getClassDescriptors() { - if (classDescriptors == null) { - classDescriptors = new HashMap(); - 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 getFunctionGroups() { - if (functionGroups == null) { - functionGroups = new HashMap(); - 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); - } -} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index 0516180b7b8..c706374c7a4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -13,6 +13,7 @@ import java.util.Map; * @author abreslav */ public class OverloadResolver { + public static final OverloadResolver INSTANCE = new OverloadResolver(); private OverloadResolver() {} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 9b073aeea46..9d01900976a 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -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 classes = new LinkedHashMap(); private final Map functions = new HashMap(); + private Map properties = new HashMap(); private final Map declaringScopes = new HashMap(); private Map expressionTypes = new HashMap(); private Map resolutionResults = new HashMap(); + private final JetSemanticServices semanticServices; + + public TopDownAnalyzer(JetSemanticServices semanticServices) { + this.semanticServices = semanticServices; + } + public BindingContext process(@NotNull JetScope outerScope, @NotNull List 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 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); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableBindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableBindingContext.java deleted file mode 100644 index 6e9248db3db..00000000000 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableBindingContext.java +++ /dev/null @@ -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 - } -} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java similarity index 87% rename from idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java rename to idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index de25b91c7c8..9424815ee84 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeCheckerTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -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) { } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index da46cb20e06..4c59976462b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java new file mode 100644 index 00000000000..b102668a0e7 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -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; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index e4755f543c3..3ed0f3a915b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -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 body = expression.getBody(); - final Map parameterDescriptors = new HashMap(); - List parameterTypes = new ArrayList(); - 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 expressions = new ArrayList(); - collectAllReturnTypes(expression, scope, expressions); - result[0] = commonSupertype(expressions); - } - - @Override - public void visitTryExpression(JetTryExpression expression) { - JetExpression tryBlock = expression.getTryBlock(); - List catchClauses = expression.getCatchClauses(); - JetFinallySection finallyBlock = expression.getFinallyBlock(); - List types = new ArrayList(); - 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 entries = expression.getEntries(); - List types = new ArrayList(); - 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 - 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 supertypes = thisType.getConstructor().getSupertypes(); - Map 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 typeArguments = expression.getTypeArguments(); - - List valueArguments = expression.getValueArguments(); - boolean someNamed = false; - for (JetArgument argument : valueArguments) { - if (argument.isNamed()) { - someNamed = true; - break; - } - } - List 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 positionedValueArguments = new ArrayList(); - for (JetArgument argument : valueArguments) { - positionedValueArguments.add(argument.getArgumentExpression()); - } - - positionedValueArguments.addAll(functionLiteralArguments); - - List types = new ArrayList(); - for (JetTypeProjection projection : typeArguments) { - // TODO : check that there's no projection - types.add(TypeResolver.INSTANCE.resolveType(scope, projection.getTypeReference())); - } - - List valueArgumentTypes = new ArrayList(); - 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) { - // 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 typeArguments, @NotNull Map 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 typeArguments, @NotNull List positionedValueArgumentTypes) { - FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes); - trace.recordResolutionResult(reference[0], descriptor); - return descriptor; - } - }; - } - - private Type getBlockReturnedType(@NotNull JetScope outerScope, List 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 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 types) { Collection typeSet = new HashSet(types); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java new file mode 100644 index 00000000000..f121c6e5683 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -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 body = expression.getBody(); + final Map parameterDescriptors = new HashMap(); + List parameterTypes = new ArrayList(); + 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 expressions = new ArrayList(); + collectAllReturnTypes(expression, scope, expressions); + result[0] = JetTypeChecker.INSTANCE.commonSupertype(expressions); + } + + @Override + public void visitTryExpression(JetTryExpression expression) { + JetExpression tryBlock = expression.getTryBlock(); + List catchClauses = expression.getCatchClauses(); + JetFinallySection finallyBlock = expression.getFinallyBlock(); + List types = new ArrayList(); + 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 entries = expression.getEntries(); + List types = new ArrayList(); + 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 + 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 supertypes = thisType.getConstructor().getSupertypes(); + Map 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 typeArguments = expression.getTypeArguments(); + + List valueArguments = expression.getValueArguments(); + boolean someNamed = false; + for (JetArgument argument : valueArguments) { + if (argument.isNamed()) { + someNamed = true; + break; + } + } + List 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 positionedValueArguments = new ArrayList(); + for (JetArgument argument : valueArguments) { + positionedValueArguments.add(argument.getArgumentExpression()); + } + + positionedValueArguments.addAll(functionLiteralArguments); + + List types = new ArrayList(); + for (JetTypeProjection projection : typeArguments) { + // TODO : check that there's no projection + types.add(TypeResolver.INSTANCE.resolveType(scope, projection.getTypeReference())); + } + + List valueArgumentTypes = new ArrayList(); + 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) { + // 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 typeArguments, @NotNull Map 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 typeArguments, @NotNull List positionedValueArgumentTypes) { + FunctionDescriptor descriptor = result[0].getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes); + trace.recordResolutionResult(reference[0], descriptor); + return descriptor; + } + }; + } + + private Type getBlockReturnedType(@NotNull JetScope outerScope, List 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 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)); + } + } + } + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java index 8cd475c6f86..d1d6606e3ce 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java @@ -31,7 +31,11 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup { Collection possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); Collection result = new ArrayList(); 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; } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a3abebc5057..eef1828f059 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -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); diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 69a8fa65637..fa7511f59ec 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -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 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.emptyList()).getFunctionGroup("plus"); - Collection pluses = plusGroup.getPossiblyApplicableFunctions(Collections.emptyList(), Collections.singletonList(JetStandardClasses.getIntType())); + FunctionGroup plusGroup = library.getInt().getMemberScope(Collections.emptyList()).getFunctionGroup("plus"); + Collection pluses = plusGroup.getPossiblyApplicableFunctions(Collections.emptyList(), Collections.singletonList(library.getIntType())); FunctionDescriptor intPlus = null; for (FunctionDescriptor plus : pluses) { intPlus = plus; diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 8d03662053b..9e0123d2d20 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -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 CLASSES = new HashMap(); - private static String[] CLASS_DECLARATIONS = { + private class ClassDefinitions { + private Map CLASSES = new HashMap(); + private String[] CLASS_DECLARATIONS = { "open class Base_T", "open class Derived_T : Base_T", "open class DDerived_T : Derived_T", @@ -492,20 +510,20 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { "fun f(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(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); }