From da80c42a762daffc87000ceddd3c74fa8cf5dbb8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 21 Jun 2017 16:03:21 -0700 Subject: [PATCH] Sema: Don't infer 'dynamic' for static methods and properties Otherwise, can crash in the AST verifier. Fixes . --- lib/Sema/TypeCheckDecl.cpp | 23 +++++++++++++++++++---- test/attr/attr_dynamic_infer.swift | 8 +++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 0d2ae5f933b41..337ae036188dd 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1245,12 +1245,14 @@ static void validatePatternBindingEntries(TypeChecker &tc, void swift::makeFinal(ASTContext &ctx, ValueDecl *D) { if (D && !D->isFinal()) { + assert(!D->isDynamic()); D->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true)); } } void swift::makeDynamic(ASTContext &ctx, ValueDecl *D) { if (D && !D->isDynamic()) { + assert(!D->isFinal()); D->getAttrs().add(new (ctx) DynamicAttr(/*IsImplicit=*/true)); } } @@ -2556,15 +2558,29 @@ static void inferDynamic(ASTContext &ctx, ValueDecl *D) { // Variables declared with 'let' cannot be 'dynamic'. if (auto VD = dyn_cast(D)) { - if (VD->isLet() && !isNSManaged) return; + auto staticSpelling = VD->getParentPatternBinding()->getStaticSpelling(); + + // The presence of 'static' bocks the inference of 'dynamic'. + if (VD->isStatic() && staticSpelling == StaticSpellingKind::KeywordStatic) + return; + + if (VD->isLet() && !isNSManaged) + return; } // Accessors should not infer 'dynamic' on their own; they can get it from // their storage decls. - if (auto FD = dyn_cast(D)) + if (auto FD = dyn_cast(D)) { if (FD->isAccessor()) return; + auto staticSpelling = FD->getStaticSpelling(); + + // The presence of 'static' bocks the inference of 'dynamic'. + if (FD->isStatic() && staticSpelling == StaticSpellingKind::KeywordStatic) + return; + } + // The presence of 'final' on a class prevents 'dynamic'. auto classDecl = D->getDeclContext()->getAsClassOrClassExtensionContext(); if (!classDecl) return; @@ -5176,8 +5192,7 @@ class DeclChecker : public DeclVisitor { // If the storage is dynamic or final, propagate to this accessor. if (isObjC && - storage->isDynamic() && - !storage->isFinal()) + storage->isDynamic()) makeDynamic(TC.Context, FD); if (storage->isFinal()) diff --git a/test/attr/attr_dynamic_infer.swift b/test/attr/attr_dynamic_infer.swift index 4fc57ba3cf35a..f81765e04ec8f 100644 --- a/test/attr/attr_dynamic_infer.swift +++ b/test/attr/attr_dynamic_infer.swift @@ -59,7 +59,7 @@ extension Sub { @objc class FinalTests {} extension FinalTests { - // CHECK: @objc final func foo + // CHECK: @objc final func foo final func foo() { } // CHECK: @objc final var prop: Super @@ -77,5 +77,11 @@ extension FinalTests { // CHECK: @objc final set set { } } + + // CHECK: static @objc var x + static var x: Int = 0 + + // CHECK: @objc static func bar + static func bar() { } }