Skip to content

Commit 11cce3b

Browse files
committed
Diagnose circular type aliases in protocol declarations
1 parent 5e25990 commit 11cce3b

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ class alignas(1 << DeclAlignInBits) Decl {
573573
unsigned : NumTypeDeclBits;
574574

575575
unsigned Recursive : 1;
576+
577+
/// Whether or not this declaration is currently being type-checked.
578+
unsigned BeingTypeChecked : 1;
576579
};
577580
enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 1 };
578581
static_assert(NumAssociatedTypeDeclBits <= 32, "fits in an unsigned");
@@ -2605,6 +2608,14 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl {
26052608
void setIsRecursive() { AssociatedTypeDeclBits.Recursive = true; }
26062609
bool isRecursive() { return AssociatedTypeDeclBits.Recursive; }
26072610

2611+
/// Whether the declaration is currently being validated.
2612+
bool isBeingTypeChecked() { return AssociatedTypeDeclBits.BeingTypeChecked; }
2613+
2614+
/// Toggle whether or not the declaration is being validated.
2615+
void setIsBeingTypeChecked(bool ibt = true) {
2616+
AssociatedTypeDeclBits.BeingTypeChecked = ibt;
2617+
}
2618+
26082619
static bool classof(const Decl *D) {
26092620
return D->getKind() == DeclKind::AssociatedType;
26102621
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3173,7 +3173,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31733173
TAD->getUnderlyingTypeLoc().setInvalidType(TC.Context);
31743174
} else if (TAD->getDeclContext()->isGenericContext()) {
31753175
TAD->setInterfaceType(
3176-
TC.getInterfaceTypeFromInternalType(TAD->getDeclContext(),
3176+
TC.getInterfaceTypeFromInternalType(TAD->getDeclContext(),
31773177
TAD->getType()));
31783178
}
31793179

@@ -3192,6 +3192,19 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31923192
}
31933193

31943194
void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) {
3195+
if (assocType->isBeingTypeChecked()) {
3196+
3197+
if (!assocType->hasType()) {
3198+
assocType->setInvalid();
3199+
assocType->overwriteType(ErrorType::get(TC.Context));
3200+
}
3201+
3202+
TC.diagnose(assocType->getLoc(), diag::circular_type_alias, assocType->getName());
3203+
return;
3204+
}
3205+
3206+
assocType->setIsBeingTypeChecked();
3207+
31953208
TC.checkDeclAttributesEarly(assocType);
31963209
if (!assocType->hasAccessibility())
31973210
assocType->setAccessibility(assocType->getProtocol()->getFormalAccess());
@@ -3205,6 +3218,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32053218
defaultDefinition.setInvalidType(TC.Context);
32063219
}
32073220
TC.checkDeclAttributes(assocType);
3221+
3222+
assocType->setIsBeingTypeChecked(false);
32083223
}
32093224

32103225
bool checkUnsupportedNestedGeneric(NominalTypeDecl *NTD) {

test/decl/protocol/req/recursion.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ public struct S<A: P where A.T == S<A>> {}
1616
class X<T where T == X> { // expected-error{{same-type requirement makes generic parameter 'T' non-generic}}
1717
var type: T { return self.dynamicType } // expected-error{{use of undeclared type 'T'}}
1818
}
19+
20+
protocol Y {
21+
typealias Z = Z // expected-error{{type alias 'Z' circularly references itself}}
22+
}

0 commit comments

Comments
 (0)