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
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface BindingContext {
|
public interface BindingContext {
|
||||||
|
@Deprecated // "Tests only"
|
||||||
|
DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration);
|
||||||
|
|
||||||
NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration);
|
NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration);
|
||||||
ClassDescriptor getClassDescriptor(JetClass declaration);
|
ClassDescriptor getClassDescriptor(JetClass declaration);
|
||||||
TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter 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) {
|
public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) {
|
||||||
return namespaceDeclarationsToDescriptors.get(declaration);
|
return namespaceDeclarationsToDescriptors.get(declaration);
|
||||||
}
|
}
|
||||||
@@ -152,8 +161,13 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) {
|
public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) {
|
||||||
PropertyDescriptor descriptor = primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter);
|
return primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter);
|
||||||
return descriptor;
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) {
|
||||||
|
return constructorDeclarationsToDescriptors.get(declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -166,12 +180,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
return expressionTypes.get(expression);
|
return expressionTypes.get(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) {
|
|
||||||
return constructorDeclarationsToDescriptors.get(declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) {
|
public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) {
|
||||||
return resolutionResults.get(referenceExpression);
|
return resolutionResults.get(referenceExpression);
|
||||||
|
|||||||
@@ -316,10 +316,12 @@ public class TopDownAnalyzer {
|
|||||||
|
|
||||||
private void resolveDelegationSpecifierLists() {
|
private void resolveDelegationSpecifierLists() {
|
||||||
// TODO : Make sure the same thing is not initialized twice
|
// 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()) {
|
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
|
||||||
final JetClass jetClass = entry.getKey();
|
final JetClass jetClass = entry.getKey();
|
||||||
final MutableClassDescriptor descriptor = entry.getValue();
|
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()) {
|
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
|
||||||
delegationSpecifier.accept(new JetVisitor() {
|
delegationSpecifier.accept(new JetVisitor() {
|
||||||
@@ -327,7 +329,8 @@ public class TopDownAnalyzer {
|
|||||||
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
|
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
|
||||||
JetExpression delegateExpression = specifier.getDelegateExpression();
|
JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||||
if (delegateExpression != null) {
|
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());
|
JetType supertype = trace.resolveTypeReference(specifier.getTypeReference());
|
||||||
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
|
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
|
||||||
semanticServices.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
|
semanticServices.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
|
||||||
@@ -339,13 +342,15 @@ public class TopDownAnalyzer {
|
|||||||
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||||
JetTypeReference typeReference = call.getTypeReference();
|
JetTypeReference typeReference = call.getTypeReference();
|
||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
typeInferrer.checkConstructorCall(descriptor.getWritableUnsubstitutedMemberScope(), typeReference, call);
|
|
||||||
if (!jetClass.hasPrimaryConstructor()) {
|
if (!jetClass.hasPrimaryConstructor()) {
|
||||||
JetArgumentList valueArgumentList = call.getValueArgumentList();
|
JetArgumentList valueArgumentList = call.getValueArgumentList();
|
||||||
assert valueArgumentList != null;
|
assert valueArgumentList != null;
|
||||||
semanticServices.getErrorHandler().genericError(valueArgumentList.getNode(),
|
semanticServices.getErrorHandler().genericError(valueArgumentList.getNode(),
|
||||||
"Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes");
|
"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) {
|
class A(~a~val a : Int) {
|
||||||
this() {`a`a}
|
this() {`$a`a}
|
||||||
~b~val b = `a`a
|
~b~val b = `a`a
|
||||||
~f~fun f() = `a`a
|
~f~fun f() = `$a`a
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
~va~val a = new A()
|
~va~val a = new A()
|
||||||
`va`a.`a`a`:std::Int`
|
`va`a.`$a`a`:std::Int`
|
||||||
a.`b`b`:std::Int`
|
a.`b`b`:std::Int`
|
||||||
a.`f`f()`:std::Int`
|
a.`f`f()`:std::Int`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ public class ExpectedResolveData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PsiElement expected = nameToDeclaration.get(name);
|
PsiElement expected = nameToDeclaration.get(name);
|
||||||
|
if (expected == null && name.startsWith("$")) {
|
||||||
|
expected = nameToDeclaration.get(name.substring(1));
|
||||||
|
}
|
||||||
if (expected == null) {
|
if (expected == null) {
|
||||||
expected = nameToPsiElement.get(name);
|
expected = nameToPsiElement.get(name);
|
||||||
}
|
}
|
||||||
@@ -143,6 +146,7 @@ public class ExpectedResolveData {
|
|||||||
assert expected != null : "No declaration for " + name;
|
assert expected != null : "No declaration for " + name;
|
||||||
|
|
||||||
PsiElement actual = bindingContext.resolveToDeclarationPsiElement(reference);
|
PsiElement actual = bindingContext.resolveToDeclarationPsiElement(reference);
|
||||||
|
|
||||||
String actualName = null;
|
String actualName = null;
|
||||||
if (actual != null) {
|
if (actual != null) {
|
||||||
actualName = declarationToName.get(actual);
|
actualName = declarationToName.get(actual);
|
||||||
@@ -151,9 +155,31 @@ public class ExpectedResolveData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertNotNull(reference);
|
assertNotNull(reference);
|
||||||
assertEquals(
|
|
||||||
"Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",
|
if (expected instanceof JetParameter || actual instanceof JetParameter) {
|
||||||
expected, actual);
|
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()) {
|
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.PsiElement;
|
||||||
import com.intellij.psi.PsiMethod;
|
import com.intellij.psi.PsiMethod;
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
|
import junit.framework.Test;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.JetTestCaseBase;
|
import org.jetbrains.jet.JetTestCaseBase;
|
||||||
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
|
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
|
||||||
@@ -22,6 +23,14 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class JetResolveTest extends ExtensibleResolveTestCase {
|
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
|
@Override
|
||||||
protected ExpectedResolveData getExpectedResolveData() {
|
protected ExpectedResolveData getExpectedResolveData() {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
@@ -116,43 +125,62 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String getHomeDirectory() {
|
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 {
|
@Override
|
||||||
doTest("/resolve/Basic.jet", true, true);
|
public String getName() {
|
||||||
|
return "test" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testResolveToJava() throws Exception {
|
@Override
|
||||||
doTest("/resolve/ResolveToJava.jet", true, true);
|
protected void runTest() throws Throwable {
|
||||||
|
doTest(path, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testResolveOfInfixExpressions() throws Exception {
|
// public void testBasic() throws Exception {
|
||||||
doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
|
// 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 {
|
public static Test suite() {
|
||||||
doTest("/resolve/Projections.jet", true, true);
|
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