JET-18 Resolve references to value parameters of the primary constructor to parameter or property descriptors according to the semantics

This commit is contained in:
Andrey Breslav
2011-05-04 14:12:36 +04:00
parent dae06f0b67
commit ba221419b4
7 changed files with 137 additions and 48 deletions
@@ -9,6 +9,9 @@ import org.jetbrains.jet.lang.types.*;
* @author abreslav
*/
public interface BindingContext {
@Deprecated // "Tests only"
DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration);
NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration);
ClassDescriptor getClassDescriptor(JetClass declaration);
TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration);
@@ -121,6 +121,15 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration) {
if (declaration instanceof JetNamespace) {
JetNamespace namespace = (JetNamespace) declaration;
return getNamespaceDescriptor(namespace);
}
return declarationsToDescriptors.get(declaration);
}
public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) {
return namespaceDeclarationsToDescriptors.get(declaration);
}
@@ -152,8 +161,13 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
@Override
public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) {
PropertyDescriptor descriptor = primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter);
return descriptor;
return primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter);
}
@Nullable
@Override
public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) {
return constructorDeclarationsToDescriptors.get(declaration);
}
@Override
@@ -166,12 +180,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
return expressionTypes.get(expression);
}
@Nullable
@Override
public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) {
return constructorDeclarationsToDescriptors.get(declaration);
}
@Override
public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) {
return resolutionResults.get(referenceExpression);
@@ -316,10 +316,12 @@ public class TopDownAnalyzer {
private void resolveDelegationSpecifierLists() {
// TODO : Make sure the same thing is not initialized twice
final JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.NONE);
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
final JetClass jetClass = entry.getKey();
final MutableClassDescriptor descriptor = entry.getValue();
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
final JetScope scopeForConstructor = primaryConstructor == null ? null : getInnerScopeForConstructor(primaryConstructor, descriptor.getWritableUnsubstitutedMemberScope());
final JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
delegationSpecifier.accept(new JetVisitor() {
@@ -327,7 +329,8 @@ public class TopDownAnalyzer {
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
JetExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) {
JetType type = typeInferrer.getType(descriptor.getWritableUnsubstitutedMemberScope(), delegateExpression, false);
JetScope scope = scopeForConstructor == null ? descriptor.getWritableUnsubstitutedMemberScope() : scopeForConstructor;
JetType type = typeInferrer.getType(scope, delegateExpression, false);
JetType supertype = trace.resolveTypeReference(specifier.getTypeReference());
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
semanticServices.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
@@ -339,13 +342,15 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
typeInferrer.checkConstructorCall(descriptor.getWritableUnsubstitutedMemberScope(), typeReference, call);
if (!jetClass.hasPrimaryConstructor()) {
JetArgumentList valueArgumentList = call.getValueArgumentList();
assert valueArgumentList != null;
semanticServices.getErrorHandler().genericError(valueArgumentList.getNode(),
"Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes");
}
else {
typeInferrer.checkConstructorCall(scopeForConstructor, typeReference, call);
}
}
}
@@ -0,0 +1,19 @@
class C(~x~x : Int, ~y~val y : Int) : Base(`x`x /*parameter*/), Base1 by new Base1(`x`x) {
var z = `x`x // parameter
get() = `$x`x // property
{
val z = `x`x // parameter
}
this() : this(1, 2) {
val z = x // inaccessible
val zz = `$y`y // property
}
fun f() : Int {
return `$x`x // property
}
}
@@ -1,12 +1,12 @@
class A(~a~val a : Int) {
this() {`a`a}
this() {`$a`a}
~b~val b = `a`a
~f~fun f() = `a`a
~f~fun f() = `$a`a
}
fun test() {
~va~val a = new A()
`va`a.`a`a`:std::Int`
`va`a.`$a`a`:std::Int`
a.`b`b`:std::Int`
a.`f`f()`:std::Int`
}
@@ -119,6 +119,9 @@ public class ExpectedResolveData {
}
PsiElement expected = nameToDeclaration.get(name);
if (expected == null && name.startsWith("$")) {
expected = nameToDeclaration.get(name.substring(1));
}
if (expected == null) {
expected = nameToPsiElement.get(name);
}
@@ -143,6 +146,7 @@ public class ExpectedResolveData {
assert expected != null : "No declaration for " + name;
PsiElement actual = bindingContext.resolveToDeclarationPsiElement(reference);
String actualName = null;
if (actual != null) {
actualName = declarationToName.get(actual);
@@ -151,9 +155,31 @@ public class ExpectedResolveData {
}
}
assertNotNull(reference);
assertEquals(
"Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",
expected, actual);
if (expected instanceof JetParameter || actual instanceof JetParameter) {
DeclarationDescriptor expectedDescriptor;
if (name.startsWith("$")) {
expectedDescriptor = bindingContext.getPropertyDescriptor((JetParameter) expected);
}
else {
expectedDescriptor = bindingContext.getDeclarationDescriptor(expected);
if (expectedDescriptor == null) {
expectedDescriptor = bindingContext.getConstructorDescriptor((JetElement) expected);
}
}
DeclarationDescriptor actualDescriptor = bindingContext.resolveReferenceExpression(reference);
assertEquals(
"Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",
expectedDescriptor, actualDescriptor);
}
else {
assertEquals(
"Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",
expected, actual);
}
}
for (Map.Entry<Integer, String> entry : positionToType.entrySet()) {
@@ -8,6 +8,7 @@ import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import junit.framework.Test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetTestCaseBase;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
@@ -22,6 +23,14 @@ import java.util.*;
*/
public class JetResolveTest extends ExtensibleResolveTestCase {
private final String path;
private final String name;
public JetResolveTest(String path, String name) {
this.path = path;
this.name = name;
}
@Override
protected ExpectedResolveData getExpectedResolveData() {
Project project = getProject();
@@ -116,43 +125,62 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
}
private static String getHomeDirectory() {
return new File(PathManager.getResourceRoot(JetParsingTest.class, "/org/jetbrains/jet/parsing/JetParsingTest.class")).getParentFile().getParentFile().getParent();
return new File(PathManager.getResourceRoot(JetParsingTest.class, "/org/jetbrains/jet/parsing/JetParsingTest.class")).getParentFile().getParentFile().getParent();
}
public void testBasic() throws Exception {
doTest("/resolve/Basic.jet", true, true);
@Override
public String getName() {
return "test" + name;
}
public void testResolveToJava() throws Exception {
doTest("/resolve/ResolveToJava.jet", true, true);
@Override
protected void runTest() throws Throwable {
doTest(path, true, false);
}
public void testResolveOfInfixExpressions() throws Exception {
doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
}
// public void testBasic() throws Exception {
// doTest("/resolve/Basic.jet", true, true);
// }
//
// public void testResolveToJava() throws Exception {
// doTest("/resolve/ResolveToJava.jet", true, true);
// }
//
// public void testResolveOfInfixExpressions() throws Exception {
// doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
// }
//
// public void testProjections() throws Exception {
// doTest("/resolve/Projections.jet", true, true);
// }
//
// public void testPrimaryConstructors() throws Exception {
// doTest("/resolve/PrimaryConstructors.jet", true, true);
// }
//
// public void testClassifiers() throws Exception {
// doTest("/resolve/Classifiers.jet", true, true);
// }
//
// public void testConstructorsAndInitializers() throws Exception {
// doTest("/resolve/ConstructorsAndInitializers.jet", true, true);
// }
//
// public void testNamespaces() throws Exception {
// doTest("/resolve/Namespaces.jet", true, true);
// }
//
// public void testTryCatch() throws Exception {
// doTest("/resolve/TryCatch.jet", true, true);
// }
public void testProjections() throws Exception {
doTest("/resolve/Projections.jet", true, true);
public static Test suite() {
return JetTestCaseBase.suiteForDirectory(getHomeDirectory() + "/idea/testData/", "/resolve/", true, new JetTestCaseBase.NamedTestFactory() {
@NotNull
@Override
public Test createTest(@NotNull String dataPath, @NotNull String name) {
return new JetResolveTest(dataPath + "/" + name + ".jet", name);
}
});
}
public void testPrimaryConstructors() throws Exception {
doTest("/resolve/PrimaryConstructors.jet", true, true);
}
public void testClassifiers() throws Exception {
doTest("/resolve/Classifiers.jet", true, true);
}
public void testConstructorsAndInitializers() throws Exception {
doTest("/resolve/ConstructorsAndInitializers.jet", true, true);
}
public void testNamespaces() throws Exception {
doTest("/resolve/Namespaces.jet", true, true);
}
public void testTryCatch() throws Exception {
doTest("/resolve/TryCatch.jet", true, true);
}
}