Basic method resolution for built-in classes

This commit is contained in:
Andrey Breslav
2011-02-25 15:00:58 +03:00
parent ed60c79099
commit e1994b0332
6 changed files with 203 additions and 143 deletions
@@ -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<String, PropertyDescriptor> properties = new HashMap<String, PropertyDescriptor>();
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;
}
}
@@ -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<JetDeclaration> declarations;
private Map<String, ClassDescriptor> classDescriptors;
private Map<String, WritableFunctionGroup> functionGroups;
public LazyScope(JetScope scope, List<JetDeclaration> declarations) {
super(scope);
this.declarations = declarations;
}
public Map<String, ClassDescriptor> getClassDescriptors() {
private Map<String, ClassDescriptor> getClassDescriptors() {
if (classDescriptors == null) {
classDescriptors = new HashMap<String, ClassDescriptor>();
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<String, WritableFunctionGroup> getFunctionGroups() {
if (functionGroups == null) {
functionGroups = new HashMap<String, WritableFunctionGroup>();
for (JetDeclaration declaration : declarations) {
declaration.accept(new JetVisitor() {
@Override
public void visitFunction(JetFunction function) {
FunctionDescriptor functionDescriptor = ClassDescriptorResolver.INSTANCE.resolveFunctionDescriptor(LazyScope.this, function);
String name = functionDescriptor.getName();
WritableFunctionGroup group = functionGroups.get(name);
if (group == null) {
group = new WritableFunctionGroup(name);
functionGroups.put(name, group);
}
group.addFunction(functionDescriptor);
}
});
}
}
return functionGroups;
}
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO
WritableFunctionGroup group = getFunctionGroups().get(name);
if (!group.isEmpty()) {
return group;
}
return super.getFunctionGroup(name);
}
}
@@ -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<String, WritableFunctionGroup> functionGroups;
@Nullable
private Map<String, TypeParameterDescriptor> typeParameterDescriptors;
@Nullable
private Map<String, ClassDescriptor> classDescriptors;
public WritableScope(JetScope scope) {
super(scope);
}
public WritableScope() {
super(JetScope.EMPTY);
}
@NotNull
private Map<String, PropertyDescriptor> getPropertyDescriptors() {
if (propertyDescriptors == null) {
@@ -45,7 +44,11 @@ public class WritableScope extends JetScopeAdapter {
public PropertyDescriptor getProperty(String name) {
@NotNull
Map<String, PropertyDescriptor> 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<String, ClassDescriptor> getClassDescriptors() {
if (classDescriptors == null) {
classDescriptors = new HashMap<String, ClassDescriptor>();
}
return classDescriptors;
}
public void addClassDescriptor(@NotNull ClassDescriptor classDescriptor) {
addClassAlias(classDescriptor.getName(), classDescriptor);
}
public void addClassAlias(String name, ClassDescriptor classDescriptor) {
Map<String, ClassDescriptor> 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
}
}
@@ -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.<Attribute>emptyList(),
getNothing().getTypeConstructor(),
true,
Collections.<TypeProjection>emptyList(),
JetScope.EMPTY);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final ClassDescriptor ANY = new ClassDescriptorImpl(
Collections.<Attribute>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<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>();
@@ -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<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>();
@@ -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.<Attribute>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.<Attribute>emptyList(),
getNothing().getTypeConstructor(),
true,
Collections.<TypeProjection>emptyList(),
JetScope.EMPTY);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private static final Map<String, ClassDescriptor> CLASS_MAP = new HashMap<String, ClassDescriptor>();
@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;
@@ -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) {
@@ -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) {