Wrap SE-0481 into an upcoming feature until source incompatibilities are resolved

This commit is contained in:
Mykola Pokhylets
2025-07-02 07:26:39 +02:00
parent 09a751f698
commit ae48446716
28 changed files with 353 additions and 132 deletions

View File

@@ -713,7 +713,11 @@ public:
/// or `let self = self` condition.
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
/// RHS of the self condition references a var defined in a capture list.
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const;
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
/// the self condition is a `LoadExpr`.
/// TODO: Remove `requireLoadExpr` after full-on of the WeakLet feature
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
bool requireLoadExpr = false) const;
SourceLoc getStartLoc() const;
SourceLoc getEndLoc() const;
@@ -822,7 +826,8 @@ public:
/// or `let self = self` condition.
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
/// RHS of the self condition references a var defined in a capture list.
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const;
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
bool requireLoadExpr = false) const;
static bool classof(const Stmt *S) {
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&

View File

@@ -296,6 +296,7 @@ UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
MIGRATABLE_UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
UPCOMING_FEATURE(WeakLet, 481, 7)
// Optional language features / modes

View File

@@ -1373,8 +1373,10 @@ CaptureListEntry CaptureListEntry::createParsed(
SourceRange ownershipRange, Identifier name, SourceLoc nameLoc,
SourceLoc equalLoc, Expr *initializer, DeclContext *DC) {
bool forceVar = ownershipKind == ReferenceOwnership::Weak && !Ctx.LangOpts.hasFeature(Feature::WeakLet);
auto introducer = forceVar ? VarDecl::Introducer::Var : VarDecl::Introducer::Let;
auto *VD =
new (Ctx) VarDecl(/*isStatic==*/false, VarDecl::Introducer::Let, nameLoc, name, DC);
new (Ctx) VarDecl(/*isStatic==*/false, introducer, nameLoc, name, DC);
if (ownershipKind != ReferenceOwnership::Strong)
VD->getAttrs().add(

View File

@@ -442,6 +442,15 @@ UNINTERESTING_FEATURE(BuiltinInterleave)
UNINTERESTING_FEATURE(BuiltinVectorsExternC)
UNINTERESTING_FEATURE(AddressOfProperty2)
static bool usesFeatureWeakLet(Decl *decl) {
if (auto *VD = dyn_cast<VarDecl>(decl)) {
if (auto *refAttr = VD->getAttrs().getAttribute<ReferenceOwnershipAttr>()) {
return VD->isLet() && refAttr->get() == ReferenceOwnership::Weak;
}
}
return false;
}
// ----------------------------------------------------------------------------
// MARK: - FeatureSet
// ----------------------------------------------------------------------------

View File

@@ -515,9 +515,11 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
/// RHS of the self condition references a var defined in a capture list.
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
bool requiresCaptureListRef) const {
return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef](const auto &cond) {
return cond.rebindsSelf(Ctx, requiresCaptureListRef);
bool requiresCaptureListRef,
bool requireLoadExpr) const {
return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef,
requireLoadExpr](const auto &cond) {
return cond.rebindsSelf(Ctx, requiresCaptureListRef, requireLoadExpr);
});
}
@@ -526,7 +528,8 @@ bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
/// RHS of the self condition references a var defined in a capture list.
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
bool requiresCaptureListRef) const {
bool requiresCaptureListRef,
bool requireLoadExpr) const {
auto pattern = getPatternOrNull();
if (!pattern) {
return false;
@@ -554,6 +557,10 @@ bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
return false;
}
if (requireLoadExpr && !isa<LoadExpr>(exprToCheckForDRE)) {
return false;
}
if (auto *load = dyn_cast<LoadExpr>(exprToCheckForDRE)) {
exprToCheckForDRE = load->getSubExpr();
}

View File

@@ -170,6 +170,15 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
return CaptureKind::StorageAddress;
}
// Reference storage types can appear in a capture list, which means
// we might allocate boxes to store the captures. However, those boxes
// have the same lifetime as the closure itself, so we must capture
// the box itself and not the payload, even if the closure is noescape,
// otherwise they will be destroyed when the closure is formed.
if (var->getInterfaceType()->is<ReferenceStorageType>() && !Context.LangOpts.hasFeature(Feature::WeakLet)) {
return CaptureKind::Box;
}
// For 'let' constants
if (!var->supportsMutation()) {
assert(getTypeProperties(

View File

@@ -1780,24 +1780,37 @@ public:
if (!conditionalStmt) {
return false;
}
// Require that the RHS of the `let self = self` condition
// refers to a variable defined in a capture list.
// This lets us reject invalid examples like:
//
// var `self` = self ?? .somethingElse
// guard let self = self else { return }
// method() // <- implicit self is not allowed
//
// In 5.10, instead of this check, compiler was checking that RHS of the
// self binding is loaded from a mutable variable. This is incorrect, but
// before SE-0481 compiler was trying to maintain this behavior in Swift 5
// mode for source compatibility. After SE-0481 this does not work
// anymore, because even in Swift 5 mode `weak self` capture is not mutable.
// So we have to introduce a breaking change as part of the SE-0481, and use
// proper check for capture list even in Swift 5 mode.
//
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true);
if (Ctx.LangOpts.hasFeature(Feature::WeakLet)) {
// Require that the RHS of the `let self = self` condition
// refers to a variable defined in a capture list.
// This lets us reject invalid examples like:
//
// var `self` = self ?? .somethingElse
// guard let self = self else { return }
// method() // <- implicit self is not allowed
//
// In 5.10, instead of this check, compiler was checking that RHS of the
// self binding is loaded from a mutable variable. This is incorrect, but
// before SE-0481 compiler was trying to maintain this behavior in Swift 5
// mode for source compatibility. After SE-0481 this does not work
// anymore, because even in Swift 5 mode `weak self` capture is not mutable.
// So we have to introduce a breaking change as part of the SE-0481, and use
// proper check for capture list even in Swift 5 mode.
//
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true);
} else {
// Require `LoadExpr`s when validating the self binding.
// This lets us reject invalid examples like:
//
// let `self` = self ?? .somethingElse
// guard let self = self else { return }
// method() // <- implicit self is not allowed
//
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
/*requireLoadExpr*/ true);
}
}
static bool
@@ -4093,6 +4106,11 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
access &= ~RK_Written;
}
// If this variable has WeakStorageType, then it can be mutated in ways we
// don't know.
if (var->getInterfaceType()->is<WeakStorageType>() && !DC->getASTContext().LangOpts.hasFeature(Feature::WeakLet))
access |= RK_Written;
// Diagnose variables that were never used (other than their
// initialization).
//

View File

@@ -5406,6 +5406,11 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
case ReferenceOwnershipOptionality::Allowed:
break;
case ReferenceOwnershipOptionality::Required:
if (var->isLet() && !ctx.LangOpts.hasFeature(Feature::WeakLet)) {
var->diagnose(diag::invalid_ownership_is_let, ownershipKind);
attr->setInvalid();
}
if (!isOptional) {
attr->setInvalid();

View File

@@ -1,16 +1,19 @@
// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null
// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix old- %s -o /dev/null
// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix new- -enable-upcoming-feature WeakLet %s -o /dev/null
// This test validates the behavior of transfer non sendable around ownership
// constructs like non copyable types, consuming/borrowing parameters, and inout
// parameters.
// REQUIRES: concurrency
// REQUIRES: swift_feature_WeakLet
final class S: Sendable {
func foo() {}
}
// expected-note@+1 12{{class 'NS' does not conform to the 'Sendable' protocol}}
// expected-old-note@+2 13{{class 'NS' does not conform to the 'Sendable' protocol}}
// expected-new-note@+1 12{{class 'NS' does not conform to the 'Sendable' protocol}}
final class NS {
func bar() {}
}
@@ -19,18 +22,23 @@ func getS() -> S { S() }
func getNS() -> NS { NS() }
final class CheckOptionality1: Sendable {
// expected-error@+2 {{'weak' variable should have optional type 'S?'}}
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}}
// expected-old-error@+4 {{'weak' variable should have optional type 'S?'}}
// expected-old-error@+3 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}}
// expected-new-error@+2 {{'weak' variable should have optional type 'S?'}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}}
weak var x: S = getS()
}
final class CheckOptionality2: Sendable {
// expected-error@+1 {{'weak' variable should have optional type 'S?'}}
// expected-old-error@+3 {{'weak' must be a mutable variable, because it may change at runtime}}
// expected-old-error@+2 {{'weak' variable should have optional type 'S?'}}
// expected-new-error@+1 {{'weak' variable should have optional type 'S?'}}
weak let x: S = getS()
}
final class CheckSendability1: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability1' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability1' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability1' is mutable}}
weak var x: S? = nil
weak var y: S? {
@@ -40,26 +48,32 @@ final class CheckSendability1: Sendable {
}
final class CheckSendability2: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability2' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability2' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability2' is mutable}}
weak var x: NS? = nil
}
final class CheckSendability3: Sendable {
// expected-old-error@+1 {{'weak' must be a mutable variable, because it may change at runtime}}
weak let x: S? = nil
}
final class CheckSendability4: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability4' contains non-Sendable type 'NS'}}
// expected-old-error@+3 {{'weak' must be a mutable variable, because it may change at runtime}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability4' contains non-Sendable type 'NS'}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability4' contains non-Sendable type 'NS'}}
weak let x: NS? = nil
}
final class CheckSendability5: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability5' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability5' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability5' is mutable}}
unowned var x: S = getS()
}
final class CheckSendability6: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability6' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability6' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability6' is mutable}}
unowned var x: NS = getNS()
}
@@ -73,12 +87,14 @@ final class CheckSendability8: Sendable {
}
final class CheckSendability9: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability9' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability9' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability9' is mutable}}
unowned(unsafe) var x: S = getS()
}
final class CheckSendability10: Sendable {
// expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability10' is mutable}}
// expected-old-error@+2 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability10' is mutable}}
// expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckSendability10' is mutable}}
unowned(unsafe) var x: NS = getNS()
}
@@ -93,15 +109,17 @@ final class CheckSendability12: Sendable {
func checkWeakCapture1(_ strongRef: S) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}}
weak var weakRef: S? = strongRef
return {
// expected-error@+1 {{reference to captured var 'weakRef' in concurrently-executing code}}
// expected-old-error@+2 {{reference to captured var 'weakRef' in concurrently-executing code}}
// expected-new-error@+1 {{reference to captured var 'weakRef' in concurrently-executing code}}
weakRef?.foo()
}
}
func checkWeakCapture2(_ strongRef: S) -> @Sendable () -> Void {
// expected-old-error@+1 {{'weak' must be a mutable variable, because it may change at runtime}}
weak let weakRef: S? = strongRef
return {
weakRef?.foo()
@@ -113,13 +131,13 @@ func checkWeakCapture3(_ strongRef: S) -> @Sendable () -> Void {
// TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed
// See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910
weakRef?.foo()
// expected-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}}
weakRef = nil
}
}
func checkWeakCapture4(_ strongRef: NS) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}}
weak var weakRef: NS? = strongRef
return {
// expected-error@+2 {{capture of 'weakRef' with non-Sendable type 'NS?' in a '@Sendable' closure}}
@@ -129,6 +147,7 @@ func checkWeakCapture4(_ strongRef: NS) -> @Sendable () -> Void {
}
func checkWeakCapture5(_ strongRef: NS) -> @Sendable () -> Void {
// expected-old-error@+1 {{'weak' must be a mutable variable, because it may change at runtime}}
weak let weakRef: NS? = strongRef
return {
// expected-error@+1 {{capture of 'weakRef' with non-Sendable type 'NS?' in a '@Sendable' closure}}
@@ -138,10 +157,11 @@ func checkWeakCapture5(_ strongRef: NS) -> @Sendable () -> Void {
func checkWeakCapture6(_ strongRef: NS) -> @Sendable () -> Void {
return { [weak weakRef = strongRef] in
// expected-old-error@+3 {{capture of 'weakRef' with non-Sendable type 'NS?' in a '@Sendable' closure}}
// For some reason the next error masks this error.
// This case is split into two, to verify that when unmasked error is triggered.
weakRef?.bar()
// expected-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}}
weakRef = nil
}
}
@@ -154,10 +174,12 @@ func checkWeakCapture7(_ strongRef: NS) -> @Sendable () -> Void {
}
func checkUnownedCapture1(_ strongRef: S) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
unowned var unownedRef: S = strongRef
return {
// expected-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}}
// expected-old-error@+2 {{reference to captured var 'unownedRef' in concurrently-executing code}}
// expected-new-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}}
unownedRef.foo()
}
}
@@ -171,14 +193,18 @@ func checkUnownedCapture2(_ strongRef: S) -> @Sendable () -> Void {
func checkUnownedCapture3(_ strongRef: S) -> @Sendable () -> Void {
return { [unowned unownedRef = strongRef] in
// TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed
// See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910
unownedRef.foo()
// expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
unownedRef = strongRef
}
}
func checkUnownedCapture4(_ strongRef: NS) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
unowned var unownedRef: NS = strongRef
return {
// expected-error@+2 {{capture of 'unownedRef' with non-Sendable type 'NS' in a '@Sendable' closure}}
@@ -200,7 +226,8 @@ func checkUnownedCapture6(_ strongRef: NS) -> @Sendable () -> Void {
// For some reason the next error masks this error.
// This case is split into two, to verify that when unmasked error is triggered.
unownedRef.bar()
// expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
unownedRef = strongRef
}
}
@@ -213,10 +240,12 @@ func checkUnownedCapture7(_ strongRef: NS) -> @Sendable () -> Void {
}
func checkUnsafeCapture1(_ strongRef: S) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
unowned(unsafe) var unownedRef: S = strongRef
return {
// expected-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}}
// expected-old-error@+2 {{reference to captured var 'unownedRef' in concurrently-executing code}}
// expected-new-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}}
unownedRef.foo()
}
}
@@ -230,14 +259,18 @@ func checkUnsafeCapture2(_ strongRef: S) -> @Sendable () -> Void {
func checkUnsafeCapture3(_ strongRef: S) -> @Sendable () -> Void {
return { [unowned(unsafe) unownedRef = strongRef] in
// TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed
// See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910
unownedRef.foo()
// expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
unownedRef = strongRef
}
}
func checkUnsafeCapture4(_ strongRef: NS) -> @Sendable () -> Void {
// expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
// expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}}
unowned(unsafe) var unownedRef: NS = strongRef
return {
// expected-error@+2 {{capture of 'unownedRef' with non-Sendable type 'NS' in a '@Sendable' closure}}
@@ -259,7 +292,8 @@ func checkUnsafeCapture6(_ strongRef: NS) -> @Sendable () -> Void {
// For some reason the next error masks this error.
// This case is split into two, to verify that when unmasked error is triggered.
unownedRef.bar()
// expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}}
// expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}}
unownedRef = strongRef
}
}

View File

@@ -1,4 +1,8 @@
// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
// RUN: %target-swift-frontend %s -enable-upcoming-feature WeakLet -emit-ir -g -o - | %FileCheck %s
// REQUIRES: swift_feature_WeakLet
class A {
init(handler: (() -> ())) { }
}

View File

@@ -1,14 +1,14 @@
// RUN: %target-swift-frontend -g -Xllvm -sil-print-types -emit-sil %s -parse-as-library -module-name a | %FileCheck %s
// RUN: %target-swift-frontend -g -Xllvm -sil-print-types -emit-sil %s -parse-as-library -module-name a -enable-upcoming-feature WeakLet | %FileCheck %s --check-prefixes=CHECK,CHECK-HAS-WEAK-LET
// REQUIRES: swift_feature_WeakLet
open class C {
public func fun() {}
public func run() {
{ [weak self] in
guard let self else { fatalError("cannot happen") }
// CHECK: sil_scope [[LAMBDA:[0-9]+]] { loc "{{.*}}":6:5
// CHECK: sil_scope [[BODY:[0-9]+]] { loc "{{.*}}":6:19 parent [[LAMBDA]]
// CHECK: sil_scope [[LET:[0-9]+]] { loc "{{.*}}":7:7 parent [[BODY]]
// CHECK: sil_scope [[TMP:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]]
// CHECK-HAS-WEAK-LET: sil_scope [[TMP:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]]
// CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]]
// CHECK: debug_value {{.*}} : $C, let, name "self", {{.*}}, scope [[GUARD]]
// CHECK: function_ref {{.*}}3fun{{.*}}, scope [[GUARD]]
@@ -16,4 +16,8 @@ open class C {
self.fun()
}()
}
public func fun() {}
}

View File

@@ -1,4 +1,8 @@
// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s
// RUN: %target-swift-frontend %s -enable-upcoming-feature WeakLet -emit-ir -g -o - | %FileCheck %s
// REQUIRES: swift_feature_WeakLet
public class ClosureMaker {
var a : Int

View File

@@ -1,5 +1,8 @@
// RUN: %target-run-simple-swift | %FileCheck %s
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-feature -Xfrontend WeakLet) | %FileCheck %s --check-prefixes=CHECK,CHECK-WEAK-LET
// REQUIRES: executable_test
// REQUIRES: swift_feature_WeakLet
protocol Protocol : class {
func noop()
@@ -76,17 +79,19 @@ func testWeakInLet() {
testWeakInLet()
#if hasFeature(WeakLet)
func testWeakLet() {
print("testWeakLet") // CHECK-LABEL: testWeakLet
print("testWeakLet") // CHECK-WEAK-LET-LABEL: testWeakLet
var obj: SwiftClassBase? = SwiftClass() // CHECK: SwiftClass Created
var obj: SwiftClassBase? = SwiftClass() // CHECK-WEAK-LET: SwiftClass Created
weak let weakRef = obj
printState(weakRef) // CHECK-NEXT: is present
obj = nil // CHECK-NEXT: SwiftClass Destroyed
printState(weakRef) // CHECK-NEXT: is nil
printState(weakRef) // CHECK-WEAK-LET-NEXT: is present
obj = nil // CHECK-WEAK-LET-NEXT: SwiftClass Destroyed
printState(weakRef) // CHECK-WEAK-LET-NEXT: is nil
}
testWeakLet()
#endif
//======================== Test Classbound Protocols ========================

View File

@@ -1,8 +1,14 @@
// RUN: %target-build-swift %s -Xfrontend -disable-objc-attr-requires-foundation-module -o %t-main
// RUN: %target-codesign %t-main
// RUN: %target-run %t-main | %FileCheck %s
// RUN: %target-build-swift %s -Xfrontend -disable-objc-attr-requires-foundation-module -enable-upcoming-feature WeakLet -o %t-main-weak-let
// RUN: %target-codesign %t-main-weak-let
// RUN: %target-run %t-main-weak-let | %FileCheck %s --check-prefixes=CHECK,CHECK-WEAK-LET
// REQUIRES: executable_test
// REQUIRES: objc_interop
// REQUIRES: swift_feature_WeakLet
import Foundation
@@ -48,28 +54,30 @@ func testObjCClass() {
testObjCClass()
#if hasFeature(WeakLet)
func testObjCWeakLet() {
print("testObjCWeakLet") // CHECK: testObjCWeakLet
print("testObjCWeakLet") // CHECK-WEAK-LET: testObjCWeakLet
var c : ObjCClassBase = ObjCClass() // CHECK: ObjCClass Created
var c : ObjCClassBase = ObjCClass() // CHECK-WEAK-LET: ObjCClass Created
weak let w : ObjCClassBase? = c
printState(w) // CHECK-NEXT: is present
c = ObjCClassBase() // CHECK-NEXT: ObjCClass Destroyed
printState(w) // CHECK-NEXT: is nil
printState(w) // CHECK-WEAK-LET-NEXT: is present
c = ObjCClassBase() // CHECK-WEAK-LET-NEXT: ObjCClass Destroyed
printState(w) // CHECK-WEAK-LET-NEXT: is nil
}
testObjCWeakLet()
func testObjCWeakLetCapture() {
print("testObjCWeakLetCapture") // CHECK: testObjCWeakLetCapture
print("testObjCWeakLetCapture") // CHECK-WEAK-LET: testObjCWeakLetCapture
var c : ObjCClassBase = ObjCClass() // CHECK: ObjCClass Created
var c : ObjCClassBase = ObjCClass() // CHECK-WEAK-LET: ObjCClass Created
let closure: () -> ObjCClassBase? = { [weak c] in c }
printState(closure()) // CHECK-NEXT: is present
printState(closure()) // CHECK-NEXT: is present
c = ObjCClassBase() // CHECK-NEXT: ObjCClass Destroyed
printState(closure()) // CHECK-NEXT: is nil
printState(closure()) // CHECK-NEXT: is nil
printState(closure()) // CHECK-WEAK-LET-NEXT: is present
printState(closure()) // CHECK-WEAK-LET-NEXT: is present
c = ObjCClassBase() // CHECK-WEAK-LET-NEXT: ObjCClass Destroyed
printState(closure()) // CHECK-WEAK-LET-NEXT: is nil
printState(closure()) // CHECK-WEAK-LET-NEXT: is nil
}
testObjCWeakLetCapture()
#endif

View File

@@ -1,7 +1,9 @@
// RUN: %target-typecheck-verify-swift
// RUN: %target-typecheck-verify-swift -verify-additional-prefix no-weak-let-
// RUN: %target-typecheck-verify-swift -enable-upcoming-feature WeakLet
// REQUIRES: swift_swift_parser
// FIXME: Swift parser is not enabled on Linux CI yet.
// REQUIRES: OS=macosx
// REQUIRES: swift_feature_WeakLet
// rdar://15946844
func test1(inout var x : Int) {} // expected-warning {{'var' in this position is interpreted as an argument label}} {{18-21=`var`}}
@@ -119,6 +121,7 @@ prefix func %<T>(x: T) -> T { return x } // No error expected - the < is conside
struct Weak<T: class> { // expected-error {{'class' constraint can only appear on protocol declarations}}
// expected-note@-1 {{did you mean to write an 'AnyObject' constraint?}} {{16-21=AnyObject}}
// expected-no-weak-let-error@+1 {{'weak' must be a mutable variable, because it may change at runtime}}
weak let value: T // expected-error {{'weak' variable should have optional type 'T?'}} expected-error {{'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound}}
}

View File

@@ -1,4 +1,7 @@
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
// RUN: %target-swift-emit-silgen %s | %FileCheck %s --check-prefixes=CHECK,CHECK-NO-WEAK-LET
// RUN: %target-swift-emit-silgen -enable-upcoming-feature WeakLet %s | %FileCheck %s --check-prefixes=CHECK,CHECK-HAS-WEAK-LET
// REQUIRES: swift_feature_WeakLet
// https://github.com/apple/swift/issues/50924
@@ -31,7 +34,8 @@ class C {
func returnsSelf1() -> Self {
return { [weak self] in self?.f(); return .init() }()
// CHECK-LABEL: sil private [ossa] @{{.*}}returnsSelf{{.*}} : $@convention(thin) (@in_guaranteed @sil_weak Optional<C>, @thick @dynamic_self C.Type) -> @owned C {
// CHECK-NO-WEAK-LET-LABEL: sil private [ossa] @{{.*}}returnsSelf{{.*}} : $@convention(thin) (@guaranteed { var @sil_weak Optional<C> }, @thick @dynamic_self C.Type) -> @owned C {
// CHECK-HAS-WEAK-LET-LABEL: sil private [ossa] @{{.*}}returnsSelf{{.*}} : $@convention(thin) (@in_guaranteed @sil_weak Optional<C>, @thick @dynamic_self C.Type) -> @owned C {
}
func returnsSelf2() -> Self {

View File

@@ -1,4 +1,6 @@
// RUN: %target-swift-emit-silgen %s -verify
// RUN: %target-swift-emit-silgen -enable-upcoming-feature WeakLet %s -verify
// REQUIRES: swift_feature_WeakLet
/// We emit an invalid forward capture as an 'undef'; make sure
/// we cover the various possible cases.

View File

@@ -1,10 +1,12 @@
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 4 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s
// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 4 -O %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-ir -swift-version 4 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 4 -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s
// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 4 -O -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-ir -swift-version 4 -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s
// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 5 -O %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-ir -swift-version 5 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s
// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 5 -O -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// RUN: %target-swift-emit-ir -swift-version 5 -enable-upcoming-feature WeakLet %s -disable-objc-attr-requires-foundation-module -enable-objc-interop
// REQUIRES: swift_feature_WeakLet
protocol P {
func f() -> Self

View File

@@ -1,4 +1,6 @@
// RUN: %target-swift-emit-silgen %s -enable-objc-interop | %FileCheck %s
// RUN: %target-swift-emit-silgen %s -enable-objc-interop -enable-upcoming-feature WeakLet | %FileCheck %s
// REQUIRES: swift_feature_WeakLet
protocol ClassProtocol: AnyObject {}

View File

@@ -1,5 +1,7 @@
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name weak -Xllvm -sil-full-demangle %s | %FileCheck %s
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name weak -Xllvm -sil-full-demangle %s -enable-upcoming-feature WeakLet | %FileCheck %s
// REQUIRES: swift_feature_WeakLet
class C {
func f() -> Int { return 42 }
@@ -67,6 +69,7 @@ func testClosureOverWeak() {
takeClosure { bC!.f() }
}
#if hasFeature(WeakLet)
func testClosureOverWeakLet() {
weak let bC = C()
takeClosure { bC!.f() }
@@ -77,6 +80,8 @@ func testClosureOverWeakCapture() {
takeClosure { [weak bC] in bC!.f() }
}
#endif
class CC {
weak var x: CC?

View File

@@ -1,4 +1,7 @@
// RUN: %target-swift-frontend -enable-copy-propagation=requested-passes-only -emit-sil -primary-file %s -o /dev/null -verify
// RUN: %target-swift-frontend -enable-copy-propagation=requested-passes-only -emit-sil -primary-file %s -o /dev/null -verify -verify-additional-prefix no-weak-let-
// RUN: %target-swift-frontend -enable-copy-propagation=requested-passes-only -enable-upcoming-feature WeakLet -emit-sil -primary-file %s -o /dev/null -verify -verify-additional-prefix has-weak-let-
// REQUIRES: swift_feature_WeakLet
import Swift
@@ -103,15 +106,22 @@ func test2() {
// Weak
// expected-warning @+1 {{variable 'w1' was never mutated; consider changing to 'let' constant}} {{8-11=let}}
// expected-has-weak-let-warning@+1 {{variable 'w1' was never mutated; consider changing to 'let' constant}} {{8-11=let}}
weak var w1 : SomeClass?
_ = w1 // ok: default-initialized
// Note: with -enable-copy-propagation, we also expect: {{weak reference will always be nil because the referenced object is deallocated here}}
// expected-warning@+3 {{instance will be immediately deallocated because variable 'w2' is 'weak'}}
// expected-note@+2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-note@+1 {{'w2' declared here}}
#if hasFeature(WeakLet)
// expected-has-weak-let-warning@+3 {{instance will be immediately deallocated because variable 'w2' is 'weak'}}
// expected-has-weak-let-note@+2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-has-weak-let-note@+1 {{'w2' declared here}}
weak let w2 = SomeClass()
#else
// expected-no-weak-let-warning@+3 {{instance will be immediately deallocated because variable 'w2' is 'weak'}}
// expected-no-weak-let-note@+2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-no-weak-let-note@+1 {{'w2' declared here}}
weak var w2 = SomeClass()
#endif
_ = w2 // ok

View File

@@ -1,4 +1,6 @@
// RUN: %target-typecheck-verify-swift -module-name ModuleName
// RUN: %target-typecheck-verify-swift -module-name ModuleName -enable-upcoming-feature WeakLet
// REQUIRES: swift_feature_WeakLet
protocol ClassProtocol : class {
init()

View File

@@ -1,4 +1,7 @@
// RUN: %target-typecheck-verify-swift
// RUN: %target-typecheck-verify-swift -verify-additional-prefix no-weak-let-
// RUN: %target-typecheck-verify-swift -enable-upcoming-feature WeakLet -verify-additional-prefix has-weak-let-
// REQUIRES: swift_feature_WeakLet
func markUsed<T>(_ t: T) {}
@@ -114,10 +117,12 @@ var x15: Int {
// For the purpose of this test we need to use an attribute that cannot be
// applied to the getter.
weak
var foo: SomeClass? = SomeClass() // expected-warning {{variable 'foo' was never used; consider replacing with '_' or removing it}}
// expected-warning@-1 {{instance will be immediately deallocated because variable 'foo' is 'weak'}}
// expected-note@-2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-note@-3 {{'foo' declared here}}
var foo: SomeClass? = SomeClass()
// expected-no-weak-let-warning@-1 {{variable 'foo' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{variable 'foo' was never used; consider replacing with '_' or removing it}}
// expected-warning@-3 {{instance will be immediately deallocated because variable 'foo' is 'weak'}}
// expected-note@-4 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-note@-5 {{'foo' declared here}}
return 0
}

View File

@@ -1,4 +1,7 @@
// RUN: %target-typecheck-verify-swift
// RUN: %target-typecheck-verify-swift -verify-additional-prefix no-weak-let-
// RUN: %target-typecheck-verify-swift -enable-upcoming-feature WeakLet -verify-additional-prefix has-weak-let-
// REQUIRES: swift_feature_WeakLet
var t1 : Int
var t2 = 10
@@ -87,10 +90,12 @@ var shouldWarnWithoutSugar = (arrayOfEmptyTuples as Array<()>) // expected-warni
class SomeClass {}
weak let V = SomeClass() // ok since SE-0481
// expected-warning@-1 {{instance will be immediately deallocated because variable 'V' is 'weak'}}
// expected-note@-2 {{'V' declared here}}
// expected-note@-3 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-no-weak-let-error@-1 {{'weak' must be a mutable variable, because it may change at runtime}}
// expected-has-weak-let-warning@-2 {{instance will be immediately deallocated because variable 'V' is 'weak'}}
// expected-has-weak-let-note@-3 {{'V' declared here}}
// expected-has-weak-let-note@-4 {{a strong reference is required to prevent the instance from being deallocated}}
let a = b ; let b = a
// expected-error@-1 {{circular reference}}

View File

@@ -1,4 +1,7 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking
// RUN: %target-typecheck-verify-swift -disable-availability-checking -verify-additional-prefix no-weak-let-
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-upcoming-feature WeakLet -verify-additional-prefix has-weak-let-
// REQUIRES: swift_feature_WeakLet
var func6 : (_ fn : (Int,Int) -> Int) -> ()
var func6a : ((Int, Int) -> Int) -> ()
@@ -262,12 +265,29 @@ class ExplicitSelfRequiredTest {
// because its `sawError` flag is set to true. To preserve the "capture 'y' was never used" warnings
// above, we put these cases in their own method.
func weakSelfError() {
doVoidStuff({ [weak self] in x += 1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doVoidStuffNonEscaping({ [weak self] in x += 1 }) // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doStuff({ [weak self] in x+1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doVoidStuff({ [weak self] in _ = method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doVoidStuffNonEscaping({ [weak self] in _ = method() }) // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doStuff({ [weak self] in method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}}
doVoidStuff({ [weak self] in x += 1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
doVoidStuffNonEscaping({ [weak self] in x += 1 }) // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
doStuff({ [weak self] in x+1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
doVoidStuff({ [weak self] in _ = method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
doVoidStuffNonEscaping({ [weak self] in _ = method() }) // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
doStuff({ [weak self] in method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@-2 {{capture 'self' was never used}}
}
}
@@ -374,7 +394,8 @@ extension SomeClass {
//expected-error@-3{{reference to property 'in' in closure requires explicit use of 'self' to make capture semantics explicit}}
//expected-note@-4{{reference 'self.' explicitly}}
// expected-warning @+1 {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
doStuff { [weak self&field] in 42 } // expected-error {{expected ']' at end of capture list}}
}
@@ -1522,22 +1543,30 @@ final class AutoclosureTests {
withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
}
}
doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
doVoidStuff { [weak self] in
withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}}
}
doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
doVoidStuff { [weak self] in
withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
}
doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
doVoidStuff { [weak self] in
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
withNonEscapingAutoclosure(bar()) // expected-error {{all to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
}
}
doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
doVoidStuff { [weak self] in
doVoidStuff {
withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}}
}
@@ -1604,7 +1633,13 @@ final class AutoclosureTests {
let someOptional: Self? = Self()
var `self` = self ?? someOptional // expected-warning {{'self' was never mutated; consider changing to 'let' constant}}
guard let self = self else { return }
method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
#if hasFeature(WeakLet)
method() // expected-has-weak-let-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
#else
// This is not supposed to be permitted, but has been allowed since Swift 5.8,
// so we have to continue allowing it to maintain source compatibility.
method()
#endif
}
doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
@@ -1770,13 +1805,17 @@ class rdar129475277 {
func method() {}
func test1() {
takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
takesEscapingWithAllowedImplicitSelf { [weak self] in
takesEscapingWithAllowedImplicitSelf {
method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
}
}
takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
takesEscapingWithAllowedImplicitSelf { [weak self] in
takesEscapingWithAllowedImplicitSelf {
doVoidStuffNonEscaping {
withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}}
@@ -1784,7 +1823,9 @@ class rdar129475277 {
}
}
takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
takesEscapingWithAllowedImplicitSelf { [weak self] in
withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}}
}
}
@@ -1817,7 +1858,9 @@ class TestExtensionOnOptionalSelf {
extension TestExtensionOnOptionalSelf? {
func foo() {
_ = { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
_ = { [weak self] in
foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
}
@@ -1825,7 +1868,9 @@ extension TestExtensionOnOptionalSelf? {
foo()
}
_ = { [weak self] in // expected-warning {{capture 'self' was never used}}
// expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}}
// expected-has-weak-let-warning@+1 {{capture 'self' was never used}}
_ = { [weak self] in
_ = {
foo()
}

View File

@@ -1,4 +1,12 @@
// RUN: %target-typecheck-verify-swift -swift-version 6
// There seems to be a minor bug in the diagnostic of the self-capture.
// Diagnostic algorithm does not @lvalue DeclRefExpr wrapped into LoadExpr,
// and enabling WeakLet removes the LoadExpr.
// As a result, diagnostic messages change slightly.
// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix no-weak-let-
// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix has-weak-let- -enable-upcoming-feature WeakLet
// REQUIRES: swift_feature_WeakLet
func doStuff(_ fn : @escaping () -> Int) {}
func doVoidStuff(_ fn : @escaping () -> ()) {}
@@ -936,7 +944,8 @@ class TestExtensionOnOptionalSelf {
extension TestExtensionOnOptionalSelf? {
func foo() {
_ = { [weak self] in
// expected-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-error@+2 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}}
// expected-has-weak-let-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
foo()
}
@@ -947,9 +956,10 @@ extension TestExtensionOnOptionalSelf? {
}
_ = { [weak self] in
_ = { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
// expected-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-note@+1 {{reference 'self.' explicitly}}
_ = { // expected-has-weak-let-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
// expected-no-weak-let-error@+3 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}}
// expected-has-weak-let-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-has-weak-let-note@+1 {{reference 'self.' explicitly}}
foo()
self.foo()
self?.bar()
@@ -970,7 +980,8 @@ extension TestExtensionOnOptionalSelf? {
extension TestExtensionOnOptionalSelf {
func foo() {
_ = { [weak self] in
// expected-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-no-weak-let-error@+2 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}}
// expected-has-weak-let-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
foo()
self.foo()
self?.bar()
@@ -982,9 +993,10 @@ extension TestExtensionOnOptionalSelf {
}
_ = { [weak self] in
_ = { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
// expected-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-note@+1 {{reference 'self.' explicitly}}
_ = { // expected-has-weak-let-note {{capture 'self' explicitly to enable implicit 'self' in this closure}}
// expected-no-weak-let-error@+3 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}}
// expected-has-weak-let-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}}
// expected-has-weak-let-note@+1 {{reference 'self.' explicitly}}
foo()
self.foo()
}

View File

@@ -1,7 +1,9 @@
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -swift-version 6)
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -swift-version 6 -enable-upcoming-feature WeakLet)
// REQUIRES: concurrency
// REQUIRES: executable_test
// REQUIRES: swift_feature_WeakLet
// rdar://102155748
// UNSUPPORTED: back_deployment_runtime

View File

@@ -14,9 +14,9 @@
// RUN: if [ %target-runtime == "objc" ]; \
// RUN: then \
// RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g && \
// RUN: %target-build-swift -Xfrontend -disable-access-control %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \
// RUN: %target-build-swift -Xfrontend -disable-access-control -Xfrontend -enable-experimental-feature -Xfrontend WeakLet %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \
// RUN: else \
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Mirror; \
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -enable-experimental-feature -Xfrontend WeakLet -o %t/Mirror; \
// RUN: fi
// RUN: %target-codesign %t/Mirror
// RUN: %target-run %t/Mirror
@@ -24,6 +24,7 @@
// REQUIRES: executable_test
// REQUIRES: shell
// REQUIRES: reflection
// REQUIRES: swift_feature_WeakLet
import StdlibUnittest
@@ -123,6 +124,7 @@ mirrors.test("class/NativeSwiftClassHasNativeWeakReferenceNoLeak") {
expectNil(verifier)
}
#if hasFeature(WeakLet)
class NativeSwiftClassHasWeakLet {
weak let weakProperty: AnyObject?
let x: Int
@@ -205,6 +207,7 @@ mirrors.test("class/NativeSwiftClassHasNativeWeakLetReferenceNoLeak") {
}
expectNil(verifier)
}
#endif
#if _runtime(_ObjC)
@@ -375,6 +378,8 @@ mirrors.test("struct/StructHasObjCClassBoundExistential") {
print(extractedChild)
}
#if hasFeature(WeakLet)
class NativeSwiftClassHasObjCClassBoundExistentialLet {
weak let weakProperty: ObjCClassExistential?
let x: Int
@@ -527,4 +532,6 @@ mirrors.test("struct/StructHasObjCClassBoundExistentialLet") {
#endif
#endif
runAllTests()