From 23afce9ca0b6abbb7e77eb0b2a36a80a93ec648d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 19 Sep 2016 17:17:47 -0700 Subject: [PATCH] [Type checker] Don't infer 'dynamic' for 'let' variables or within final classes. The 'dynamic' inference would infer 'dynamic' in places where it would also infer 'final', leading to a diagnostic error: a declaration cannot be both 'final' and 'dynamic' with no source location information. Don't infer 'dynamic' in such places. Fixes SR-993 / rdar://problem/20449627. (cherry picked from commit 81661262c8f4d124cce4c9b1897cfb516a52b165) --- lib/Sema/TypeCheckDecl.cpp | 15 ++++++++++++++- test/ClangModules/objc_final_dynamic.swift | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/ClangModules/objc_final_dynamic.swift diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2ada08f3f151b..12625809f785f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2104,9 +2104,10 @@ static void inferDynamic(ASTContext &ctx, ValueDecl *D) { return; // Only introduce 'dynamic' on declarations... + bool isNSManaged = D->getAttrs().hasAttribute(); if (!isa(D->getDeclContext())) { // ...and in classes on decls marked @NSManaged. - if (!D->getAttrs().hasAttribute()) + if (!isNSManaged) return; } @@ -2114,6 +2115,18 @@ static void inferDynamic(ASTContext &ctx, ValueDecl *D) { if (D->isDynamic() || D->isFinal()) return; + // Variables declared with 'let' cannot be 'dynamic'. + if (auto VD = dyn_cast(D)) { + if (VD->isLet() && !isNSManaged) return; + } + + // The presence of 'final' on a class prevents 'dynamic'. + auto classDecl = D->getDeclContext()->getAsClassOrClassExtensionContext(); + if (!classDecl) return; + if (!isNSManaged && classDecl->isFinal() && + !classDecl->requiresStoredPropertyInits()) + return; + // Add the 'dynamic' attribute. D->getAttrs().add(new (ctx) DynamicAttr(/*isImplicit=*/true)); } diff --git a/test/ClangModules/objc_final_dynamic.swift b/test/ClangModules/objc_final_dynamic.swift new file mode 100644 index 0000000000000..ec92846974723 --- /dev/null +++ b/test/ClangModules/objc_final_dynamic.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s + +// REQUIRES: objc_interop + +import Foundation + +// Note: make sure we don't get a bogus error from nowhere, +// error: a declaration cannot be both 'final' and 'dynamic' +extension NSObject { + public static let staticIntProperty: Int = 17 +} + +final class MyClass : NSObject { } + +extension MyClass { + public static var otherStaticIntProperty: Int = 17 +}