KT-286 Check supertype lists (in progress)
Tests involving multiple inheritance fixed
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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,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>>
|
||||
|
||||
@@ -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> {}
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
class A() {
|
||||
<info>open</info> class A() {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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() {}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user