From 4071d67c41c6eb667120cddae8b527b7c301814f Mon Sep 17 00:00:00 2001 From: svtk Date: Mon, 12 Sep 2011 16:01:48 +0400 Subject: [PATCH 1/2] Added static checks for properties in traits; more tests for 'abstract' --- .../jet/lang/resolve/BodyResolver.java | 217 ++++++++++++----- .../jet/lang/resolve/TopDownAnalyzer.java | 4 + .../jet/lang/resolve/WritableScopeImpl.java | 2 +- idea/testData/checker/Abstract.jet | 225 ++++++++++++++---- idea/testData/checker/NamespaceQualified.jet | 4 +- idea/testData/checker/regression/Jet67.jet | 2 +- .../codegen/controlStructures/forUserType.jet | 1 + 7 files changed, 347 insertions(+), 108 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 71404fa4bb7..8214c46409e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -14,10 +14,7 @@ import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.slicedmap.WritableSlice; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; @@ -77,6 +74,8 @@ public class BodyResolver { resolveFunctionBodies(); checkIfPrimaryConstructorIsNecessary(); + + checkOverrides(); } private void bindOverrides() { @@ -88,35 +87,15 @@ public class BodyResolver { } } - protected void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { + private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) { for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { - JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); - assert function != null; - JetModifierList modifierList = function.getModifierList(); - ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; - boolean hasOverrideModifier = overrideNode != null; - boolean foundError = false; for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype); if (overridden != null) { - if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { - context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and can not be overridden"); - foundError = true; - } ((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden); } } - if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { - context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); - } - PsiElement nameIdentifier = function.getNameIdentifier(); - if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { - FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); - context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), - "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + - overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); - } } } @@ -130,12 +109,88 @@ public class BodyResolver { } return null; } + + private void checkOverrides() { + for (Map.Entry entry : context.getClasses().entrySet()) { + checkOverridesInAClass(entry.getValue(), entry.getKey()); + } + for (Map.Entry entry : context.getObjects().entrySet()) { + checkOverridesInAClass(entry.getValue(), entry.getKey()); + } + } + + protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { + checkOverrideForFunction(declaredFunction); + } + if (classDescriptor.getModality() == Modality.ABSTRACT) { + return; + } + Set allOverriddenFunctions = Sets.newHashSet(); + for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) { + for (FunctionDescriptor overriddenDescriptor : declaredFunction.getOverriddenDescriptors()) { + allOverriddenFunctions.add(overriddenDescriptor.getOriginal()); + } + } + boolean foundError = false; + PsiElement nameIdentifier = null; + if (klass instanceof JetClass) { + nameIdentifier = ((JetClass) klass).getNameIdentifier(); + } + else if (klass instanceof JetObjectDeclaration) { + nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier(); + } + for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { + Collection allDescriptors = supertype.getMemberScope().getAllDescriptors(); + for (DeclarationDescriptor descriptor : allDescriptors) { + if (descriptor instanceof FunctionDescriptor) { + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) { + DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor(); + assert declarationDescriptor != null; + context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" + + functionDescriptor.getName() + "' in " + declarationDescriptor.getName()); + foundError = true; + } + } + } + } + } + + private void checkOverrideForFunction(FunctionDescriptor declaredFunction) { + JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction); + assert function != null; + JetModifierList modifierList = function.getModifierList(); + ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null; + boolean hasOverrideModifier = overrideNode != null; + boolean foundError = false; + + for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) { + if (overridden != null) { + if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) { + context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden"); + foundError = true; + } + } + } + if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) { + context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing"); + } + PsiElement nameIdentifier = function.getNameIdentifier(); + if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) { + FunctionDescriptor overriddenMethod = declaredFunction.getOverriddenDescriptors().iterator().next(); + context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), + "Method " + declaredFunction.getName() + " overrides method " + overriddenMethod.getName() + " in class " + + overriddenMethod.getContainingDeclaration().getName() + " and needs 'override' modifier"); + } + } + private void checkIfPrimaryConstructorIsNecessary() { for (Map.Entry entry : context.getClasses().entrySet()) { MutableClassDescriptor classDescriptor = entry.getValue(); JetClass jetClass = entry.getKey(); - if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) { + if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) { for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { PsiElement nameIdentifier = jetClass.getNameIdentifier(); @@ -177,7 +232,7 @@ public class BodyResolver { @Override public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { if (descriptor.getKind() == ClassKind.TRAIT) { - context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); + context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Traits cannot use delegation"); } JetType supertype = context.getTrace().getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); recordSupertype(specifier.getTypeReference(), supertype); @@ -198,7 +253,7 @@ public class BodyResolver { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); if (descriptor.getKind() == ClassKind.TRAIT) { - context.getTrace().getErrorHandler().genericError(node, "Traits can not initialize supertypes"); + context.getTrace().getErrorHandler().genericError(node, "Traits cannot initialize supertypes"); } JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { @@ -455,10 +510,7 @@ public class BodyResolver { JetExpression initializer = property.getInitializer(); if (initializer != null) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - if (primaryConstructor == null) { - context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present"); - } - else { + if (primaryConstructor != null) { JetScope scope = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); resolvePropertyInitializer(property, propertyDescriptor, initializer, scope); } @@ -520,47 +572,77 @@ public class BodyResolver { } protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) { - JetExpression initializer = property.getInitializer(); + checkPropertyAbstractness(property, propertyDescriptor, classDescriptor); + checkPropertyInitializer(property, propertyDescriptor, classDescriptor); + } + + private void checkPropertyAbstractness(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) { JetPropertyAccessor getter = property.getGetter(); JetPropertyAccessor setter = property.getSetter(); - PsiElement nameIdentifier = property.getNameIdentifier(); - ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode(); - if (propertyDescriptor.getModality() == Modality.ABSTRACT) { + JetModifierList modifierList = property.getModifierList(); + ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; + + if (abstractNode != null) { //has abstract modifier if (classDescriptor == null) { - context.getTrace().getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Global property can not be abstract"); + context.getTrace().getErrorHandler().genericError(abstractNode, "This property cannot be abstract"); return; } - if (classDescriptor.getModality() != Modality.ABSTRACT) { - context.getTrace().getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), - "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); + if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) { + context.getTrace().getErrorHandler().genericError(abstractNode, "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); return; } + if (classDescriptor.getKind() == ClassKind.TRAIT) { + context.getTrace().getErrorHandler().genericWarning(abstractNode, "Abstract modifier is redundant in traits"); + } + } + + if (propertyDescriptor.getModality() == Modality.ABSTRACT) { + JetExpression initializer = property.getInitializer(); if (initializer != null) { - context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property with initializer can not be abstract"); + context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property with initializer cannot be abstract"); } if (getter != null && getter.getBodyExpression() != null) { - context.getTrace().getErrorHandler().genericError(getter.getNode(), "Property with getter implementation can not be abstract"); + context.getTrace().getErrorHandler().genericError(getter.getNode(), "Property with getter implementation cannot be abstract"); } if (setter != null && setter.getBodyExpression() != null) { - context.getTrace().getErrorHandler().genericError(setter.getNode(), "Property with setter implementation can not be abstract"); + context.getTrace().getErrorHandler().genericError(setter.getNode(), "Property with setter implementation cannot be abstract"); } - return; } + } + + private void checkPropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) { + boolean hasAccessorImplementation = (property.getGetter() != null && property.getGetter().getBodyExpression() != null) || + (property.getSetter() != null && property.getSetter().getBodyExpression() != null); + if (propertyDescriptor.getModality() == Modality.ABSTRACT) return; + + boolean inTrait = classDescriptor != null && classDescriptor.getKind() == ClassKind.TRAIT; + JetExpression initializer = property.getInitializer(); boolean backingFieldRequired = context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); - if (backingFieldRequired) { - if (initializer == null && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { - if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) { + + PsiElement nameIdentifier = property.getNameIdentifier(); + ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode(); + + if (inTrait && backingFieldRequired && hasAccessorImplementation) { + context.getTrace().getErrorHandler().genericError(nameNode, "Property in trait cannot have backing field"); + } + if (initializer == null) { + if (backingFieldRequired && !inTrait && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { + if (classDescriptor == null || hasAccessorImplementation) { context.getTrace().getErrorHandler().genericError(nameNode, "Property must be initialized"); - } else if (classDescriptor.getKind() != ClassKind.TRAIT) { + } else { context.getTrace().getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract"); } } + return; } - else { - if (initializer != null) { - context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Initializer is not allowed here because this property has no backing field"); - } + if (inTrait) { + context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed in trait"); + } + else if (!backingFieldRequired) { + context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Initializer is not allowed here because this property has no backing field"); + } + else if (classDescriptor != null && classDescriptor.getUnsubstitutedPrimaryConstructor() == null) { + context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present"); } } @@ -648,16 +730,17 @@ public class BodyResolver { DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration(); PsiElement nameIdentifier; JetModifierList modifierList; + boolean isPropertyAccessor = false; if (function instanceof JetNamedFunction) { JetNamedFunction namedFunction = (JetNamedFunction) function; nameIdentifier = namedFunction.getNameIdentifier(); modifierList = namedFunction.getModifierList(); } else if (function instanceof JetPropertyAccessor) { - return; -// JetPropertyAccessor propertyAccessor = (JetPropertyAccessor) function; -// nameIdentifier = propertyAccessor.getNamePlaceholder(); -// modifierList = propertyAccessor.getModifierList(); + isPropertyAccessor = true; + JetPropertyAccessor propertyAccessor = (JetPropertyAccessor) function; + nameIdentifier = propertyAccessor.getNamePlaceholder(); + modifierList = propertyAccessor.getModifierList(); } else { throw new UnsupportedOperationException(); @@ -669,24 +752,30 @@ public class BodyResolver { boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS; boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT; + String methodName = function.getName() != null ? function.getName() + " " : ""; if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) { - context.getTrace().getErrorHandler().genericError(abstractNode, "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); + context.getTrace().getErrorHandler().genericError(abstractNode, "Abstract method " + methodName + "in non-abstract class " + classDescriptor.getName()); } - if (hasAbstractModifier && inTrait) { - context.getTrace().getErrorHandler().genericWarning(abstractNode, "Abstract modifier is not necessary in traits"); + if (hasAbstractModifier && inTrait && !isPropertyAccessor) { + context.getTrace().getErrorHandler().genericWarning(abstractNode, "Abstract modifier is redundant in trait"); } if (function.getBodyExpression() != null && hasAbstractModifier) { - context.getTrace().getErrorHandler().genericError(abstractNode, "Method " + function.getName() + " with body can not be abstract"); + context.getTrace().getErrorHandler().genericError(abstractNode, "Method " + methodName + "with body cannot be abstract"); } - if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null) { + if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null && !isPropertyAccessor) { context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); } return; } if (hasAbstractModifier) { - context.getTrace().getErrorHandler().genericError(abstractNode, "Function " + function.getName() + " can not be abstract"); + if (!isPropertyAccessor) { + context.getTrace().getErrorHandler().genericError(abstractNode, "Function " + function.getName() + " cannot be abstract"); + } + else { + context.getTrace().getErrorHandler().genericError(abstractNode, "This property accessor cannot be abstract"); + } } - if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { + if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null && !isPropertyAccessor) { context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Function " + function.getName() + " must have body"); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 62fa5cf0008..47d569b259b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -83,6 +83,10 @@ public class TopDownAnalyzer { @Override protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) { } + + @Override + protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) { + } }; bodyResolver.resolveBehaviorDeclarationBodies(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java index a1a835e1ab2..e74280957d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java @@ -16,7 +16,7 @@ import java.util.*; */ public class WritableScopeImpl extends WritableScopeWithImports { - private final Collection allDescriptors = Sets.newHashSet(); + private final Collection allDescriptors = Sets.newLinkedHashSet(); private boolean allDescriptorsDone = false; @NotNull diff --git a/idea/testData/checker/Abstract.jet b/idea/testData/checker/Abstract.jet index 771ab3e0bc3..a004d179a5e 100644 --- a/idea/testData/checker/Abstract.jet +++ b/idea/testData/checker/Abstract.jet @@ -1,81 +1,226 @@ namespace abstract class MyClass() { + //properties + val a: Int + val a1: Int = 1 + abstract val a2: Int + abstract val a3: Int = 1 + + var b: Int private set + var b1: Int = 0; private set + abstract var b2: Int private set + abstract var b3: Int = 0; private set + + var c: Int set(v: Int) { $c = v } + var c1: Int = 0; set(v: Int) { $c1 = v } + abstract var c2: Int set(v: Int) { $c2 = v } + abstract var c3: Int = 0; set(v: Int) { $c3 = v } + + val e: Int get() = a + val e1: Int = 0; get() = a + abstract val e2: Int get() = a + abstract val e3: Int = 0; get() = a + + //methods fun f() fun g() {} abstract fun h() - abstract fun j() {} + abstract fun j() {} + + //property accessors + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set + + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set + + var k: Int abstract set + var k1: Int = 0; abstract set + + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set + + var n: Int abstract get abstract set(v: Int) {} } abstract class MyAbstractClass() { + //properties + val a: Int + val a1: Int = 1 + abstract val a2: Int + abstract val a3: Int = 1 + + var b: Int private set + var b1: Int = 0; private set + abstract var b2: Int private set + abstract var b3: Int = 0; private set + + var c: Int set(v: Int) { $c = v } + var c1: Int = 0; set(v: Int) { $c1 = v } + abstract var c2: Int set(v: Int) { $c2 = v } + abstract var c3: Int = 0; set(v: Int) { $c3 = v } + + val e: Int get() = a + val e1: Int = 0; get() = a + abstract val e2: Int get() = a + abstract val e3: Int = 0; get() = a + + //methods fun f() fun g() {} abstract fun h() abstract fun j() {} + + //property accessors + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set + + var j: Int get() = i; abstract set + var j1: Int get() = i; abstract set + + var k: Int abstract set + var k1: Int = 0; abstract set + + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set + + var n: Int abstract get abstract set(v: Int) {} } trait MyTrait { + //properties + val a: Int + val a1: Int = 1 + abstract val a2: Int + abstract val a3: Int = 1 + + var b: Int private set + var b1: Int = 0; private set + abstract var b2: Int private set + abstract var b3: Int = 0; private set + + var c: Int set(v: Int) { $c = v } + var c1: Int = 0; set(v: Int) { $c1 = v } + abstract var c2: Int set(v: Int) { $c2 = v } + abstract var c3: Int = 0; set(v: Int) { $c3 = v } + + val e: Int get() = a + val e1: Int = 0; get() = a + abstract val e2: Int get() = a + abstract val e3: Int = 0; get() = a + + //methods fun f() fun g() {} abstract fun h() abstract fun j() {} + + //property accessors + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set + + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set + + var k: Int abstract set + var k1: Int = 0; abstract set + + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set + + var n: Int abstract get abstract set(v: Int) {} } -enum class MyEnum { +enum class MyEnum() { + //properties + val a: Int + val a1: Int = 1 + abstract val a2: Int + abstract val a3: Int = 1 + + var b: Int private set + var b1: Int = 0; private set + abstract var b2: Int private set + abstract var b3: Int = 0; private set + + var c: Int set(v: Int) { $c = v } + var c1: Int = 0; set(v: Int) { $c1 = v } + abstract var c2: Int set(v: Int) { $c2 = v } + abstract var c3: Int = 0; set(v: Int) { $c3 = v } + + val e: Int get() = a + val e1: Int = 0; get() = a + abstract val e2: Int get() = a + abstract val e3: Int = 0; get() = a + + //methods fun f() fun g() {} abstract fun h() abstract fun j() {} + + //property accessors + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set + + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set + + var k: Int abstract set + var k1: Int = 0; abstract set + + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set + + var n: Int abstract get abstract set(v: Int) {} } -class A1() { - fun foo(): Int - abstract fun f(): Int -} +abstract enum class MyAbstractEnum() {} -abstract class A2() { - abstract fun f(): Int -} +namespace MyNamespace { + //properties + val a: Int + val a1: Int = 1 + abstract val a2: Int + abstract val a3: Int = 1 -class A3() { - val i: Int - val j: Int? - var k: String - var l: Int? -} + var b: Int private set + var b1: Int = 0; private set + abstract var b2: Int private set + abstract var b3: Int = 0; private set -class A4 { - val i: Int? -} + var c: Int set(v: Int) { $c = v } + var c1: Int = 0; set(v: Int) { $c1 = v } + abstract var c2: Int set(v: Int) { $c2 = v } + abstract var c3: Int = 0; set(v: Int) { $c3 = v } -class A5 { - var i: Int? -} + val e: Int get() = a + val e1: Int = 0; get() = a + abstract val e2: Int get() = a + abstract val e3: Int = 0; get() = a -class A6 { - abstract val i: Int -} + //methods + fun f() + fun g() {} + abstract fun h() + abstract fun j() {} -abstract class A7 { - abstract val i: Int //ok -} + //property accessors + var i: Int abstract get abstract set + var i1: Int = 0; abstract get abstract set -class A8() { - val i = 11 -} + var j: Int get() = i; abstract set + var j1: Int = 0; get() = i; abstract set -class A9() { - abstract val i = 23 -} + var k: Int abstract set + var k1: Int = 0; abstract set -abstract class A10 { - val i: Int -} + var l: Int abstract get abstract set + var l1: Int = 0; abstract get abstract set -abstract val i: Int -abstract fun foo(): fun(Int): Int -val j: Int -fun foo1(): fun(Int): Int + var n: Int abstract get abstract set(v: Int) {} +} //creating an instance abstract class B1( diff --git a/idea/testData/checker/NamespaceQualified.jet b/idea/testData/checker/NamespaceQualified.jet index 9c16c4de8de..120b3b73d34 100644 --- a/idea/testData/checker/NamespaceQualified.jet +++ b/idea/testData/checker/NamespaceQualified.jet @@ -39,7 +39,7 @@ class StrangeIterateeImpl(val obj: O) : Iteratee { override fun process(item: I): Iteratee = StrangeIterateeImpl(obj) override val isDone = true override val result = obj - override val done = obj + override fun done() = obj } abstract class Sum() : Iteratee { @@ -51,7 +51,7 @@ abstract class Sum() : Iteratee { abstract override fun done() : Int } -class Collection : Iterable { +abstract class Collection : Iterable { fun iterate(iteratee : Iteratee) : O { for (x in this) { val it = iteratee.process(x) diff --git a/idea/testData/checker/regression/Jet67.jet b/idea/testData/checker/regression/Jet67.jet index 13b000754e4..49a449094ec 100644 --- a/idea/testData/checker/regression/Jet67.jet +++ b/idea/testData/checker/regression/Jet67.jet @@ -1,4 +1,4 @@ -class XXX { +abstract class XXX { val a : Int abstract get } diff --git a/idea/testData/codegen/controlStructures/forUserType.jet b/idea/testData/codegen/controlStructures/forUserType.jet index b3aa1cff8a0..1d90ceee938 100644 --- a/idea/testData/codegen/controlStructures/forUserType.jet +++ b/idea/testData/codegen/controlStructures/forUserType.jet @@ -77,6 +77,7 @@ class MyCollection1(): java.lang.Iterable { override fun next() : Int = k-- override fun hasNext() = k > 0 + override fun remove() {} } } From b7542ecc4e943cf69645deedacd89c5445a1a18c Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 12 Sep 2011 18:01:39 +0300 Subject: [PATCH 2/2] fix for KT-299 --- .../jet/codegen/ExpressionCodegen.java | 4 ++-- idea/testData/codegen/regressions/kt299.jet | 17 +++++++++++++++++ .../jet/codegen/ControlStructuresTest.java | 4 ++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt299.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index df479228c83..f47fdb9b385 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1196,10 +1196,10 @@ public class ExpressionCodegen extends JetVisitor { getInIntRange(leftValue, rangeExpression, inverted); } else { - leftValue.put(JetTypeMapper.TYPE_OBJECT, v); + FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference()); + leftValue.put(typeMapper.mapType(op.getValueParameters().get(0).getOutType()), v); genToJVMStack(expression.getRight()); v.swap(); - FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference()); invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v); } return StackValue.onStack(Type.BOOLEAN_TYPE); diff --git a/idea/testData/codegen/regressions/kt299.jet b/idea/testData/codegen/regressions/kt299.jet new file mode 100644 index 00000000000..4aa31a44dc8 --- /dev/null +++ b/idea/testData/codegen/regressions/kt299.jet @@ -0,0 +1,17 @@ +class MyRange1() : Range { + override fun contains(item: Int) = true +} + +class MyRange2() { + fun contains(item: Int) = true +} + +fun box(): String { + if (1 in MyRange1()) { + if (1 in MyRange2()) { + return "OK" + } + return "fail 2" + } + return "fail 1" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 47abe0a954c..2e93fc8b561 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -177,4 +177,8 @@ public class ControlStructuresTest extends CodegenTestCase { assertEquals(true, main.invoke(null, null, "lala")); assertEquals(false, main.invoke(null, "papa", "papa")); } + + public void testKt299() throws Exception { + blackBoxFile("regressions/kt299.jet"); + } }