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 +}