From 11cce3bcdc885391318ca4c4a64f205e4441562c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 3 Dec 2015 22:12:43 -0500 Subject: [PATCH 1/2] Diagnose circular type aliases in protocol declarations --- include/swift/AST/Decl.h | 11 +++++++++++ lib/Sema/TypeCheckDecl.cpp | 17 ++++++++++++++++- test/decl/protocol/req/recursion.swift | 4 ++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index be729431cf27e..029c44cc1a427 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -573,6 +573,9 @@ class alignas(1 << DeclAlignInBits) Decl { unsigned : NumTypeDeclBits; unsigned Recursive : 1; + + /// Whether or not this declaration is currently being type-checked. + unsigned BeingTypeChecked : 1; }; enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 1 }; static_assert(NumAssociatedTypeDeclBits <= 32, "fits in an unsigned"); @@ -2605,6 +2608,14 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl { void setIsRecursive() { AssociatedTypeDeclBits.Recursive = true; } bool isRecursive() { return AssociatedTypeDeclBits.Recursive; } + /// Whether the declaration is currently being validated. + bool isBeingTypeChecked() { return AssociatedTypeDeclBits.BeingTypeChecked; } + + /// Toggle whether or not the declaration is being validated. + void setIsBeingTypeChecked(bool ibt = true) { + AssociatedTypeDeclBits.BeingTypeChecked = ibt; + } + static bool classof(const Decl *D) { return D->getKind() == DeclKind::AssociatedType; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 547e92fa264ce..cf9b537a7e19f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3173,7 +3173,7 @@ class DeclChecker : public DeclVisitor { TAD->getUnderlyingTypeLoc().setInvalidType(TC.Context); } else if (TAD->getDeclContext()->isGenericContext()) { TAD->setInterfaceType( - TC.getInterfaceTypeFromInternalType(TAD->getDeclContext(), + TC.getInterfaceTypeFromInternalType(TAD->getDeclContext(), TAD->getType())); } @@ -3192,6 +3192,19 @@ class DeclChecker : public DeclVisitor { } void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) { + if (assocType->isBeingTypeChecked()) { + + if (!assocType->hasType()) { + assocType->setInvalid(); + assocType->overwriteType(ErrorType::get(TC.Context)); + } + + TC.diagnose(assocType->getLoc(), diag::circular_type_alias, assocType->getName()); + return; + } + + assocType->setIsBeingTypeChecked(); + TC.checkDeclAttributesEarly(assocType); if (!assocType->hasAccessibility()) assocType->setAccessibility(assocType->getProtocol()->getFormalAccess()); @@ -3205,6 +3218,8 @@ class DeclChecker : public DeclVisitor { defaultDefinition.setInvalidType(TC.Context); } TC.checkDeclAttributes(assocType); + + assocType->setIsBeingTypeChecked(false); } bool checkUnsupportedNestedGeneric(NominalTypeDecl *NTD) { diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index 0a18a54b79d77..bc8090112d435 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -16,3 +16,7 @@ public struct S> {} class X { // expected-error{{same-type requirement makes generic parameter 'T' non-generic}} var type: T { return self.dynamicType } // expected-error{{use of undeclared type 'T'}} } + +protocol Y { + typealias Z = Z // expected-error{{type alias 'Z' circularly references itself}} +} From 9b68f5f6e34aa94099c4a460e5c08932ca36d089 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Dec 2015 02:24:55 -0500 Subject: [PATCH 2/2] Bump decl bits --- include/swift/AST/Decl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 029c44cc1a427..e6ee2fed757cd 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -577,7 +577,7 @@ class alignas(1 << DeclAlignInBits) Decl { /// Whether or not this declaration is currently being type-checked. unsigned BeingTypeChecked : 1; }; - enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 1 }; + enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 2 }; static_assert(NumAssociatedTypeDeclBits <= 32, "fits in an unsigned"); class ImportDeclBitfields {