diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AccumulatingScope.java b/idea/src/org/jetbrains/jet/lang/resolve/AccumulatingScope.java deleted file mode 100644 index c6ce9c7e553..00000000000 --- a/idea/src/org/jetbrains/jet/lang/resolve/AccumulatingScope.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.jetbrains.jet.lang.resolve; - -import org.jetbrains.jet.lang.types.PropertyDescriptor; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author abreslav - */ -public class AccumulatingScope extends JetScopeAdapter { - private final Map properties = new HashMap(); - - public AccumulatingScope(JetScope outerScope) { - super(outerScope); - } - - public void addPropertyDescriptor(PropertyDescriptor propertyDescriptor) { - if (properties.put(propertyDescriptor.getName(), propertyDescriptor) != null) { - throw new IllegalArgumentException("Duplicate property: " + propertyDescriptor.getName()); - } - } - - @Override - public PropertyDescriptor getProperty(String name) { - PropertyDescriptor propertyDescriptor = properties.get(name); - if (propertyDescriptor == null) { - return super.getProperty(name); - } - return propertyDescriptor; - } -} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java b/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java index 58840468058..e016220ca07 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/LazyScope.java @@ -3,8 +3,11 @@ 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.*; +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; @@ -17,13 +20,14 @@ 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; } - public Map getClassDescriptors() { + private Map getClassDescriptors() { if (classDescriptors == null) { classDescriptors = new HashMap(); for (JetDeclaration declaration : declarations) { @@ -47,35 +51,35 @@ public class LazyScope extends JetScopeAdapter { return super.getClass(name); } - @Override - public PropertyDescriptor getProperty(String name) { - throw new UnsupportedOperationException(); // TODO - } - - @Override - public ExtensionDescriptor getExtension(String name) { - throw new UnsupportedOperationException(); // TODO - } - - @Override - public NamespaceDescriptor getNamespace(String name) { - throw new UnsupportedOperationException(); // TODO - } - - @Override - public TypeParameterDescriptor getTypeParameter(String name) { - throw new UnsupportedOperationException(); // TODO - } - - @NotNull - @Override - public Type getThisType() { - throw new UnsupportedOperationException(); // TODO + 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) { - throw new UnsupportedOperationException(); // TODO + WritableFunctionGroup group = getFunctionGroups().get(name); + if (!group.isEmpty()) { + return group; + } + return super.getFunctionGroup(name); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java index addfdcdeb0c..837145a4082 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java @@ -4,7 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.*; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * @author abreslav @@ -16,15 +17,13 @@ public class WritableScope extends JetScopeAdapter { private Map functionGroups; @Nullable private Map typeParameterDescriptors; + @Nullable + private Map classDescriptors; public WritableScope(JetScope scope) { super(scope); } - public WritableScope() { - super(JetScope.EMPTY); - } - @NotNull private Map getPropertyDescriptors() { if (propertyDescriptors == null) { @@ -45,7 +44,11 @@ public class WritableScope extends JetScopeAdapter { public PropertyDescriptor getProperty(String name) { @NotNull Map propertyDescriptors = getPropertyDescriptors(); - return propertyDescriptors.get(name); + PropertyDescriptor propertyDescriptor = propertyDescriptors.get(name); + if (propertyDescriptor != null) { + return propertyDescriptor; + } + return super.getProperty(name); } @NotNull @@ -73,10 +76,10 @@ public class WritableScope extends JetScopeAdapter { @NotNull public FunctionGroup getFunctionGroup(@NotNull String name) { WritableFunctionGroup functionGroup = getFunctionGroups().get(name); - if (functionGroup == null) { - return FunctionGroup.EMPTY; + if (functionGroup != null && !functionGroup.isEmpty()) { + return functionGroup; } - return functionGroup; + return super.getFunctionGroup(name); } @NotNull @@ -105,24 +108,47 @@ public class WritableScope extends JetScopeAdapter { return super.getTypeParameter(name); } + @NotNull + private Map getClassDescriptors() { + if (classDescriptors == null) { + classDescriptors = new HashMap(); + } + return classDescriptors; + } + + public void addClassDescriptor(@NotNull ClassDescriptor classDescriptor) { + addClassAlias(classDescriptor.getName(), classDescriptor); + } + + public void addClassAlias(String name, ClassDescriptor classDescriptor) { + Map classDescriptors = getClassDescriptors(); + if (classDescriptors.put(name, classDescriptor) != null) { + throw new UnsupportedOperationException("Class redeclared: " + classDescriptor.getName()); + } + } + @Override public ClassDescriptor getClass(String name) { - return super.getClass(name); // TODO - } - - @Override - public ExtensionDescriptor getExtension(String name) { - throw new UnsupportedOperationException(); // TODO - } - - @Override - public NamespaceDescriptor getNamespace(String name) { - throw new UnsupportedOperationException(); // TODO + ClassDescriptor classDescriptor = getClassDescriptors().get(name); + if (classDescriptor != null) { + return classDescriptor; + } + return super.getClass(name); } @NotNull @Override public Type getThisType() { - throw new UnsupportedOperationException(); // TODO + return super.getThisType(); // TODO + } + + @Override + public NamespaceDescriptor getNamespace(String name) { + return super.getNamespace(name); // TODO + } + + @Override + public ExtensionDescriptor getExtension(String name) { + return super.getExtension(name); // TODO } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 808ee0e18fc..77658dc5664 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -10,7 +10,7 @@ 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.JetScopeImpl; +import org.jetbrains.jet.lang.resolve.WritableScope; import java.io.IOException; import java.io.InputStream; @@ -47,6 +47,16 @@ public class JetStandardClasses { }, JetScope.EMPTY ); + private static final Type NOTHING_TYPE = new TypeImpl(getNothing()); + private static final Type NULLABLE_NOTHING_TYPE = new TypeImpl( + Collections.emptyList(), + getNothing().getTypeConstructor(), + true, + Collections.emptyList(), + JetScope.EMPTY); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private static final ClassDescriptor ANY = new ClassDescriptorImpl( Collections.emptyList(), false, @@ -56,48 +66,17 @@ public class JetStandardClasses { JetScope.EMPTY ); + private static final Type ANY_TYPE = new TypeImpl(ANY.getTypeConstructor(), JetScope.EMPTY); + private static final Type NULLABLE_ANY_TYPE = TypeUtils.makeNullable(ANY_TYPE); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public static final JetScope STUB = JetScope.EMPTY; - private static final Type ANY_TYPE = new TypeImpl(ANY.getTypeConstructor(), JetScope.EMPTY); - - 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(JetScope.EMPTY, file); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private static final Type NULLABLE_ANY_TYPE = TypeUtils.makeNullable(ANY_TYPE); - @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"); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static final int TUPLE_COUNT = 22; private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT]; - static { for (int i = 0; i < TUPLE_COUNT; i++) { List parameters = new ArrayList(); @@ -112,14 +91,16 @@ public class JetStandardClasses { true, "Tuple" + i, parameters, - Collections.singleton(JetStandardClasses.getAnyType()), STUB); + Collections.singleton(getAnyType()), STUB); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public static final int FUNCTION_COUNT = 22; private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; private static final ClassDescriptor[] RECEIVER_FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; - static { for (int i = 0; i < FUNCTION_COUNT; i++) { List parameters = new ArrayList(); @@ -138,7 +119,7 @@ public class JetStandardClasses { false, "Function" + i, parameters, - Collections.singleton(JetStandardClasses.getAnyType()), STUB); + Collections.singleton(getAnyType()), STUB); parameters.add(0, new TypeParameterDescriptor( Collections.emptyList(), Variance.IN_VARIANCE, "T", @@ -148,10 +129,69 @@ public class JetStandardClasses { false, "ReceiverFunction" + i, parameters, - Collections.singleton(JetStandardClasses.getAnyType()), STUB); + Collections.singleton(getAnyType()), STUB); } } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + 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()); @@ -162,17 +202,14 @@ public class JetStandardClasses { 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)); - private static final Type NOTHING_TYPE = new TypeImpl(getNothing()); - private static final Type NULLABLE_NOTHING_TYPE = new TypeImpl( - Collections.emptyList(), - getNothing().getTypeConstructor(), - true, - Collections.emptyList(), - JetScope.EMPTY); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private static final Map CLASS_MAP = new HashMap(); + @NotNull + public static final JetScope STANDARD_CLASSES; static { + WritableScope writableScope = new WritableScope(LIBRARY_SCOPE); + STANDARD_CLASSES = writableScope; Field[] declaredFields = JetStandardClasses.class.getDeclaredFields(); for (Field field : declaredFields) { if ((field.getModifiers() & Modifier.STATIC) == 0) { @@ -182,7 +219,7 @@ public class JetStandardClasses { if (type == ClassDescriptor.class) { try { ClassDescriptor descriptor = (ClassDescriptor) field.get(null); - CLASS_MAP.put(descriptor.getName(), descriptor); + writableScope.addClassDescriptor(descriptor); } catch (IllegalAccessException e) { throw new IllegalStateException(e); } @@ -190,24 +227,15 @@ public class JetStandardClasses { try { ClassDescriptor[] array = (ClassDescriptor[]) field.get(null); for (ClassDescriptor descriptor : array) { - CLASS_MAP.put(descriptor.getName(), descriptor); + writableScope.addClassDescriptor(descriptor); } } catch (IllegalAccessException e) { throw new IllegalStateException(e); } } } - CLASS_MAP.put("Unit", getTuple(0)); } - @NotNull - public static final JetScope STANDARD_CLASSES = new JetScopeImpl() { - @Override - public ClassDescriptor getClass(String name) { - return CLASS_MAP.get(name); - } - }; - @NotNull public static ClassDescriptor getAny() { return ANY; diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index c50d67d7374..3e021517654 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -388,7 +388,7 @@ public class JetTypeChecker { if (block.isEmpty()) { return JetStandardClasses.getUnitType(); } else { - AccumulatingScope scope = new AccumulatingScope(outerScope); + WritableScope scope = new WritableScope(outerScope); for (JetElement statement : block) { // TODO: consider other declarations if (statement instanceof JetProperty) { diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index ff6ff034313..59bd14bfde6 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -333,8 +333,42 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertType("f(1.0)", (String) null); } + public void testPlus() throws Exception { + assertType("1d.plus(1d)", "Double"); +// assertType("1d.plus(1f)", "Double"); +// assertType("1d.plus(1L)", "Double"); +// assertType("1d.plus(1)", "Double"); + + assertType("1f.plus(1d)", "Double"); + assertType("1f.plus(1f)", "Float"); +// assertType("1f.plus(1L)", "Float"); +// assertType("1f.plus(1)", "Float"); + + assertType("1L.plus(1d)", "Double"); + assertType("1L.plus(1f)", "Float"); + assertType("1L.plus(1L)", "Long"); +// assertType("1L.plus(1)", "Long"); + + assertType("1.plus(1d)", "Double"); + assertType("1.plus(1f)", "Float"); + assertType("1.plus(1L)", "Long"); + assertType("1.plus(1)", "Int"); + + assertType("'1'.plus(1d)", "Double"); + assertType("'1'.plus(1f)", "Float"); + assertType("'1'.plus(1L)", "Long"); + assertType("'1'.plus(1)", "Int"); + assertType("'1'.plus('1')", "Char"); + + assertType("\"1\".plus(1d)", "String"); + assertType("\"1\".plus(1f)", "String"); + assertType("\"1\".plus(1L)", "String"); + assertType("\"1\".plus(1)", "String"); + assertType("\"1\".plus('1')", "String"); + } + + // assertConvertibleTo("1", JetStandardClasses.getByteType()); // public void testImplicitConversions() throws Exception { -// assertConvertibleTo("1", JetStandardClasses.getByteType()); // } // private static void assertSubtype(String type1, String type2) {