Skip to content

Commit ae48446

Browse files
Wrap SE-0481 into an upcoming feature until source incompatibilities are resolved
1 parent 09a751f commit ae48446

28 files changed

+353
-132
lines changed

include/swift/AST/Stmt.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,11 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
713713
/// or `let self = self` condition.
714714
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
715715
/// RHS of the self condition references a var defined in a capture list.
716-
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const;
716+
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
717+
/// the self condition is a `LoadExpr`.
718+
/// TODO: Remove `requireLoadExpr` after full-on of the WeakLet feature
719+
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
720+
bool requireLoadExpr = false) const;
717721

718722
SourceLoc getStartLoc() const;
719723
SourceLoc getEndLoc() const;
@@ -822,7 +826,8 @@ class LabeledConditionalStmt : public LabeledStmt {
822826
/// or `let self = self` condition.
823827
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
824828
/// RHS of the self condition references a var defined in a capture list.
825-
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const;
829+
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
830+
bool requireLoadExpr = false) const;
826831

827832
static bool classof(const Stmt *S) {
828833
return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
296296
MIGRATABLE_UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
297297
MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
298298
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
299+
UPCOMING_FEATURE(WeakLet, 481, 7)
299300

300301
// Optional language features / modes
301302

lib/AST/Expr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,8 +1373,10 @@ CaptureListEntry CaptureListEntry::createParsed(
13731373
SourceRange ownershipRange, Identifier name, SourceLoc nameLoc,
13741374
SourceLoc equalLoc, Expr *initializer, DeclContext *DC) {
13751375

1376+
bool forceVar = ownershipKind == ReferenceOwnership::Weak && !Ctx.LangOpts.hasFeature(Feature::WeakLet);
1377+
auto introducer = forceVar ? VarDecl::Introducer::Var : VarDecl::Introducer::Let;
13761378
auto *VD =
1377-
new (Ctx) VarDecl(/*isStatic==*/false, VarDecl::Introducer::Let, nameLoc, name, DC);
1379+
new (Ctx) VarDecl(/*isStatic==*/false, introducer, nameLoc, name, DC);
13781380

13791381
if (ownershipKind != ReferenceOwnership::Strong)
13801382
VD->getAttrs().add(

lib/AST/FeatureSet.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,15 @@ UNINTERESTING_FEATURE(BuiltinInterleave)
442442
UNINTERESTING_FEATURE(BuiltinVectorsExternC)
443443
UNINTERESTING_FEATURE(AddressOfProperty2)
444444

445+
static bool usesFeatureWeakLet(Decl *decl) {
446+
if (auto *VD = dyn_cast<VarDecl>(decl)) {
447+
if (auto *refAttr = VD->getAttrs().getAttribute<ReferenceOwnershipAttr>()) {
448+
return VD->isLet() && refAttr->get() == ReferenceOwnership::Weak;
449+
}
450+
}
451+
return false;
452+
}
453+
445454
// ----------------------------------------------------------------------------
446455
// MARK: - FeatureSet
447456
// ----------------------------------------------------------------------------

lib/AST/Stmt.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,11 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
515515
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
516516
/// RHS of the self condition references a var defined in a capture list.
517517
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
518-
bool requiresCaptureListRef) const {
519-
return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef](const auto &cond) {
520-
return cond.rebindsSelf(Ctx, requiresCaptureListRef);
518+
bool requiresCaptureListRef,
519+
bool requireLoadExpr) const {
520+
return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef,
521+
requireLoadExpr](const auto &cond) {
522+
return cond.rebindsSelf(Ctx, requiresCaptureListRef, requireLoadExpr);
521523
});
522524
}
523525

@@ -526,7 +528,8 @@ bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
526528
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
527529
/// RHS of the self condition references a var defined in a capture list.
528530
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
529-
bool requiresCaptureListRef) const {
531+
bool requiresCaptureListRef,
532+
bool requireLoadExpr) const {
530533
auto pattern = getPatternOrNull();
531534
if (!pattern) {
532535
return false;
@@ -554,6 +557,10 @@ bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
554557
return false;
555558
}
556559

560+
if (requireLoadExpr && !isa<LoadExpr>(exprToCheckForDRE)) {
561+
return false;
562+
}
563+
557564
if (auto *load = dyn_cast<LoadExpr>(exprToCheckForDRE)) {
558565
exprToCheckForDRE = load->getSubExpr();
559566
}

lib/SIL/IR/TypeLowering.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,15 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
170170
return CaptureKind::StorageAddress;
171171
}
172172

173+
// Reference storage types can appear in a capture list, which means
174+
// we might allocate boxes to store the captures. However, those boxes
175+
// have the same lifetime as the closure itself, so we must capture
176+
// the box itself and not the payload, even if the closure is noescape,
177+
// otherwise they will be destroyed when the closure is formed.
178+
if (var->getInterfaceType()->is<ReferenceStorageType>() && !Context.LangOpts.hasFeature(Feature::WeakLet)) {
179+
return CaptureKind::Box;
180+
}
181+
173182
// For 'let' constants
174183
if (!var->supportsMutation()) {
175184
assert(getTypeProperties(

lib/Sema/MiscDiagnostics.cpp

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,24 +1780,37 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
17801780
if (!conditionalStmt) {
17811781
return false;
17821782
}
1783-
1784-
// Require that the RHS of the `let self = self` condition
1785-
// refers to a variable defined in a capture list.
1786-
// This lets us reject invalid examples like:
1787-
//
1788-
// var `self` = self ?? .somethingElse
1789-
// guard let self = self else { return }
1790-
// method() // <- implicit self is not allowed
1791-
//
1792-
// In 5.10, instead of this check, compiler was checking that RHS of the
1793-
// self binding is loaded from a mutable variable. This is incorrect, but
1794-
// before SE-0481 compiler was trying to maintain this behavior in Swift 5
1795-
// mode for source compatibility. After SE-0481 this does not work
1796-
// anymore, because even in Swift 5 mode `weak self` capture is not mutable.
1797-
// So we have to introduce a breaking change as part of the SE-0481, and use
1798-
// proper check for capture list even in Swift 5 mode.
1799-
//
1800-
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true);
1783+
1784+
if (Ctx.LangOpts.hasFeature(Feature::WeakLet)) {
1785+
// Require that the RHS of the `let self = self` condition
1786+
// refers to a variable defined in a capture list.
1787+
// This lets us reject invalid examples like:
1788+
//
1789+
// var `self` = self ?? .somethingElse
1790+
// guard let self = self else { return }
1791+
// method() // <- implicit self is not allowed
1792+
//
1793+
// In 5.10, instead of this check, compiler was checking that RHS of the
1794+
// self binding is loaded from a mutable variable. This is incorrect, but
1795+
// before SE-0481 compiler was trying to maintain this behavior in Swift 5
1796+
// mode for source compatibility. After SE-0481 this does not work
1797+
// anymore, because even in Swift 5 mode `weak self` capture is not mutable.
1798+
// So we have to introduce a breaking change as part of the SE-0481, and use
1799+
// proper check for capture list even in Swift 5 mode.
1800+
//
1801+
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true);
1802+
} else {
1803+
// Require `LoadExpr`s when validating the self binding.
1804+
// This lets us reject invalid examples like:
1805+
//
1806+
// let `self` = self ?? .somethingElse
1807+
// guard let self = self else { return }
1808+
// method() // <- implicit self is not allowed
1809+
//
1810+
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
1811+
/*requireLoadExpr*/ true);
1812+
1813+
}
18011814
}
18021815

18031816
static bool
@@ -4093,6 +4106,11 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
40934106
access &= ~RK_Written;
40944107
}
40954108

4109+
// If this variable has WeakStorageType, then it can be mutated in ways we
4110+
// don't know.
4111+
if (var->getInterfaceType()->is<WeakStorageType>() && !DC->getASTContext().LangOpts.hasFeature(Feature::WeakLet))
4112+
access |= RK_Written;
4113+
40964114
// Diagnose variables that were never used (other than their
40974115
// initialization).
40984116
//

lib/Sema/TypeCheckAttr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5406,6 +5406,11 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
54065406
case ReferenceOwnershipOptionality::Allowed:
54075407
break;
54085408
case ReferenceOwnershipOptionality::Required:
5409+
if (var->isLet() && !ctx.LangOpts.hasFeature(Feature::WeakLet)) {
5410+
var->diagnose(diag::invalid_ownership_is_let, ownershipKind);
5411+
attr->setInvalid();
5412+
}
5413+
54095414
if (!isOptional) {
54105415
attr->setInvalid();
54115416

0 commit comments

Comments
 (0)