JET-6 Perform checks for primary and secondary constructors (In progress): class having a stateful property must have a constructor
This commit is contained in:
@@ -63,6 +63,11 @@ public class JetSemanticServices {
|
||||
|
||||
@NotNull
|
||||
public WritableScope createWritableScope(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner) {
|
||||
return new WritableScopeImpl(scope, owner, errorHandler);
|
||||
return new WritableScopeImpl(scope, owner, errorHandler, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WritableScope createWritableScope(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull DeclarationDescriptorVisitor<?, ? super WritableScope> modificationListener) {
|
||||
return new WritableScopeImpl(scope, owner, errorHandler, modificationListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
@@ -7,14 +8,16 @@ import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor {
|
||||
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
|
||||
private final WritableScope classHeaderScope;
|
||||
private final WritableScope writableMemberScope;
|
||||
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
|
||||
private final Set<PropertyDescriptor> properties = Sets.newHashSet();
|
||||
private ConstructorDescriptor primaryConstructor;
|
||||
|
||||
private TypeConstructor typeConstructor;
|
||||
@@ -23,7 +26,13 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
||||
public MutableClassDescriptor(@NotNull JetSemanticServices semanticServices, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) {
|
||||
super(containingDeclaration);
|
||||
this.classHeaderScope = semanticServices.createWritableScope(outerScope, this);
|
||||
this.writableMemberScope = semanticServices.createWritableScope(classHeaderScope, this);
|
||||
this.writableMemberScope = semanticServices.createWritableScope(classHeaderScope, this, new DeclarationDescriptorVisitor<Void, WritableScope>() {
|
||||
@Override
|
||||
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, WritableScope data) {
|
||||
properties.add(descriptor);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.unsubstitutedMemberScope = this.writableMemberScope;
|
||||
}
|
||||
|
||||
@@ -48,6 +57,10 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
||||
this.typeConstructor = typeConstructor;
|
||||
}
|
||||
|
||||
public Set<PropertyDescriptor> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
@@ -312,6 +313,23 @@ public class TopDownAnalyzer {
|
||||
|
||||
resolveSecondaryConstructorBodies();
|
||||
resolveFunctionBodies();
|
||||
|
||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
|
||||
MutableClassDescriptor classDescriptor = entry.getValue();
|
||||
JetClass jetClass = entry.getKey();
|
||||
if (!jetClass.hasPrimaryConstructor()) {
|
||||
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
|
||||
if (trace.hasBackingField(propertyDescriptor)) {
|
||||
PsiElement nameIdentifier = jetClass.getNameIdentifier();
|
||||
if (nameIdentifier != null) {
|
||||
semanticServices.getErrorHandler().genericError(nameIdentifier.getNode(),
|
||||
"This class must have a primary constructor, because property " + propertyDescriptor.getName() + " has a backing field");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveDelegationSpecifierLists() {
|
||||
|
||||
@@ -34,10 +34,14 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
@Nullable
|
||||
private JetType thisType;
|
||||
|
||||
public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull ErrorHandler errorHandler) {
|
||||
@Nullable
|
||||
private final DeclarationDescriptorVisitor<?, ? super WritableScopeImpl> modificationListener;
|
||||
|
||||
public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull ErrorHandler errorHandler, @Nullable DeclarationDescriptorVisitor<?, ? super WritableScopeImpl> modificationListener) {
|
||||
super(scope);
|
||||
this.ownerDeclarationDescriptor = owner;
|
||||
this.errorHandler = errorHandler;
|
||||
this.modificationListener = modificationListener;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -46,6 +50,12 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
return ownerDeclarationDescriptor;
|
||||
}
|
||||
|
||||
private void notifyListeners(DeclarationDescriptor descriptor) {
|
||||
if (modificationListener != null) {
|
||||
descriptor.accept(modificationListener, this);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<String, List<DeclarationDescriptor>> getLabelsToDescriptors() {
|
||||
if (labelsToDescriptors == null) {
|
||||
@@ -80,6 +90,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
labelsToDescriptors.put(name, declarationDescriptors);
|
||||
}
|
||||
declarationDescriptors.add(descriptor);
|
||||
notifyListeners(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -99,6 +110,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
}
|
||||
// TODO : Should this always happen?
|
||||
propertyDescriptors.put(variableDescriptor.getName(), variableDescriptor);
|
||||
notifyListeners(variableDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,6 +155,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
functionGroups.put(name, functionGroup);
|
||||
}
|
||||
functionGroup.addFunction(functionDescriptor);
|
||||
notifyListeners(functionDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,6 +187,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
errorHandler.redeclaration(originalDescriptor, typeParameterDescriptor);
|
||||
}
|
||||
classifierDescriptors.put(name, typeParameterDescriptor);
|
||||
notifyListeners(typeParameterDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -197,6 +211,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
errorHandler.redeclaration(originalDescriptor, classifierDescriptor);
|
||||
}
|
||||
classifierDescriptors.put(name, classifierDescriptor);
|
||||
notifyListeners(classifierDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -239,6 +254,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
if (oldValue != null) {
|
||||
errorHandler.redeclaration(oldValue, namespaceDescriptor);
|
||||
}
|
||||
notifyListeners(namespaceDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -285,6 +301,7 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
||||
@Override
|
||||
public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor);
|
||||
notifyListeners(propertyDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -168,7 +168,7 @@ public class JetStandardClasses {
|
||||
/*package*/ static final JetScope STANDARD_CLASSES;
|
||||
|
||||
static {
|
||||
WritableScope writableScope = new WritableScopeImpl(JetScope.EMPTY, STANDARD_CLASSES_NAMESPACE, ErrorHandler.DO_NOTHING);
|
||||
WritableScope writableScope = new WritableScopeImpl(JetScope.EMPTY, STANDARD_CLASSES_NAMESPACE, ErrorHandler.DO_NOTHING, null);
|
||||
STANDARD_CLASSES = writableScope;
|
||||
writableScope.addClassifierAlias("Unit", getTuple(0));
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class WithCPI(x : Int) {
|
||||
val xy : Int = x
|
||||
}
|
||||
|
||||
class NoCPI {
|
||||
class <error>NoCPI</error> {
|
||||
val a = <error>1</error>
|
||||
var ab = <error>1</error>
|
||||
get() = 1
|
||||
|
||||
@@ -35,7 +35,7 @@ class NotRange5() {
|
||||
|
||||
class AmbiguousHasNextIterator {
|
||||
fun hasNext() : Boolean
|
||||
val hasNext : Boolean
|
||||
val hasNext : Boolean get() = false
|
||||
fun next() : Int
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class NotRange6() {
|
||||
}
|
||||
|
||||
class ImproperIterator4 {
|
||||
val hasNext : Int
|
||||
val hasNext : Int get() = 1
|
||||
fun next() : Int
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class Iteratee<in I, out O> {
|
||||
abstract fun done() : O
|
||||
}
|
||||
|
||||
class Sum : Iteratee<Int, Int> {
|
||||
class Sum() : Iteratee<Int, Int> {
|
||||
override fun process(item : Int) : Iteratee<Int, Int> {
|
||||
return foobar.done<Int>(item);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
class <error>X</error> {
|
||||
val x : Int
|
||||
}
|
||||
|
||||
class Y() {
|
||||
val x : Int
|
||||
}
|
||||
|
||||
class Y1 {
|
||||
val x : Int get() = 1
|
||||
}
|
||||
|
||||
class Z : Y<error>()</error> {
|
||||
}
|
||||
Reference in New Issue
Block a user