Skip to content

Commit 44c46d6

Browse files
committed
Merge pull request #138 from CodaFi/the-circular-typealias-of-life
Diagnose Circular Typealiases in Protocols
2 parents 888de46 + 9b68f5f commit 44c46d6

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

include/swift/AST/Decl.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,11 @@ 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
};
577-
enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 1 };
580+
enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 2 };
578581
static_assert(NumAssociatedTypeDeclBits <= 32, "fits in an unsigned");
579582

580583
class ImportDeclBitfields {
@@ -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

+16-1
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

+4
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)