Resolution in generic classes fixed

This commit is contained in:
Andrey Breslav
2011-03-10 17:13:19 +03:00
parent 5472df794b
commit c1677055b0
14 changed files with 120 additions and 29 deletions
@@ -52,7 +52,7 @@ public class ClassDescriptorResolver {
@Nullable @Nullable
public void resolveMutableClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) { public void resolveMutableClassDescriptor(@NotNull JetScope scope, @NotNull JetClass classElement, @NotNull MutableClassDescriptor descriptor) {
WritableScope parameterScope = new WritableScope(scope); WritableScope parameterScope = descriptor.getUnsubstitutedMemberScope();
// This call has side-effects on the parameterScope (fills it in) // This call has side-effects on the parameterScope (fills it in)
List<TypeParameterDescriptor> typeParameters List<TypeParameterDescriptor> typeParameters
@@ -157,17 +157,21 @@ public class ClassDescriptorResolver {
JetParameter valueParameter = valueParameters.get(i); JetParameter valueParameter = valueParameters.get(i);
JetTypeReference typeReference = valueParameter.getTypeReference(); JetTypeReference typeReference = valueParameter.getTypeReference();
assert typeReference != null : "Parameters without type annotations are not supported"; // TODO Type type;
if (typeReference == null) {
semanticServices.getErrorHandler().structuralError(valueParameter.getNode(), "A type annotation is required on a value parameter " + valueParameter.getName());
type = ErrorType.createErrorType("Type annotation was missing");
} else {
type = typeResolver.resolveType(parameterScope, typeReference);
}
ValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl( ValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl(
i, i,
AttributeResolver.INSTANCE.resolveAttributes(valueParameter.getModifierList()), AttributeResolver.INSTANCE.resolveAttributes(valueParameter.getModifierList()),
valueParameter.getName(), valueParameter.getName(),
typeResolver.resolveType(parameterScope, typeReference), type,
valueParameter.getDefaultValue() != null, valueParameter.getDefaultValue() != null,
false // TODO : varargs false // TODO : varargs
); );
// TODO : Default values??? // TODO : Default values???
result.add(valueParameterDescriptor); result.add(valueParameterDescriptor);
@@ -197,6 +201,7 @@ public class ClassDescriptorResolver {
: Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound)) : Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound))
); );
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor); extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor);
return typeParameterDescriptor; return typeParameterDescriptor;
} }
@@ -1,10 +1,7 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.Attribute; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.ClassDescriptor;
import org.jetbrains.jet.lang.types.TypeConstructor;
import org.jetbrains.jet.lang.types.TypeProjection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -49,4 +46,9 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
public String getName() { public String getName() {
return original.getName(); return original.getName();
} }
@Override
public DeclarationDescriptor getOriginal() {
return original.getOriginal();
}
} }
@@ -24,4 +24,9 @@ public class MutableDeclarationDescriptor implements DeclarationDescriptor {
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@Override
public DeclarationDescriptor getOriginal() {
return this;
}
} }
@@ -60,6 +60,10 @@ public class SubstitutingScope implements JetScope {
@NotNull @NotNull
@Override @Override
public FunctionGroup getFunctionGroup(@NotNull String name) { public FunctionGroup getFunctionGroup(@NotNull String name) {
return new LazySubstitutingFunctionGroup(substitutionContext, workerScope.getFunctionGroup(name)); FunctionGroup functionGroup = workerScope.getFunctionGroup(name);
if (substitutionContext.isEmpty()) {
return functionGroup;
}
return new LazySubstitutingFunctionGroup(substitutionContext, functionGroup);
} }
} }
@@ -4,4 +4,11 @@ package org.jetbrains.jet.lang.types;
* @author abreslav * @author abreslav
*/ */
public interface DeclarationDescriptor extends Annotated, Named { public interface DeclarationDescriptor extends Annotated, Named {
/**
* @return The descriptor that corresponds to the original declaration of this element.
* A descriptor can be obtained from its original by substituting type arguments (of the declaring class
* or of the element itself).
* returns <code>this</code> object if the current descriptor is original itself
*/
DeclarationDescriptor getOriginal();
} }
@@ -18,4 +18,9 @@ public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements
public String getName() { public String getName() {
return name; return name;
} }
@Override
public DeclarationDescriptor getOriginal() {
return this;
}
} }
@@ -18,12 +18,6 @@ public interface FunctionDescriptor extends DeclarationDescriptor {
@NotNull @NotNull
Type getUnsubstitutedReturnType(); Type getUnsubstitutedReturnType();
/**
* @return The descriptor that corresponds to the original declaration of this function.
* A descriptor can be obtained from its original by substituting type arguments (of the declaring class
* or of the function itself).
* null if the current descriptor is original itself
*/
@Nullable @Nullable
FunctionDescriptor getOriginal(); FunctionDescriptor getOriginal();
} }
@@ -2,9 +2,8 @@ package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFunction;
import java.util.*; import java.util.List;
/** /**
* @author abreslav * @author abreslav
@@ -27,7 +26,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters, @NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
@NotNull Type unsubstitutedReturnType) { @NotNull Type unsubstitutedReturnType) {
super(attributes, name); super(attributes, name);
this.original = original; this.original = original == null ? this : original;
this.typeParameters = typeParameters; this.typeParameters = typeParameters;
this.unsubstitutedValueParameters = unsubstitutedValueParameters; this.unsubstitutedValueParameters = unsubstitutedValueParameters;
this.unsubstitutedReturnType = unsubstitutedReturnType; this.unsubstitutedReturnType = unsubstitutedReturnType;
@@ -16,7 +16,9 @@ import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -46,6 +48,7 @@ public class JetStandardLibrary {
private final ClassDescriptor doubleClass; private final ClassDescriptor doubleClass;
private final ClassDescriptor booleanClass; private final ClassDescriptor booleanClass;
private final ClassDescriptor stringClass; private final ClassDescriptor stringClass;
private final ClassDescriptor arrayClass;
private final Type byteType; private final Type byteType;
private final Type charType; private final Type charType;
@@ -82,6 +85,7 @@ public class JetStandardLibrary {
this.doubleClass = libraryScope.getClass("Double"); this.doubleClass = libraryScope.getClass("Double");
this.booleanClass = libraryScope.getClass("Boolean"); this.booleanClass = libraryScope.getClass("Boolean");
this.stringClass = libraryScope.getClass("String"); this.stringClass = libraryScope.getClass("String");
this.arrayClass = libraryScope.getClass("Array");
this.byteType = new TypeImpl(getByte()); this.byteType = new TypeImpl(getByte());
this.charType = new TypeImpl(getChar()); this.charType = new TypeImpl(getChar());
@@ -146,39 +150,71 @@ public class JetStandardLibrary {
return stringClass; return stringClass;
} }
@NotNull
public ClassDescriptor getArray() {
return arrayClass;
}
@NotNull
public Type getIntType() { public Type getIntType() {
return intType; return intType;
} }
@NotNull
public Type getLongType() { public Type getLongType() {
return longType; return longType;
} }
@NotNull
public Type getDoubleType() { public Type getDoubleType() {
return doubleType; return doubleType;
} }
@NotNull
public Type getFloatType() { public Type getFloatType() {
return floatType; return floatType;
} }
@NotNull
public Type getCharType() { public Type getCharType() {
return charType; return charType;
} }
@NotNull
public Type getBooleanType() { public Type getBooleanType() {
return booleanType; return booleanType;
} }
@NotNull
public Type getStringType() { public Type getStringType() {
return stringType; return stringType;
} }
@NotNull
public Type getByteType() { public Type getByteType() {
return byteType; return byteType;
} }
@NotNull
public Type getShortType() { public Type getShortType() {
return shortType; return shortType;
} }
@NotNull
public Type getArrayType(@NotNull Type argument) {
Variance variance = Variance.INVARIANT;
return getArrayType(variance, argument);
}
@NotNull
public Type getArrayType(@NotNull Variance variance, @NotNull Type argument) {
List<TypeProjection> types = Collections.singletonList(new TypeProjection(variance, argument));
return new TypeImpl(
Collections.<Attribute>emptyList(),
getArray().getTypeConstructor(),
false,
types,
getArray().getMemberScope(types)
);
}
} }
@@ -36,4 +36,9 @@ public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor
public String getName() { public String getName() {
return propertyDescriptor.getName(); return propertyDescriptor.getName();
} }
@Override
public DeclarationDescriptor getOriginal() {
return propertyDescriptor.getOriginal();
}
} }
@@ -60,7 +60,7 @@ public class LazySubstitutingFunctionDescriptor implements FunctionDescriptor {
@Override @Override
public FunctionDescriptor getOriginal() { public FunctionDescriptor getOriginal() {
return functionDescriptor; return functionDescriptor.getOriginal();
} }
@Override @Override
@@ -73,5 +73,7 @@ public class LazySubstitutingFunctionDescriptor implements FunctionDescriptor {
public String getName() { public String getName() {
return functionDescriptor.getName(); return functionDescriptor.getName();
} }
} }
+5
View File
@@ -1,6 +1,11 @@
import `java::java`java.* import `java::java`java.*
import `java::java.util`util.* import `java::java.util`util.*
fun foo(~a~a : `std::Array`Array<`std::Int`Int>) : `java::java.util.List`List {
`a`a.`std::Array.get(Int)`get(1)
`a`a.`std::Array.set(Int, Int)`set(1, 1)
}
fun foo(o : `java::java.lang.Object`Object, l : `java::java.util`util.`java::java.util.List`List) : `java::java.util.List`List {} fun foo(o : `java::java.lang.Object`Object, l : `java::java.util`util.`java::java.util.List`List) : `java::java.util.List`List {}
~A~class A { ~A~class A {
@@ -120,7 +120,7 @@ public class ExpectedResolveData {
JetTypeReference typeReference = getAncestorOfType(JetTypeReference.class, element); JetTypeReference typeReference = getAncestorOfType(JetTypeReference.class, element);
if (expectedDescriptor != null) { if (expectedDescriptor != null) {
DeclarationDescriptor actual = bindingContext.resolveReferenceExpression(reference); DeclarationDescriptor actual = bindingContext.resolveReferenceExpression(reference);
assertSame(expectedDescriptor, actual); assertSame("Expected: " + name, expectedDescriptor.getOriginal(), actual == null ? null : actual.getOriginal());
continue; continue;
} }
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest; import org.jetbrains.jet.parsing.JetParsingTest;
@@ -28,6 +29,11 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
JetStandardLibrary lib = JetStandardLibrary.getJetStandardLibrary(project); JetStandardLibrary lib = JetStandardLibrary.getJetStandardLibrary(project);
Map<String, DeclarationDescriptor> nameToDescriptor = new HashMap<String, DeclarationDescriptor>(); Map<String, DeclarationDescriptor> nameToDescriptor = new HashMap<String, DeclarationDescriptor>();
nameToDescriptor.put("std::Int.plus(Int)", standardFunction(lib.getInt(), "plus", lib.getIntType())); nameToDescriptor.put("std::Int.plus(Int)", standardFunction(lib.getInt(), "plus", lib.getIntType()));
FunctionDescriptor descriptorForGet = standardFunction(lib.getArray(), Collections.singletonList(new TypeProjection(lib.getIntType())), "get", lib.getIntType());
nameToDescriptor.put("std::Array.get(Int)", descriptorForGet.getOriginal());
@NotNull
FunctionDescriptor descriptorForSet = standardFunction(lib.getArray(), Collections.singletonList(new TypeProjection(lib.getIntType())), "set", lib.getIntType(), lib.getIntType());
nameToDescriptor.put("std::Array.set(Int, Int)", descriptorForSet.getOriginal());
Map<String,PsiElement> nameToDeclaration = new HashMap<String, PsiElement>(); Map<String,PsiElement> nameToDeclaration = new HashMap<String, PsiElement>();
nameToDeclaration.put("java::java.util.Collections.emptyList()", findMethod(findClass("java.util.Collections"), "emptyList")); nameToDeclaration.put("java::java.util.Collections.emptyList()", findMethod(findClass("java.util.Collections"), "emptyList"));
@@ -43,20 +49,22 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
nameToDeclaration.put("java::java.io.PrintStream.print(Int)", methods[2]); nameToDeclaration.put("java::java.io.PrintStream.print(Int)", methods[2]);
nameToDeclaration.put("java::java.lang.System.out", findClass("java.lang.System").findFieldByName("out", true)); nameToDeclaration.put("java::java.lang.System.out", findClass("java.lang.System").findFieldByName("out", true));
return new ExpectedResolveData(nameToDescriptor, nameToDeclaration); return new ExpectedResolveData(nameToDescriptor, nameToDeclaration);
} }
@NotNull
private PsiElement findPackage(String qualifiedName) { private PsiElement findPackage(String qualifiedName) {
JavaPsiFacade javaFacade = JavaPsiFacade.getInstance(getProject()); JavaPsiFacade javaFacade = JavaPsiFacade.getInstance(getProject());
return javaFacade.findPackage(qualifiedName); return javaFacade.findPackage(qualifiedName);
} }
@NotNull
private PsiMethod findMethod(PsiClass psiClass, String name) { private PsiMethod findMethod(PsiClass psiClass, String name) {
PsiMethod[] emptyLists = psiClass.findMethodsByName(name, true); PsiMethod[] emptyLists = psiClass.findMethodsByName(name, true);
return emptyLists[0]; return emptyLists[0];
} }
@NotNull
private PsiClass findClass(String qualifiedName) { private PsiClass findClass(String qualifiedName) {
Project project = getProject(); Project project = getProject();
JavaPsiFacade javaFacade = JavaPsiFacade.getInstance(project); JavaPsiFacade javaFacade = JavaPsiFacade.getInstance(project);
@@ -64,15 +72,27 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
return javaFacade.findClass(qualifiedName, javaSearchScope); return javaFacade.findClass(qualifiedName, javaSearchScope);
} }
private DeclarationDescriptor standardFunction(ClassDescriptor classDescriptor, String name, Type parameterType) { @NotNull
FunctionGroup functionGroup = classDescriptor.getMemberScope(Collections.<TypeProjection>emptyList()).getFunctionGroup(name); private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, String name, Type parameterType) {
Collection<FunctionDescriptor> functions = functionGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), Collections.singletonList(parameterType)); List<TypeProjection> typeArguments = Collections.emptyList();
return standardFunction(classDescriptor, typeArguments, name, parameterType);
}
@NotNull
private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, List<TypeProjection> typeArguments, String name, Type... parameterType) {
FunctionGroup functionGroup = classDescriptor.getMemberScope(typeArguments).getFunctionGroup(name);
List<Type> parameterTypeList = Arrays.asList(parameterType);
Collection<FunctionDescriptor> functions = functionGroup.getPossiblyApplicableFunctions(Collections.<Type>emptyList(), parameterTypeList);
for (FunctionDescriptor function : functions) { for (FunctionDescriptor function : functions) {
if (function.getUnsubstitutedValueParameters().get(0).getType().equals(parameterType)) { List<ValueParameterDescriptor> unsubstitutedValueParameters = function.getUnsubstitutedValueParameters();
return function; for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
if (unsubstitutedValueParameter.getType().equals(parameterType[i])) {
return function;
}
} }
} }
throw new IllegalArgumentException("Not found: std::" + classDescriptor.getName() + "." + name + "(" + parameterType + ")"); throw new IllegalArgumentException("Not found: std::" + classDescriptor.getName() + "." + name + "(" + parameterTypeList + ")");
} }
@Override @Override
@@ -84,7 +104,9 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
protected Sdk getProjectJDK() { protected Sdk getProjectJDK() {
Properties properties = new Properties(); Properties properties = new Properties();
try { try {
properties.load(new FileReader(getHomeDirectory() + "/idea/idea.properties")); FileReader reader = new FileReader(getHomeDirectory() + "/idea/idea.properties");
properties.load(reader);
reader.close();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }