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
fun Any?.toString() : String// = this === other
class Iterator<out T> {
trait class Iterator<out T> {
fun next() : T
abstract fun hasNext() : Boolean
}
class Iterable<out T> {
trait class Iterable<out T> {
fun iterator() : Iterator<T>
}
@@ -56,11 +56,11 @@ class Array<T>(val size : Int) {
fun iterator() : Iterator<T>
}
virtual class Comparable<in T> {
trait class Comparable<in T> {
fun compareTo(other : T) : Int
}
virtual class Hashable {
trait class Hashable {
fun hashCode() : Int
fun equals(other : Any?) : Boolean
}
@@ -92,7 +92,7 @@ class String() : Comparable<String> {
fun trim(): String
}
class Range<in T : Comparable<T>> {
trait class Range<in T : Comparable<T>> {
fun contains(item : T) : Boolean
}
@@ -606,21 +606,26 @@ public class TopDownAnalyzer {
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
final JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
JetVisitorVoid visitor = new JetVisitorVoid() {
private boolean superclassAppeared = false;
private void recordSupertype(JetTypeReference typeReference, JetType supertype) {
if (supertype == null) return;
supertypes.put(typeReference, supertype);
}
@Override
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
if (descriptor.getClassModifiers().isTrait()) {
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();
if (delegateExpression != null) {
JetScope scope = scopeForConstructor == null
? descriptor.getScopeForMemberResolution()
: scopeForConstructor;
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)) {
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
}
@@ -629,27 +634,32 @@ public class TopDownAnalyzer {
@Override
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
if (descriptor.getClassModifiers().isTrait()) {
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
if (descriptor.isTrait()) {
trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes");
}
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
JetType type = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE);
if (type != null) {
DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
if (classDescriptor.getClassModifiers().isTrait()) {
trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "A trait may not have a constructor");
JetType supertype = typeInferrer.getCallResolver().resolveCall(trace, scopeForConstructor, null, call, NO_EXPECTED_TYPE);
if (supertype != null) {
recordSupertype(typeReference, supertype);
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (classDescriptor.isTrait()) {
trace.getErrorHandler().genericError(node, "A trait may not have a constructor");
}
}
}
else {
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
}
}
else {
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
else if (!descriptor.isTrait()) {
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype);
assert valueArgumentList != null;
trace.getErrorHandler().genericError(valueArgumentList.getNode(),
"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
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) {
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
if (!descriptor.getClassModifiers().isTrait()) {
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getClassModifiers().isTrait()) {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (!descriptor.isTrait()) {
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.isTrait()) {
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);
}
};
for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
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() {
@@ -253,7 +253,6 @@ public class CallResolver {
}
if (traceForFirstNonemptyCandidateSet != null) {
traceForFirstNonemptyCandidateSet.commit();
assert resultForFirstNonemptyCandidateSet != null;
if (resultForFirstNonemptyCandidateSet.singleDescriptor()) {
return resultForFirstNonemptyCandidateSet.getDescriptor();
}
@@ -321,6 +321,15 @@ public class TypeUtils {
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) {
if(type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor)
return true;
+1 -1
View File
@@ -49,7 +49,7 @@ namespace html {
class Title() : TagWithText("title")
class BodyTag(name : String) : TagWithText(name) {
abstract class BodyTag(name : String) : TagWithText(name) {
}
class Body() : BodyTag("body") {
+2 -2
View File
@@ -1,9 +1,9 @@
class NoC
open class NoC
class NoC1 : NoC
class WithC0() : NoC<error>()</error>
class WithC1() : NoC
open class WithC1() : NoC
class NoC2 : <error>WithC1</error>
class NoC3 : WithC1<error>()</error>
class WithC2() : <error>WithC1</error>
+4 -4
View File
@@ -4,14 +4,14 @@ open class A() {
fun foo() : Int = 1
}
open class B() {
trait class B {
fun bar() : Double = 1.0;
}
class C() : A(), B()
class C() : A(), B
class D() {
class object : A(), B () {}
class object : A(), B {}
}
class Test1<T : A>()
@@ -61,7 +61,7 @@ fun <T : A> test2(t : T)
}
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())
class Test<<error>T</error>>
+2 -2
View File
@@ -1,5 +1,5 @@
namespace toplevelObjectDeclarations {
class Foo(y : Int) {
open class Foo(y : Int) {
virtual fun foo() : Int = 1
}
@@ -63,7 +63,7 @@ namespace localObjects {
val x : Int = 0
}
class Foo {
open class Foo {
fun foo() : Int = 1
}
@@ -2,7 +2,7 @@ class <error>X</error> {
val <error>x</error> : Int
}
class Y() {
open class Y() {
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) {}
}
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> {}
+1 -1
View File
@@ -1,4 +1,4 @@
class A() {
<info>open</info> class A() {
fun foo() {}
}
+2 -2
View File
@@ -1,4 +1,4 @@
// JET-11 Redeclaration & Forward reference for classes cause an exception
class <error>NoC</error>
open class <error>NoC</error>
class NoC1 : NoC
class <error>NoC</error>
open class <error>NoC</error>
+1 -1
View File
@@ -1,6 +1,6 @@
import java.lang.Integer
class C {
open class C {
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
}
class Left() : Base() {}
class Right() : Base() {}
open class Left() : Base() {}
trait class Right : Base {}
class D() : Left(), Right()
class D() : Left(), Right
fun vl(l : Left) : Int = l.v
fun vr(r : Right) : Int = r.v
@@ -1,8 +1,8 @@
class Base() {
open class Base() {
fun n(n : Int) : Int = n + 1
}
class Abstract {}
trait class Abstract {}
class Derived1() : Base(), Abstract {}
class Derived2() : Abstract, Base() {}
+14 -6
View File
@@ -1,9 +1,17 @@
class X(val x : Int) {}
class Y(val y : Int) {}
// Changed when traits were introduced. May not make sense any more
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 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 {
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)
if (p.x + p.y != 239) return "FAIL #3"
val y = Y(-1)
val y = YImpl(-1)
val p1 = P1(240, y)
if (p1.x + p1.y != 239) return "FAIL #4"
val p2 = P2(240, y)
@@ -1,5 +1,5 @@
class Outer() {
class InnerBase() {
open class InnerBase() {
}
class InnerDerived(): InnerBase() {
@@ -1,4 +1,4 @@
class Foo {
open class Foo {
fun xyzzy(): String = "xyzzy"
}
@@ -1,4 +1,4 @@
class Base() {
open class Base() {
public val plain = 239
public val read : Int
get() = 239
@@ -10,7 +10,7 @@ class Base() {
}
}
class Abstract {}
trait class Abstract {}
class Derived1() : Base(), Abstract {}
class Derived2() : Abstract, Base() {}
@@ -1,7 +1,7 @@
class Outer() {
public val s = "xyzzy"
class InnerBase(public val name: String) {
open class InnerBase(public val name: String) {
}
class InnerDerived(): InnerBase(s) {
@@ -1,9 +1,11 @@
class Left() {}
class Right() {
// Changed when traits were introduced. May not make sense any more
trait class Left {}
open class Right() {
virtual fun f() = 42
}
class D() : Left(), Right() {
class D() : Left, Right() {
override fun f() = 239
}