KT-286 Check supertype lists (in progress)

Tests involving multiple inheritance fixed
This commit is contained in:
Andrey Breslav
2011-09-08 15:34:05 +04:00
parent 5cb298c093
commit 71bc41a938
22 changed files with 189 additions and 78 deletions
+5 -5
View File
@@ -40,12 +40,12 @@ fun Any?.equals(other : Any?) : Boolean// = this === other
// Returns "null" for null // Returns "null" for null
fun Any?.toString() : String// = this === other fun Any?.toString() : String// = this === other
class Iterator<out T> { trait class Iterator<out T> {
fun next() : T fun next() : T
abstract fun hasNext() : Boolean abstract fun hasNext() : Boolean
} }
class Iterable<out T> { trait class Iterable<out T> {
fun iterator() : Iterator<T> fun iterator() : Iterator<T>
} }
@@ -56,11 +56,11 @@ class Array<T>(val size : Int) {
fun iterator() : Iterator<T> fun iterator() : Iterator<T>
} }
virtual class Comparable<in T> { trait class Comparable<in T> {
fun compareTo(other : T) : Int fun compareTo(other : T) : Int
} }
virtual class Hashable { trait class Hashable {
fun hashCode() : Int fun hashCode() : Int
fun equals(other : Any?) : Boolean fun equals(other : Any?) : Boolean
} }
@@ -92,7 +92,7 @@ class String() : Comparable<String> {
fun trim(): String fun trim(): String
} }
class Range<in T : Comparable<T>> { trait class Range<in T : Comparable<T>> {
fun contains(item : T) : Boolean fun contains(item : T) : Boolean
} }
@@ -606,21 +606,26 @@ public class TopDownAnalyzer {
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
final JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow final JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
JetVisitorVoid visitor = new JetVisitorVoid() { JetVisitorVoid visitor = new JetVisitorVoid() {
private boolean superclassAppeared = false; private void recordSupertype(JetTypeReference typeReference, JetType supertype) {
if (supertype == null) return;
supertypes.put(typeReference, supertype);
}
@Override @Override
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
if (descriptor.getClassModifiers().isTrait()) { if (descriptor.getClassModifiers().isTrait()) {
trace.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); trace.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation");
} }
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
recordSupertype(specifier.getTypeReference(), supertype);
JetExpression delegateExpression = specifier.getDelegateExpression(); JetExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) { if (delegateExpression != null) {
JetScope scope = scopeForConstructor == null JetScope scope = scopeForConstructor == null
? descriptor.getScopeForMemberResolution() ? descriptor.getScopeForMemberResolution()
: scopeForConstructor; : scopeForConstructor;
JetType type = typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE); JetType type = typeInferrer.getType(scope, delegateExpression, NO_EXPECTED_TYPE);
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
if (type != null && supertype != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { if (type != null && supertype != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) {
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type); trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
} }
@@ -629,27 +634,32 @@ public class TopDownAnalyzer {
@Override @Override
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
if (descriptor.getClassModifiers().isTrait()) { JetValueArgumentList valueArgumentList = call.getValueArgumentList();
JetValueArgumentList valueArgumentList = call.getValueArgumentList(); ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); if (descriptor.isTrait()) {
trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes"); trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes");
} }
JetTypeReference typeReference = call.getTypeReference(); JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) { if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
JetType type = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE); JetType supertype = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE);
if (type != null) { if (supertype != null) {
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); recordSupertype(typeReference, supertype);
if (declarationDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; if (classDescriptor != null) {
if (classDescriptor.getClassModifiers().isTrait()) { if (classDescriptor.isTrait()) {
trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "A trait may not have a constructor"); trace.getErrorHandler().genericError(node, "A trait may not have a constructor");
} }
} }
} }
else {
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
}
} }
else { else if (!descriptor.isTrait()) {
JetValueArgumentList valueArgumentList = call.getValueArgumentList(); JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype);
assert valueArgumentList != null; assert valueArgumentList != null;
trace.getErrorHandler().genericError(valueArgumentList.getNode(), trace.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");
@@ -659,31 +669,18 @@ public class TopDownAnalyzer {
@Override @Override
public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); JetTypeReference typeReference = specifier.getTypeReference();
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype);
if (supertype != null) { if (supertype != null) {
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor(); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (declarationDescriptor instanceof ClassDescriptor) { if (classDescriptor != null) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; if (!descriptor.isTrait()) {
if (!descriptor.getClassModifiers().isTrait()) { if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.isTrait()) {
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getClassModifiers().isTrait()) {
trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here"); trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here");
} }
} }
else {
if (!classDescriptor.getClassModifiers().isTrait()) {
if (superclassAppeared) {
trace.getErrorHandler().genericError(specifier.getNode(), "A trait may extend only one class");
}
else {
superclassAppeared = true;
}
}
}
} }
else {
trace.getErrorHandler().genericError(specifier.getNode(), "Only classes may serve as supertypes");
}
} }
} }
@@ -697,9 +694,52 @@ public class TopDownAnalyzer {
throw new UnsupportedOperationException(element.getText() + " : " + element); throw new UnsupportedOperationException(element.getText() + " : " + element);
} }
}; };
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) { for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
delegationSpecifier.accept(visitor); delegationSpecifier.accept(visitor);
} }
Set<TypeConstructor> parentEnum = Collections.emptySet();
if (jetClass instanceof JetEnumEntry) {
parentEnum = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration()).getTypeConstructor());
}
checkSupertypeList(descriptor, supertypes, parentEnum);
}
// allowedFinalSupertypes typically contains a enum type of which supertypeOwner is an entry
private void checkSupertypeList(@NotNull MutableClassDescriptor supertypeOwner, @NotNull Map<JetTypeReference, JetType> supertypes, Set<TypeConstructor> allowedFinalSupertypes) {
Set<TypeConstructor> typeConstructors = Sets.newHashSet();
boolean classAppeared = false;
for (Map.Entry<JetTypeReference, JetType> entry : supertypes.entrySet()) {
JetTypeReference typeReference = entry.getKey();
JetType supertype = entry.getValue();
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (!classDescriptor.isTrait()) {
if (classAppeared) {
trace.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list");
}
else {
classAppeared = true;
}
}
}
else {
trace.getErrorHandler().genericError(typeReference.getNode(), "Only classes and traits may serve as supertypes");
}
TypeConstructor constructor = supertype.getConstructor();
if (!typeConstructors.add(constructor)) {
trace.getErrorHandler().genericError(typeReference.getNode(), "A supertype appears twice");
}
if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) {
trace.getErrorHandler().genericError(typeReference.getNode(), "This type is final, so it cannot be inherited from");
}
}
} }
private void resolveClassAnnotations() { private void resolveClassAnnotations() {
@@ -253,7 +253,6 @@ public class CallResolver {
} }
if (traceForFirstNonemptyCandidateSet != null) { if (traceForFirstNonemptyCandidateSet != null) {
traceForFirstNonemptyCandidateSet.commit(); traceForFirstNonemptyCandidateSet.commit();
assert resultForFirstNonemptyCandidateSet != null;
if (resultForFirstNonemptyCandidateSet.singleDescriptor()) { if (resultForFirstNonemptyCandidateSet.singleDescriptor()) {
return resultForFirstNonemptyCandidateSet.getDescriptor(); return resultForFirstNonemptyCandidateSet.getDescriptor();
} }
@@ -321,6 +321,15 @@ public class TypeUtils {
return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal()); return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
} }
@Nullable
public static ClassDescriptor getClassDescriptor(@NotNull JetType type) {
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
return (ClassDescriptor) declarationDescriptor;
}
return null;
}
public static boolean hasUnsubstitutedTypeParameters(JetType type) { public static boolean hasUnsubstitutedTypeParameters(JetType type) {
if(type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) if(type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor)
return true; return true;
+1 -1
View File
@@ -49,7 +49,7 @@ namespace html {
class Title() : TagWithText("title") class Title() : TagWithText("title")
class BodyTag(name : String) : TagWithText(name) { abstract class BodyTag(name : String) : TagWithText(name) {
} }
class Body() : BodyTag("body") { class Body() : BodyTag("body") {
+2 -2
View File
@@ -1,9 +1,9 @@
class NoC open class NoC
class NoC1 : NoC class NoC1 : NoC
class WithC0() : NoC<error>()</error> class WithC0() : NoC<error>()</error>
class WithC1() : NoC open class WithC1() : NoC
class NoC2 : <error>WithC1</error> class NoC2 : <error>WithC1</error>
class NoC3 : WithC1<error>()</error> class NoC3 : WithC1<error>()</error>
class WithC2() : <error>WithC1</error> class WithC2() : <error>WithC1</error>
+4 -4
View File
@@ -4,14 +4,14 @@ open class A() {
fun foo() : Int = 1 fun foo() : Int = 1
} }
open class B() { trait class B {
fun bar() : Double = 1.0; fun bar() : Double = 1.0;
} }
class C() : A(), B() class C() : A(), B
class D() { class D() {
class object : A(), B () {} class object : A(), B {}
} }
class Test1<T : A>() class Test1<T : A>()
@@ -61,7 +61,7 @@ fun <T : A> test2(t : T)
} }
val t1 = test2<<error>A</error>>(A()) val t1 = test2<<error>A</error>>(A())
val t2 = test2<<error>B</error>>(B()) val t2 = test2<<error>B</error>>(C())
val t3 = test2<C>(C()) val t3 = test2<C>(C())
class Test<<error>T</error>> class Test<<error>T</error>>
+2 -2
View File
@@ -1,5 +1,5 @@
namespace toplevelObjectDeclarations { namespace toplevelObjectDeclarations {
class Foo(y : Int) { open class Foo(y : Int) {
virtual fun foo() : Int = 1 virtual fun foo() : Int = 1
} }
@@ -63,7 +63,7 @@ namespace localObjects {
val x : Int = 0 val x : Int = 0
} }
class Foo { open class Foo {
fun foo() : Int = 1 fun foo() : Int = 1
} }
@@ -2,7 +2,7 @@ class <error>X</error> {
val <error>x</error> : Int val <error>x</error> : Int
} }
class Y() { open class Y() {
val x : Int = 2 val x : Int = 2
} }
@@ -0,0 +1,51 @@
// KT-286 Check supertype lists
/*
In a supertype list:
Same type should not be mentioned twice
Same type should not be indirectly mentioned with incoherent type arguments
Every trait's required dependencies should be satisfied
No final types should appear
Only one class is allowed
*/
class C1()
open class OC1()
open class C2 {}
open class C3 {}
trait class T1 {}
trait class T2<T> {}
trait class Test<error>()</error> {
<error>this</error>(x : Int) {}
}
trait class Test1 : C2<error>()</error> {}
trait class Test2 : C2 {}
trait class Test3 : C2, <error>C3</error> {}
trait class Test4 : T1 {}
trait class Test5 : T1, <error>T1</error> {}
trait class Test6 : <error>C1</error> {}
class CTest1() : OC1() {}
class CTest2 : C2 {}
class CTest3 : C2, <error>C3</error> {}
class CTest4 : T1 {}
class CTest5 : T1, <error>T1</error> {}
class CTest6 : <error>C1</error> {}
+3 -3
View File
@@ -1,11 +1,11 @@
class bar() open class bar()
trait open class Foo<error>()</error> : bar<error>()</error>, bar, <error>bar</error> { trait open class Foo<error>()</error> : bar<error>()</error>, <error>bar</error>, <error>bar</error> {
<error>this</error>(x : Int) {} <error>this</error>(x : Int) {}
} }
trait open class Foo2 : bar, Foo { trait open class Foo2 : bar, Foo {
} }
open class Foo1() : bar(), <error>bar</error>, Foo, Foo<error>()</error> {} open class Foo1() : bar(), <error>bar</error>, Foo, <error>Foo</error><error>()</error> {}
open class Foo12 : bar<error>()</error>, <error>bar</error> {} open class Foo12 : bar<error>()</error>, <error>bar</error> {}
+1 -1
View File
@@ -1,4 +1,4 @@
class A() { <info>open</info> class A() {
fun foo() {} fun foo() {}
} }
+2 -2
View File
@@ -1,4 +1,4 @@
// JET-11 Redeclaration & Forward reference for classes cause an exception // JET-11 Redeclaration & Forward reference for classes cause an exception
class <error>NoC</error> open class <error>NoC</error>
class NoC1 : NoC class NoC1 : NoC
class <error>NoC</error> open class <error>NoC</error>
+1 -1
View File
@@ -1,6 +1,6 @@
import java.lang.Integer import java.lang.Integer
class C { open class C {
fun f(): Any = "C f" fun f(): Any = "C f"
} }
@@ -1,11 +1,13 @@
class Base() { // Changed when traits were introduced. May not make sense any more
open class Base() {
public var v : Int = 0 public var v : Int = 0
} }
class Left() : Base() {} open class Left() : Base() {}
class Right() : Base() {} trait class Right : Base {}
class D() : Left(), Right() class D() : Left(), Right
fun vl(l : Left) : Int = l.v fun vl(l : Left) : Int = l.v
fun vr(r : Right) : Int = r.v fun vr(r : Right) : Int = r.v
@@ -1,8 +1,8 @@
class Base() { open class Base() {
fun n(n : Int) : Int = n + 1 fun n(n : Int) : Int = n + 1
} }
class Abstract {} trait class Abstract {}
class Derived1() : Base(), Abstract {} class Derived1() : Base(), Abstract {}
class Derived2() : Abstract, Base() {} class Derived2() : Abstract, Base() {}
+14 -6
View File
@@ -1,9 +1,17 @@
class X(val x : Int) {} // Changed when traits were introduced. May not make sense any more
class Y(val y : Int) {}
class Point(x : Int, y : Int) : X(x) , Y(y) {} open class X(val x : Int) {}
trait class Y {
abstract val y : Int
}
class Abstract {} class YImpl(val y : Int) : Y {}
class Point(x : Int, yy : Int) : X(x) , Y {
override val y : Int = yy
}
trait class Abstract {}
class P1(x : Int, yy : Y) : Abstract, X(x), Y by yy {} class P1(x : Int, yy : Y) : Abstract, X(x), Y by yy {}
class P2(x : Int, yy : Y) : X(x), Abstract, Y by yy {} class P2(x : Int, yy : Y) : X(x), Abstract, Y by yy {}
@@ -12,12 +20,12 @@ class P4(x : Int, yy : Y) : Y by yy, Abstract, X(x) {}
fun box() : String { fun box() : String {
if (X(239).x != 239) return "FAIL #1" if (X(239).x != 239) return "FAIL #1"
if (Y(239).y != 239) return "FAIL #2" if (YImpl(239).y != 239) return "FAIL #2"
val p = Point(240, -1) val p = Point(240, -1)
if (p.x + p.y != 239) return "FAIL #3" if (p.x + p.y != 239) return "FAIL #3"
val y = Y(-1) val y = YImpl(-1)
val p1 = P1(240, y) val p1 = P1(240, y)
if (p1.x + p1.y != 239) return "FAIL #4" if (p1.x + p1.y != 239) return "FAIL #4"
val p2 = P2(240, y) val p2 = P2(240, y)
@@ -1,5 +1,5 @@
class Outer() { class Outer() {
class InnerBase() { open class InnerBase() {
} }
class InnerDerived(): InnerBase() { class InnerDerived(): InnerBase() {
@@ -1,4 +1,4 @@
class Foo { open class Foo {
fun xyzzy(): String = "xyzzy" fun xyzzy(): String = "xyzzy"
} }
@@ -1,4 +1,4 @@
class Base() { open class Base() {
public val plain = 239 public val plain = 239
public val read : Int public val read : Int
get() = 239 get() = 239
@@ -10,7 +10,7 @@ class Base() {
} }
} }
class Abstract {} trait class Abstract {}
class Derived1() : Base(), Abstract {} class Derived1() : Base(), Abstract {}
class Derived2() : Abstract, Base() {} class Derived2() : Abstract, Base() {}
@@ -1,7 +1,7 @@
class Outer() { class Outer() {
public val s = "xyzzy" public val s = "xyzzy"
class InnerBase(public val name: String) { open class InnerBase(public val name: String) {
} }
class InnerDerived(): InnerBase(s) { class InnerDerived(): InnerBase(s) {
@@ -1,9 +1,11 @@
class Left() {} // Changed when traits were introduced. May not make sense any more
class Right() {
trait class Left {}
open class Right() {
virtual fun f() = 42 virtual fun f() = 42
} }
class D() : Left(), Right() { class D() : Left, Right() {
override fun f() = 239 override fun f() = 239
} }