Skip to content

Commit f72fd5a

Browse files
authored
Merge pull request #82930 from nickolas-pohilets/mpokhylets/6.2-weak-let
[6.2] Cherry-pick SE-0481 with source-incompatible changes to closure capture semantics still wrapped into a feature
2 parents 0802375 + 5d70bea commit f72fd5a

29 files changed

+798
-93
lines changed

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ GROUP(StringInterpolationConformance, "string-interpolation-conformance")
7171
GROUP(TemporaryPointers, "temporary-pointers")
7272
GROUP(TrailingClosureMatching, "trailing-closure-matching")
7373
GROUP(UnknownWarningGroup, "unknown-warning-group")
74+
GROUP(WeakMutability, "weak-mutability")
7475

7576
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
7677
#include "swift/AST/DefineDiagnosticGroupsMacros.h"

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7306,6 +7306,14 @@ WARNING(variable_tuple_elt_never_mutated, none,
73067306
"variable %0 was never mutated; "
73077307
"consider changing the pattern to 'case (..., let %1, ...)'",
73087308
(Identifier, StringRef))
7309+
GROUPED_WARNING(weak_variable_never_mutated, WeakMutability, none,
7310+
"weak variable %0 was never mutated; "
7311+
"consider %select{removing 'var' to make it|changing to 'let'}1 constant",
7312+
(Identifier, bool))
7313+
GROUPED_WARNING(weak_variable_tuple_elt_never_mutated, WeakMutability, none,
7314+
"weak variable %0 was never mutated; "
7315+
"consider changing the pattern to 'case (..., let %1, ...)'",
7316+
(Identifier, StringRef))
73097317
WARNING(variable_never_read, none,
73107318
"variable %0 was written to, but never read",
73117319
(Identifier))

include/swift/AST/Stmt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,8 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement {
728728
/// RHS of the self condition references a var defined in a capture list.
729729
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
730730
/// the self condition is a `LoadExpr`.
731+
/// TODO: Remove `requireLoadExpr` after full-on of the ImmutableWeakCaptures
732+
/// feature
731733
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
732734
bool requireLoadExpr = false) const;
733735

@@ -838,8 +840,6 @@ class LabeledConditionalStmt : public LabeledStmt {
838840
/// or `let self = self` condition.
839841
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
840842
/// RHS of the self condition references a var defined in a capture list.
841-
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
842-
/// the self condition is a `LoadExpr`.
843843
bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false,
844844
bool requireLoadExpr = false) const;
845845

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
293293
MIGRATABLE_UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
294294
MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
295295
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
296+
UPCOMING_FEATURE(ImmutableWeakCaptures, 481, 7)
296297

297298
// Optional language features / modes
298299

lib/AST/Expr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,9 +1366,9 @@ CaptureListEntry CaptureListEntry::createParsed(
13661366
SourceRange ownershipRange, Identifier name, SourceLoc nameLoc,
13671367
SourceLoc equalLoc, Expr *initializer, DeclContext *DC) {
13681368

1369-
auto introducer =
1370-
(ownershipKind != ReferenceOwnership::Weak ? VarDecl::Introducer::Let
1371-
: VarDecl::Introducer::Var);
1369+
bool forceVar = ownershipKind == ReferenceOwnership::Weak &&
1370+
!Ctx.LangOpts.hasFeature(Feature::ImmutableWeakCaptures);
1371+
auto introducer = forceVar ? VarDecl::Introducer::Var : VarDecl::Introducer::Let;
13721372
auto *VD =
13731373
new (Ctx) VarDecl(/*isStatic==*/false, introducer, nameLoc, name, DC);
13741374

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ static bool usesFeatureAlwaysInheritActorContext(Decl *decl) {
680680
static bool usesFeatureDefaultIsolationPerFile(Decl *D) {
681681
return isa<UsingDecl>(D);
682682
}
683+
UNINTERESTING_FEATURE(ImmutableWeakCaptures)
683684

684685
// ----------------------------------------------------------------------------
685686
// MARK: - FeatureSet

lib/AST/Stmt.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,6 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
514514
/// or `let self = self` condition.
515515
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
516516
/// RHS of the self condition references a var defined in a capture list.
517-
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
518-
/// the self condition is a `LoadExpr`.
519517
bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
520518
bool requiresCaptureListRef,
521519
bool requireLoadExpr) const {
@@ -529,8 +527,6 @@ bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx,
529527
/// or `let self = self` condition.
530528
/// - If `requiresCaptureListRef` is `true`, additionally requires that the
531529
/// RHS of the self condition references a var defined in a capture list.
532-
/// - If `requireLoadExpr` is `true`, additionally requires that the RHS of
533-
/// the self condition is a `LoadExpr`.
534530
bool StmtConditionElement::rebindsSelf(ASTContext &Ctx,
535531
bool requiresCaptureListRef,
536532
bool requireLoadExpr) const {

lib/Sema/MiscDiagnostics.cpp

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,15 +1784,34 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker {
17841784
return false;
17851785
}
17861786

1787-
// Require `LoadExpr`s when validating the self binding.
1788-
// This lets us reject invalid examples like:
1789-
//
1790-
// let `self` = self ?? .somethingElse
1791-
// guard let self = self else { return }
1792-
// method() // <- implicit self is not allowed
1793-
//
1794-
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
1795-
/*requireLoadExpr*/ true);
1787+
if (Ctx.LangOpts.hasFeature(Feature::ImmutableWeakCaptures)) {
1788+
// Require that the RHS of the `let self = self` condition
1789+
// refers to a variable defined in a capture list.
1790+
// This lets us reject invalid examples like:
1791+
//
1792+
// var `self` = self ?? .somethingElse
1793+
// guard let self = self else { return }
1794+
// method() // <- implicit self is not allowed
1795+
//
1796+
// In 5.10, instead of this check, compiler was checking that RHS of the
1797+
// self binding is loaded from a mutable variable. This is incorrect, but
1798+
// before immutable weak captures compiler was trying to maintain this
1799+
// behavior in Swift 5 mode for source compatibility. With immutable weak
1800+
// captures this does not work anymore, because even in Swift 5 mode there
1801+
// is no `LoadExpr` to use.
1802+
//
1803+
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true);
1804+
} else {
1805+
// Require `LoadExpr`s when validating the self binding.
1806+
// This lets us reject invalid examples like:
1807+
//
1808+
// let `self` = self ?? .somethingElse
1809+
// guard let self = self else { return }
1810+
// method() // <- implicit self is not allowed
1811+
//
1812+
return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false,
1813+
/*requireLoadExpr*/ true);
1814+
}
17961815
}
17971816

17981817
static bool
@@ -4043,9 +4062,12 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
40434062

40444063
// If this variable has WeakStorageType, then it can be mutated in ways we
40454064
// don't know.
4046-
if (var->getInterfaceType()->is<WeakStorageType>())
4065+
if (var->getInterfaceType()->is<WeakStorageType>() &&
4066+
(access & RK_CaptureList) &&
4067+
!DC->getASTContext().LangOpts.hasFeature(
4068+
Feature::ImmutableWeakCaptures))
40474069
access |= RK_Written;
4048-
4070+
40494071
// Diagnose variables that were never used (other than their
40504072
// initialization).
40514073
//
@@ -4216,6 +4238,8 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
42164238
if (isUsedInInactive(var))
42174239
continue;
42184240

4241+
bool isWeak = var->getInterfaceType()->is<WeakStorageType>();
4242+
42194243
// If this is a parameter explicitly marked 'var', remove it.
42204244
if (FixItLoc.isInvalid()) {
42214245
bool suggestCaseLet = false;
@@ -4226,10 +4250,14 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
42264250
suggestCaseLet = isa<ForEachStmt>(stmt);
42274251
}
42284252
if (suggestCaseLet)
4229-
Diags.diagnose(var->getLoc(), diag::variable_tuple_elt_never_mutated,
4253+
Diags.diagnose(var->getLoc(),
4254+
isWeak ? diag::weak_variable_tuple_elt_never_mutated
4255+
: diag::variable_tuple_elt_never_mutated,
42304256
var->getName(), var->getNameStr());
42314257
else
4232-
Diags.diagnose(var->getLoc(), diag::variable_never_mutated,
4258+
Diags.diagnose(var->getLoc(),
4259+
isWeak ? diag::weak_variable_never_mutated
4260+
: diag::variable_never_mutated,
42334261
var->getName(), true);
42344262

42354263
}
@@ -4242,7 +4270,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
42424270
suggestLet = !isa<ForEachStmt>(stmt);
42434271
}
42444272

4245-
auto diag = Diags.diagnose(var->getLoc(), diag::variable_never_mutated,
4273+
auto diag = Diags.diagnose(var->getLoc(),
4274+
isWeak ? diag::weak_variable_never_mutated
4275+
: diag::variable_never_mutated,
42464276
var->getName(), suggestLet);
42474277

42484278
if (suggestLet)

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5275,11 +5275,6 @@ Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
52755275
case ReferenceOwnershipOptionality::Allowed:
52765276
break;
52775277
case ReferenceOwnershipOptionality::Required:
5278-
if (var->isLet()) {
5279-
var->diagnose(diag::invalid_ownership_is_let, ownershipKind);
5280-
attr->setInvalid();
5281-
}
5282-
52835278
if (!isOptional) {
52845279
attr->setInvalid();
52855280

0 commit comments

Comments
 (0)