Skip to content

Commit 6cf25b1

Browse files
committed
[Diagnostics][Sema] warn inconstructible enum
1 parent cd5acad commit 6cf25b1

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3209,6 +3209,8 @@ ERROR(unsupported_recursive_struct,none,
32093209
"contains it",
32103210
(Type))
32113211

3212+
WARNING(type_not_constructible,none,
3213+
"value type is inconstructible", ())
32123214
ERROR(recursive_enum_not_indirect,none,
32133215
"recursive enum %0 is not marked 'indirect'", (Type))
32143216
ERROR(unsupported_infinitely_sized_type,none,

lib/Sema/TypeCheckCircularity.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class CircularityChecker {
169169
bool diagnoseInfiniteRecursion(CanType parentType, ValueDecl *member,
170170
CanType memberType);
171171

172+
void diagnoseInconstructible(EnumDecl *E);
173+
172174
void addPathElementsTo(Path &path, CanType type);
173175
void addPathElement(Path &path, ValueDecl *member, CanType memberType);
174176

@@ -272,7 +274,10 @@ bool CircularityChecker::expandStruct(CanType type, StructDecl *S,
272274
bool CircularityChecker::expandEnum(CanType type, EnumDecl *E,
273275
unsigned depth) {
274276
// Indirect enums are representational leaves.
275-
if (E->isIndirect()) return false;
277+
if (E->isIndirect()) {
278+
diagnoseInconstructible(E);
279+
return false;
280+
}
276281

277282
startExpandingType(type);
278283

@@ -298,6 +303,7 @@ bool CircularityChecker::expandEnum(CanType type, EnumDecl *E,
298303
if (addMember(type, elt, eltType, depth))
299304
return true;
300305
}
306+
diagnoseInconstructible(E);
301307

302308
return false;
303309
}
@@ -601,3 +607,43 @@ bool CircularityChecker::diagnoseInfiniteRecursion(CanType parentType,
601607

602608
return true;
603609
}
610+
611+
// Show a warning if the enum is inconstructible. The outcome of this method
612+
// is irrelevant.
613+
void CircularityChecker::diagnoseInconstructible(EnumDecl *E) {
614+
615+
auto containsType = [](TupleType *tuple, Type E) -> bool {
616+
for (auto type: tuple->getElementTypes()) {
617+
if (type->isEqual(E))
618+
return true;
619+
}
620+
return false;
621+
};
622+
auto isInconstructible = [containsType, E]() -> bool {
623+
auto elts = E->getAllElements();
624+
if (elts.empty())
625+
return false;
626+
627+
for (auto elt: elts) {
628+
if (!elt->hasInterfaceType() ||
629+
!(elt->isIndirect() || E->isIndirect()))
630+
return false;
631+
632+
auto argTy = elt->getArgumentInterfaceType();
633+
if (!argTy)
634+
return false;
635+
636+
if (auto tuple = argTy->getAs<TupleType>()) {
637+
if (!containsType(tuple, E->getSelfInterfaceType()))
638+
return false;
639+
} else if (auto paren = dyn_cast<ParenType>(argTy.getPointer())) {
640+
if (!E->getSelfInterfaceType()->isEqual(paren->getUnderlyingType()))
641+
return false;
642+
}
643+
}
644+
return true;
645+
};
646+
647+
if (isInconstructible())
648+
TC.diagnose(E, diag::type_not_constructible);
649+
}

test/Sema/unsupported_recursive_value_type.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,29 @@ enum RecursiveByGenericSubstitutionEnum<T> {
4242
case A(T)
4343
}
4444

45+
enum InconstructibleEnum1 { // expected-warning {{value type is inconstructible}}
46+
indirect case A(InconstructibleEnum1)
47+
}
48+
enum InconstructibleEnum2 { // OK
49+
indirect case A(InconstructibleEnum2)
50+
case B(Bool)
51+
indirect case C(Int, InconstructibleEnum2)
52+
}
53+
enum InconstructibleEnum3 { // expected-warning {{value type is inconstructible}}
54+
indirect case B(Int, InconstructibleEnum3)
55+
}
56+
indirect enum InconstructibleEnum4 { // expected-warning {{value type is inconstructible}}
57+
case A(InconstructibleEnum4)
58+
}
59+
indirect enum InconstructibleEnum5 { // expected-warning {{value type is inconstructible}}
60+
case B(Int, InconstructibleEnum5)
61+
}
62+
indirect enum InconstructibleEnum6 { // OK
63+
case A(InconstructibleEnum6)
64+
case B(Bool)
65+
case C(Int, InconstructibleEnum6)
66+
}
67+
4568
struct RecursiveByBeingInTupleStruct {
4669
let a: (Int, RecursiveByBeingInTupleStruct) // expected-error{{value type 'RecursiveByBeingInTupleStruct' cannot have a stored property that recursively contains it}}
4770
// expected-note@-1 {{cycle beginning here: (Int, RecursiveByBeingInTupleStruct) -> (.1: RecursiveByBeingInTupleStruct)}}

0 commit comments

Comments
 (0)