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.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDeclaration; 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.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.HashMap;
import java.util.List; import java.util.List;
@@ -17,13 +20,14 @@ public class LazyScope extends JetScopeAdapter {
private final List<JetDeclaration> declarations; private final List<JetDeclaration> declarations;
private Map<String, ClassDescriptor> classDescriptors; private Map<String, ClassDescriptor> classDescriptors;
private Map<String, WritableFunctionGroup> functionGroups;
public LazyScope(JetScope scope, List<JetDeclaration> declarations) { public LazyScope(JetScope scope, List<JetDeclaration> declarations) {
super(scope); super(scope);
this.declarations = declarations; this.declarations = declarations;
} }
public Map<String, ClassDescriptor> getClassDescriptors() { private Map<String, ClassDescriptor> getClassDescriptors() {
if (classDescriptors == null) { if (classDescriptors == null) {
classDescriptors = new HashMap<String, ClassDescriptor>(); classDescriptors = new HashMap<String, ClassDescriptor>();
for (JetDeclaration declaration : declarations) { for (JetDeclaration declaration : declarations) {
@@ -47,35 +51,35 @@ public class LazyScope extends JetScopeAdapter {
return super.getClass(name); return super.getClass(name);
} }
@Override private Map<String, WritableFunctionGroup> getFunctionGroups() {
public PropertyDescriptor getProperty(String name) { if (functionGroups == null) {
throw new UnsupportedOperationException(); // TODO functionGroups = new HashMap<String, WritableFunctionGroup>();
} for (JetDeclaration declaration : declarations) {
declaration.accept(new JetVisitor() {
@Override @Override
public ExtensionDescriptor getExtension(String name) { public void visitFunction(JetFunction function) {
throw new UnsupportedOperationException(); // TODO FunctionDescriptor functionDescriptor = ClassDescriptorResolver.INSTANCE.resolveFunctionDescriptor(LazyScope.this, function);
} String name = functionDescriptor.getName();
WritableFunctionGroup group = functionGroups.get(name);
@Override if (group == null) {
public NamespaceDescriptor getNamespace(String name) { group = new WritableFunctionGroup(name);
throw new UnsupportedOperationException(); // TODO functionGroups.put(name, group);
} }
group.addFunction(functionDescriptor);
@Override }
public TypeParameterDescriptor getTypeParameter(String name) { });
throw new UnsupportedOperationException(); // TODO }
} }
return functionGroups;
@NotNull
@Override
public Type getThisType() {
throw new UnsupportedOperationException(); // TODO
} }
@NotNull @NotNull
@Override @Override
public FunctionGroup getFunctionGroup(@NotNull String name) { 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.annotations.Nullable;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.*; import java.util.HashMap;
import java.util.Map;
/** /**
* @author abreslav * @author abreslav
@@ -16,15 +17,13 @@ public class WritableScope extends JetScopeAdapter {
private Map<String, WritableFunctionGroup> functionGroups; private Map<String, WritableFunctionGroup> functionGroups;
@Nullable @Nullable
private Map<String, TypeParameterDescriptor> typeParameterDescriptors; private Map<String, TypeParameterDescriptor> typeParameterDescriptors;
@Nullable
private Map<String, ClassDescriptor> classDescriptors;
public WritableScope(JetScope scope) { public WritableScope(JetScope scope) {
super(scope); super(scope);
} }
public WritableScope() {
super(JetScope.EMPTY);
}
@NotNull @NotNull
private Map<String, PropertyDescriptor> getPropertyDescriptors() { private Map<String, PropertyDescriptor> getPropertyDescriptors() {
if (propertyDescriptors == null) { if (propertyDescriptors == null) {
@@ -45,7 +44,11 @@ public class WritableScope extends JetScopeAdapter {
public PropertyDescriptor getProperty(String name) { public PropertyDescriptor getProperty(String name) {
@NotNull @NotNull
Map<String, PropertyDescriptor> propertyDescriptors = getPropertyDescriptors(); Map<String, PropertyDescriptor> propertyDescriptors = getPropertyDescriptors();
return propertyDescriptors.get(name); PropertyDescriptor propertyDescriptor = propertyDescriptors.get(name);
if (propertyDescriptor != null) {
return propertyDescriptor;
}
return super.getProperty(name);
} }
@NotNull @NotNull
@@ -73,10 +76,10 @@ public class WritableScope extends JetScopeAdapter {
@NotNull @NotNull
public FunctionGroup getFunctionGroup(@NotNull String name) { public FunctionGroup getFunctionGroup(@NotNull String name) {
WritableFunctionGroup functionGroup = getFunctionGroups().get(name); WritableFunctionGroup functionGroup = getFunctionGroups().get(name);
if (functionGroup == null) { if (functionGroup != null && !functionGroup.isEmpty()) {
return FunctionGroup.EMPTY; return functionGroup;
} }
return functionGroup; return super.getFunctionGroup(name);
} }
@NotNull @NotNull
@@ -105,24 +108,47 @@ public class WritableScope extends JetScopeAdapter {
return super.getTypeParameter(name); 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 @Override
public ClassDescriptor getClass(String name) { public ClassDescriptor getClass(String name) {
return super.getClass(name); // TODO ClassDescriptor classDescriptor = getClassDescriptors().get(name);
} if (classDescriptor != null) {
return classDescriptor;
@Override }
public ExtensionDescriptor getExtension(String name) { return super.getClass(name);
throw new UnsupportedOperationException(); // TODO
}
@Override
public NamespaceDescriptor getNamespace(String name) {
throw new UnsupportedOperationException(); // TODO
} }
@NotNull @NotNull
@Override @Override
public Type getThisType() { 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.psi.JetFile;
import org.jetbrains.jet.lang.resolve.FileContentsResolver; import org.jetbrains.jet.lang.resolve.FileContentsResolver;
import org.jetbrains.jet.lang.resolve.JetScope; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -47,6 +47,16 @@ public class JetStandardClasses {
}, JetScope.EMPTY }, 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( private static final ClassDescriptor ANY = new ClassDescriptorImpl(
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
false, false,
@@ -56,48 +66,17 @@ public class JetStandardClasses {
JetScope.EMPTY 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; 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; public static final int TUPLE_COUNT = 22;
private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT]; private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT];
static { static {
for (int i = 0; i < TUPLE_COUNT; i++) { for (int i = 0; i < TUPLE_COUNT; i++) {
List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(); List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>();
@@ -112,14 +91,16 @@ public class JetStandardClasses {
true, true,
"Tuple" + i, "Tuple" + i,
parameters, parameters,
Collections.singleton(JetStandardClasses.getAnyType()), STUB); Collections.singleton(getAnyType()), STUB);
} }
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static final int FUNCTION_COUNT = 22; public static final int FUNCTION_COUNT = 22;
private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT];
private static final ClassDescriptor[] RECEIVER_FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; private static final ClassDescriptor[] RECEIVER_FUNCTION = new ClassDescriptor[FUNCTION_COUNT];
static { static {
for (int i = 0; i < FUNCTION_COUNT; i++) { for (int i = 0; i < FUNCTION_COUNT; i++) {
List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(); List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>();
@@ -138,7 +119,7 @@ public class JetStandardClasses {
false, false,
"Function" + i, "Function" + i,
parameters, parameters,
Collections.singleton(JetStandardClasses.getAnyType()), STUB); Collections.singleton(getAnyType()), STUB);
parameters.add(0, new TypeParameterDescriptor( parameters.add(0, new TypeParameterDescriptor(
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
Variance.IN_VARIANCE, "T", Variance.IN_VARIANCE, "T",
@@ -148,10 +129,69 @@ public class JetStandardClasses {
false, false,
"ReceiverFunction" + i, "ReceiverFunction" + i,
parameters, 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 BYTE_TYPE = new TypeImpl(getByte());
private static final Type CHAR_TYPE = new TypeImpl(getChar()); private static final Type CHAR_TYPE = new TypeImpl(getChar());
private static final Type SHORT_TYPE = new TypeImpl(getShort()); 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 BOOLEAN_TYPE = new TypeImpl(getBoolean());
private static final Type STRING_TYPE = new TypeImpl(getString()); private static final Type STRING_TYPE = new TypeImpl(getString());
private static final Type UNIT_TYPE = new TypeImpl(getTuple(0)); 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 { static {
WritableScope writableScope = new WritableScope(LIBRARY_SCOPE);
STANDARD_CLASSES = writableScope;
Field[] declaredFields = JetStandardClasses.class.getDeclaredFields(); Field[] declaredFields = JetStandardClasses.class.getDeclaredFields();
for (Field field : declaredFields) { for (Field field : declaredFields) {
if ((field.getModifiers() & Modifier.STATIC) == 0) { if ((field.getModifiers() & Modifier.STATIC) == 0) {
@@ -182,7 +219,7 @@ public class JetStandardClasses {
if (type == ClassDescriptor.class) { if (type == ClassDescriptor.class) {
try { try {
ClassDescriptor descriptor = (ClassDescriptor) field.get(null); ClassDescriptor descriptor = (ClassDescriptor) field.get(null);
CLASS_MAP.put(descriptor.getName(), descriptor); writableScope.addClassDescriptor(descriptor);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
@@ -190,24 +227,15 @@ public class JetStandardClasses {
try { try {
ClassDescriptor[] array = (ClassDescriptor[]) field.get(null); ClassDescriptor[] array = (ClassDescriptor[]) field.get(null);
for (ClassDescriptor descriptor : array) { for (ClassDescriptor descriptor : array) {
CLASS_MAP.put(descriptor.getName(), descriptor); writableScope.addClassDescriptor(descriptor);
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalStateException(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 @NotNull
public static ClassDescriptor getAny() { public static ClassDescriptor getAny() {
return ANY; return ANY;
@@ -388,7 +388,7 @@ public class JetTypeChecker {
if (block.isEmpty()) { if (block.isEmpty()) {
return JetStandardClasses.getUnitType(); return JetStandardClasses.getUnitType();
} else { } else {
AccumulatingScope scope = new AccumulatingScope(outerScope); WritableScope scope = new WritableScope(outerScope);
for (JetElement statement : block) { for (JetElement statement : block) {
// TODO: consider other declarations // TODO: consider other declarations
if (statement instanceof JetProperty) { if (statement instanceof JetProperty) {
@@ -333,8 +333,42 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertType("f(1.0)", (String) null); 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 { // public void testImplicitConversions() throws Exception {
// assertConvertibleTo("1", JetStandardClasses.getByteType());
// } // }
// //
private static void assertSubtype(String type1, String type2) { private static void assertSubtype(String type1, String type2) {