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:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user