From 4e24405beabf0ebf84dff93249e641d98f676dd2 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 26 Apr 2011 20:20:30 +0400 Subject: [PATCH] JET-16 Check property initializers as parts of the primary constructor's body --- .../jet/lang/annotations/JetPsiChecker.java | 5 +++ .../jet/lang/resolve/BindingTraceContext.java | 33 ++++++++++++------- .../jet/lang/resolve/TopDownAnalyzer.java | 29 ++++++++++++---- .../jet/lang/types/BindingTrace.java | 4 +-- .../jet/lang/types/BindingTraceAdapter.java | 4 +-- .../types/DeclarationDescriptorVisitor.java | 18 ++++++---- 6 files changed, 65 insertions(+), 28 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index 2e0a78b412d..7aebda2d7ff 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -107,6 +107,11 @@ public class JetPsiChecker implements Annotator { } } +// @Override +// public void visitParameter(JetParameter parameter) { +// bindingContext.get +// } + @Override public void visitJetElement(JetElement elem) { elem.acceptChildren(this); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index b31ef953c21..5ffed1525b0 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.collect.Maps; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,9 +23,10 @@ public class BindingTraceContext implements BindingContext, BindingTrace { private final Map descriptorToDeclarations = new HashMap(); private final Map declarationsToDescriptors = new HashMap(); private final Map constructorDeclarationsToDescriptors = new HashMap(); + private final Map propertyDeclarationsToDescriptors = Maps.newHashMap(); private final Set blocks = new HashSet(); private final Set statements = new HashSet(); - private final Set fieldMentionedInAccessor = new HashSet(); + private final Set backingFieldRequired = new HashSet(); private JetScope toplevelScope; @@ -58,23 +60,32 @@ public class BindingTraceContext implements BindingContext, BindingTrace { @Override public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration); - if (descriptor instanceof ConstructorDescriptor) { - safePut(constructorDeclarationsToDescriptors, declaration, (ConstructorDescriptor) descriptor); - } - else { - safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); - } + descriptor.accept(new DeclarationDescriptorVisitor() { + @Override + public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, PsiElement declaration) { + safePut(constructorDeclarationsToDescriptors, declaration, constructorDescriptor); + return null; + } + + + + @Override + public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) { + safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); + return null; + } + }, declaration); } private void safePut(Map map, K key, V value) { V oldValue = map.put(key, value); // TODO: -// assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; + assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; } @Override - public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { - fieldMentionedInAccessor.add(propertyDescriptor); + public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) { + backingFieldRequired.add(propertyDescriptor); } @Override @@ -195,6 +206,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace { else if (!getter.hasBody()) { return true; } - return fieldMentionedInAccessor.contains(propertyDescriptor); + return backingFieldRequired.contains(propertyDescriptor); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index c24d579b78e..dbfbf1483b7 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -28,6 +28,7 @@ public class TopDownAnalyzer { private final Map properties = new LinkedHashMap(); private final Map declaringScopes = new HashMap(); private final Multimap declaringScopesToProperties = ArrayListMultimap.create(); + private final Set primaryConstructorParameterProperties = Sets.newHashSet(); private final JetSemanticServices semanticServices; private final ClassDescriptorResolver classDescriptorResolver; @@ -35,6 +36,7 @@ public class TopDownAnalyzer { private final JetControlFlowDataTraceFactory flowDataTraceFactory; private boolean readyToProcessExpressions = false; private final BindingTraceAdapter traceForConstructors; + private final BindingTraceAdapter traceForMembers; public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { this.semanticServices = semanticServices; @@ -43,7 +45,7 @@ public class TopDownAnalyzer { this.flowDataTraceFactory = flowDataTraceFactory; // This allows access to backing fields - this.traceForConstructors = new BindingTraceAdapter(trace) { + this.traceForConstructors = new BindingTraceAdapter(bindingTrace) { @Override public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { super.recordReferenceResolution(expression, descriptor); @@ -57,6 +59,20 @@ public class TopDownAnalyzer { } } }; + + // This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9) + this.traceForMembers = new BindingTraceAdapter(bindingTrace) { + @Override + public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { + super.recordReferenceResolution(expression, descriptor); + if (descriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (primaryConstructorParameterProperties.contains(propertyDescriptor)) { + requireBackingField(propertyDescriptor); + } + } + } + }; } public TopDownAnalyzer(JetSemanticServices semanticServices, @NotNull BindingTraceContext bindingTrace) { @@ -242,13 +258,14 @@ public class TopDownAnalyzer { WritableScope memberScope = classDescriptor.getWritableUnsubstitutedMemberScope(); // TODO : this is REALLY questionable ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass); for (JetParameter parameter : klass.getPrimaryConstructorParameters()) { - VariableDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( + PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePrimaryConstructorParameterToAProperty( classDescriptor, memberScope, parameter ); memberScope.addVariableDescriptor( propertyDescriptor); + primaryConstructorParameterProperties.add(propertyDescriptor); } if (constructorDescriptor != null) { classDescriptor.setPrimaryConstructor(constructorDescriptor); @@ -552,7 +569,7 @@ public class TopDownAnalyzer { } private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { - return new BindingTraceAdapter(trace) { + return new BindingTraceAdapter(traceForMembers) { @Override public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) { super.recordReferenceResolution(expression, descriptor); @@ -561,7 +578,7 @@ public class TopDownAnalyzer { if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { // This check may be considered redundant as long as $x is only accessible from accessors to $x if (descriptor == propertyDescriptor) { // TODO : original? - recordFieldAccessFromAccessor(propertyDescriptor); + requireBackingField(propertyDescriptor); } } } @@ -571,7 +588,7 @@ public class TopDownAnalyzer { private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); // TODO : flow JET-15 - JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider); + JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); JetType type = typeInferrer.getType(scope, initializer, false); JetType expectedType; @@ -599,7 +616,7 @@ public class TopDownAnalyzer { WritableScope declaringScope = declaringScopes.get(declaration); assert declaringScope != null; - resolveFunctionBody(trace, (JetFunction) declaration, (FunctionDescriptorImpl) descriptor, declaringScope); + resolveFunctionBody(traceForMembers, (JetFunction) declaration, (FunctionDescriptorImpl) descriptor, declaringScope); assert descriptor.getUnsubstitutedReturnType() != null; } diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index a5b764f374d..13688a8cb52 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -52,7 +52,7 @@ public interface BindingTrace { } @Override - public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { + public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) { } }; @@ -76,5 +76,5 @@ public interface BindingTrace { public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression); - public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor); + public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor); } diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java b/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java index 30ddaca36f4..1a250a5cac8 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java @@ -53,8 +53,8 @@ public class BindingTraceAdapter implements BindingTrace { } @Override - public void recordFieldAccessFromAccessor(@NotNull PropertyDescriptor propertyDescriptor) { - originalTrace.recordFieldAccessFromAccessor(propertyDescriptor); + public void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor) { + originalTrace.requireBackingField(propertyDescriptor); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorVisitor.java b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorVisitor.java index 91c417de0c8..ec5eeb73f06 100644 --- a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorVisitor.java @@ -4,28 +4,32 @@ package org.jetbrains.jet.lang.types; * @author abreslav */ public class DeclarationDescriptorVisitor { - public R visitVariableDescriptor(VariableDescriptor descriptor, D data) { + public R visitDeclarationDescriptor(DeclarationDescriptor descriptor, D data) { return null; } + public R visitVariableDescriptor(VariableDescriptor descriptor, D data) { + return visitDeclarationDescriptor(descriptor, data); + } + public R visitFunctionDescriptor(FunctionDescriptor descriptor, D data) { - return null; + return visitDeclarationDescriptor(descriptor, data); } public R visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) { - return null; + return visitDeclarationDescriptor(descriptor, data); } - public R visitNamespaceDescriptor(NamespaceDescriptor namespaceDescriptor, D data) { - return null; + public R visitNamespaceDescriptor(NamespaceDescriptor descriptor, D data) { + return visitDeclarationDescriptor(descriptor, data); } public R visitClassDescriptor(ClassDescriptor descriptor, D data) { - return null; + return visitDeclarationDescriptor(descriptor, data); } public R visitModuleDeclaration(ModuleDescriptor descriptor, D data) { - return null; + return visitDeclarationDescriptor(descriptor, data); } public R visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, D data) {