Skip to content

Commit 17c8037

Browse files
committed
Implement consuming and borrowing declaration-level modifiers from SE-0377.
`borrowing func`/`consuming func` control the ownership convention of `self` for methods.
1 parent 71b0ea6 commit 17c8037

20 files changed

+205
-35
lines changed

include/swift/AST/Decl.h

+2-6
Original file line numberDiff line numberDiff line change
@@ -7174,7 +7174,9 @@ class OperatorDecl;
71747174
enum class SelfAccessKind : uint8_t {
71757175
NonMutating,
71767176
Mutating,
7177+
LegacyConsuming,
71777178
Consuming,
7179+
Borrowing,
71787180
};
71797181

71807182
/// Diagnostic printing of \c SelfAccessKind.
@@ -7293,12 +7295,6 @@ class FuncDecl : public AbstractFunctionDecl {
72937295
bool isMutating() const {
72947296
return getSelfAccessKind() == SelfAccessKind::Mutating;
72957297
}
7296-
bool isNonMutating() const {
7297-
return getSelfAccessKind() == SelfAccessKind::NonMutating;
7298-
}
7299-
bool isConsuming() const {
7300-
return getSelfAccessKind() == SelfAccessKind::Consuming;
7301-
}
73027298
bool isCallAsFunctionMethod() const;
73037299

73047300
bool isMainTypeMainMethod() const;

lib/APIDigester/ModuleAnalyzerNodes.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -1538,13 +1538,19 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD)
15381538
case SelfAccessKind::Mutating:
15391539
FuncSelfKind = "Mutating";
15401540
break;
1541-
case SelfAccessKind::Consuming:
1541+
case SelfAccessKind::LegacyConsuming:
15421542
// FIXME: Stay consistent with earlier digests that had underscores here.
15431543
FuncSelfKind = "__Consuming";
15441544
break;
15451545
case SelfAccessKind::NonMutating:
15461546
FuncSelfKind = "NonMutating";
15471547
break;
1548+
case SelfAccessKind::Consuming:
1549+
FuncSelfKind = "Consuming";
1550+
break;
1551+
case SelfAccessKind::Borrowing:
1552+
FuncSelfKind = "Borrowing";
1553+
break;
15481554
}
15491555
}
15501556

lib/AST/ASTContext.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -3487,8 +3487,12 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
34873487

34883488
auto flags = ParameterTypeFlags().withIsolated(isIsolated);
34893489
switch (selfAccess) {
3490+
case SelfAccessKind::LegacyConsuming:
34903491
case SelfAccessKind::Consuming:
3491-
flags = flags.withOwned(true);
3492+
flags = flags.withValueOwnership(ValueOwnership::Owned);
3493+
break;
3494+
case SelfAccessKind::Borrowing:
3495+
flags = flags.withValueOwnership(ValueOwnership::Shared);
34923496
break;
34933497
case SelfAccessKind::Mutating:
34943498
flags = flags.withInOut(true);

lib/AST/ASTPrinter.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,9 @@ void PrintAST::printAttributes(const Decl *D) {
11861186
if (isa<FuncDecl>(D)) {
11871187
Options.ExcludeAttrList.push_back(DAK_Mutating);
11881188
Options.ExcludeAttrList.push_back(DAK_NonMutating);
1189+
Options.ExcludeAttrList.push_back(DAK_LegacyConsuming);
11891190
Options.ExcludeAttrList.push_back(DAK_Consuming);
1191+
Options.ExcludeAttrList.push_back(DAK_Borrowing);
11901192
}
11911193

11921194
D->getAttrs().print(Printer, Options, D);
@@ -2063,9 +2065,17 @@ void PrintAST::printSelfAccessKindModifiersIfNeeded(const FuncDecl *FD) {
20632065
!Options.excludeAttrKind(DAK_NonMutating))
20642066
Printer.printKeyword("nonmutating", Options, " ");
20652067
break;
2068+
case SelfAccessKind::LegacyConsuming:
2069+
if (!Options.excludeAttrKind(DAK_LegacyConsuming))
2070+
Printer.printKeyword("__consuming", Options, " ");
2071+
break;
20662072
case SelfAccessKind::Consuming:
20672073
if (!Options.excludeAttrKind(DAK_Consuming))
2068-
Printer.printKeyword("__consuming", Options, " ");
2074+
Printer.printKeyword("consuming", Options, " ");
2075+
break;
2076+
case SelfAccessKind::Borrowing:
2077+
if (!Options.excludeAttrKind(DAK_Borrowing))
2078+
Printer.printKeyword("borrowing", Options, " ");
20692079
break;
20702080
}
20712081
}

lib/AST/Decl.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,9 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS,
547547
switch (SAK) {
548548
case SelfAccessKind::NonMutating: return OS << "'nonmutating'";
549549
case SelfAccessKind::Mutating: return OS << "'mutating'";
550-
case SelfAccessKind::Consuming: return OS << "'__consuming'";
550+
case SelfAccessKind::LegacyConsuming: return OS << "'__consuming'";
551+
case SelfAccessKind::Consuming: return OS << "'consuming'";
552+
case SelfAccessKind::Borrowing: return OS << "'borrowing'";
551553
}
552554
llvm_unreachable("Unknown SelfAccessKind");
553555
}

lib/Parse/ParseDecl.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -6765,7 +6765,11 @@ static bool parseAccessorIntroducer(Parser &P,
67656765
} else if (P.Tok.isContextualKeyword("nonmutating")) {
67666766
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_NonMutating);
67676767
} else if (P.Tok.isContextualKeyword("__consuming")) {
6768+
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_LegacyConsuming);
6769+
} else if (P.Tok.isContextualKeyword("consuming")) {
67686770
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Consuming);
6771+
} else if (P.Tok.isContextualKeyword("borrowing")) {
6772+
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Borrowing);
67696773
}
67706774
}
67716775

lib/SILGen/SILGenApply.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -5098,11 +5098,10 @@ bool SILGenModule::shouldEmitSelfAsRValue(FuncDecl *fn, CanType selfType) {
50985098
switch (fn->getSelfAccessKind()) {
50995099
case SelfAccessKind::Mutating:
51005100
return false;
5101-
case SelfAccessKind::Consuming:
5102-
return true;
51035101
case SelfAccessKind::NonMutating:
5104-
// TODO: borrow 'self' for nonmutating methods on methods on value types.
5105-
// return selfType->hasReferenceSemantics();
5102+
case SelfAccessKind::LegacyConsuming:
5103+
case SelfAccessKind::Consuming:
5104+
case SelfAccessKind::Borrowing:
51065105
return true;
51075106
}
51085107
llvm_unreachable("bad self-access kind");
@@ -5114,7 +5113,7 @@ bool SILGenModule::isNonMutatingSelfIndirect(SILDeclRef methodRef) {
51145113
return false;
51155114

51165115
assert(method->getDeclContext()->isTypeContext());
5117-
assert(method->isNonMutating() || method->isConsuming());
5116+
assert(!method->isMutating());
51185117

51195118
auto fnType = M.Types.getConstantFunctionType(TypeExpansionContext::minimal(),
51205119
methodRef);

lib/Sema/DerivedConformanceDifferentiable.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static bool canInvokeMoveByOnProperty(
5555
if (!witness)
5656
return false;
5757
auto *decl = cast<FuncDecl>(witness.getDecl());
58-
return decl->isNonMutating();
58+
return !decl->isMutating();
5959
}
6060

6161
/// Get the stored properties of a nominal type that are relevant for

lib/Sema/TypeCheckAttr.cpp

+39-6
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
200200
void visitMutationAttr(DeclAttribute *attr);
201201
void visitMutatingAttr(MutatingAttr *attr) { visitMutationAttr(attr); }
202202
void visitNonMutatingAttr(NonMutatingAttr *attr) { visitMutationAttr(attr); }
203+
void visitBorrowingAttr(BorrowingAttr *attr) { visitMutationAttr(attr); }
203204
void visitConsumingAttr(ConsumingAttr *attr) { visitMutationAttr(attr); }
205+
void visitLegacyConsumingAttr(LegacyConsumingAttr *attr) { visitMutationAttr(attr); }
204206
void visitDynamicAttr(DynamicAttr *attr);
205207

206208
void visitIndirectAttr(IndirectAttr *attr) {
@@ -443,15 +445,21 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) {
443445

444446
SelfAccessKind attrModifier;
445447
switch (attr->getKind()) {
446-
case DeclAttrKind::DAK_Consuming:
447-
attrModifier = SelfAccessKind::Consuming;
448+
case DeclAttrKind::DAK_LegacyConsuming:
449+
attrModifier = SelfAccessKind::LegacyConsuming;
448450
break;
449451
case DeclAttrKind::DAK_Mutating:
450452
attrModifier = SelfAccessKind::Mutating;
451453
break;
452454
case DeclAttrKind::DAK_NonMutating:
453455
attrModifier = SelfAccessKind::NonMutating;
454456
break;
457+
case DeclAttrKind::DAK_Consuming:
458+
attrModifier = SelfAccessKind::Consuming;
459+
break;
460+
case DeclAttrKind::DAK_Borrowing:
461+
attrModifier = SelfAccessKind::Borrowing;
462+
break;
455463
default:
456464
llvm_unreachable("unhandled attribute kind");
457465
}
@@ -462,22 +470,33 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) {
462470
// 'mutating' and 'nonmutating' are not valid on types
463471
// with reference semantics.
464472
if (contextTy->hasReferenceSemantics()) {
465-
if (attrModifier != SelfAccessKind::Consuming) {
473+
switch (attrModifier) {
474+
case SelfAccessKind::Consuming:
475+
case SelfAccessKind::LegacyConsuming:
476+
case SelfAccessKind::Borrowing:
477+
// It's still OK to specify the ownership convention of methods in
478+
// classes.
479+
break;
480+
481+
case SelfAccessKind::Mutating:
482+
case SelfAccessKind::NonMutating:
466483
diagnoseAndRemoveAttr(attr, diag::mutating_invalid_classes,
467484
attrModifier, FD->getDescriptiveKind(),
468485
DC->getSelfProtocolDecl() != nullptr);
486+
break;
469487
}
470488
}
471489
} else {
472490
diagnoseAndRemoveAttr(attr, diag::mutating_invalid_global_scope,
473491
attrModifier);
474492
}
475493

476-
// Verify we don't have more than one of mutating, nonmutating,
477-
// and __consuming.
494+
// Verify we don't have more than one ownership specifier.
478495
if ((FD->getAttrs().hasAttribute<MutatingAttr>() +
479496
FD->getAttrs().hasAttribute<NonMutatingAttr>() +
480-
FD->getAttrs().hasAttribute<ConsumingAttr>()) > 1) {
497+
FD->getAttrs().hasAttribute<LegacyConsumingAttr>() +
498+
FD->getAttrs().hasAttribute<ConsumingAttr>() +
499+
FD->getAttrs().hasAttribute<BorrowingAttr>()) > 1) {
481500
if (auto *NMA = FD->getAttrs().getAttribute<NonMutatingAttr>()) {
482501
if (attrModifier != SelfAccessKind::NonMutating) {
483502
diagnoseAndRemoveAttr(NMA, diag::functions_mutating_and_not,
@@ -492,12 +511,26 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) {
492511
}
493512
}
494513

514+
if (auto *CSA = FD->getAttrs().getAttribute<LegacyConsumingAttr>()) {
515+
if (attrModifier != SelfAccessKind::LegacyConsuming) {
516+
diagnoseAndRemoveAttr(CSA, diag::functions_mutating_and_not,
517+
SelfAccessKind::LegacyConsuming, attrModifier);
518+
}
519+
}
520+
495521
if (auto *CSA = FD->getAttrs().getAttribute<ConsumingAttr>()) {
496522
if (attrModifier != SelfAccessKind::Consuming) {
497523
diagnoseAndRemoveAttr(CSA, diag::functions_mutating_and_not,
498524
SelfAccessKind::Consuming, attrModifier);
499525
}
500526
}
527+
528+
if (auto *BSA = FD->getAttrs().getAttribute<BorrowingAttr>()) {
529+
if (attrModifier != SelfAccessKind::Borrowing) {
530+
diagnoseAndRemoveAttr(BSA, diag::functions_mutating_and_not,
531+
SelfAccessKind::Borrowing, attrModifier);
532+
}
533+
}
501534
}
502535

503536
// Verify that we don't have a static function.

lib/Sema/TypeCheckDecl.cpp

+25-4
Original file line numberDiff line numberDiff line change
@@ -1670,8 +1670,12 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
16701670
return SelfAccessKind::Mutating;
16711671
} else if (FD->getAttrs().hasAttribute<NonMutatingAttr>()) {
16721672
return SelfAccessKind::NonMutating;
1673+
} else if (FD->getAttrs().hasAttribute<LegacyConsumingAttr>()) {
1674+
return SelfAccessKind::LegacyConsuming;
16731675
} else if (FD->getAttrs().hasAttribute<ConsumingAttr>()) {
16741676
return SelfAccessKind::Consuming;
1677+
} else if (FD->getAttrs().hasAttribute<BorrowingAttr>()) {
1678+
return SelfAccessKind::Borrowing;
16751679
}
16761680

16771681
if (auto *AD = dyn_cast<AccessorDecl>(FD)) {
@@ -2167,12 +2171,29 @@ ParamSpecifierRequest::evaluate(Evaluator &evaluator,
21672171
auto *dc = param->getDeclContext();
21682172

21692173
if (param->isSelfParameter()) {
2170-
auto selfParam = computeSelfParam(cast<AbstractFunctionDecl>(dc),
2174+
auto afd = cast<AbstractFunctionDecl>(dc);
2175+
auto selfParam = computeSelfParam(afd,
21712176
/*isInitializingCtor*/true,
21722177
/*wantDynamicSelf*/false);
2173-
return (selfParam.getParameterFlags().isInOut()
2174-
? ParamSpecifier::InOut
2175-
: ParamSpecifier::Default);
2178+
if (auto fd = dyn_cast<FuncDecl>(afd)) {
2179+
switch (fd->getSelfAccessKind()) {
2180+
case SelfAccessKind::LegacyConsuming:
2181+
return ParamSpecifier::LegacyOwned;
2182+
case SelfAccessKind::Consuming:
2183+
return ParamSpecifier::Consuming;
2184+
case SelfAccessKind::Borrowing:
2185+
return ParamSpecifier::Borrowing;
2186+
case SelfAccessKind::Mutating:
2187+
return ParamSpecifier::InOut;
2188+
case SelfAccessKind::NonMutating:
2189+
return ParamSpecifier::Default;
2190+
}
2191+
llvm_unreachable("nonexhaustive switch");
2192+
} else {
2193+
return (selfParam.getParameterFlags().isInOut()
2194+
? ParamSpecifier::InOut
2195+
: ParamSpecifier::Default);
2196+
}
21762197
}
21772198

21782199
if (auto *accessor = dyn_cast<AccessorDecl>(dc)) {

lib/Sema/TypeCheckDeclOverride.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,7 @@ namespace {
14891489
UNINTERESTING_ATTR(Alignment)
14901490
UNINTERESTING_ATTR(AlwaysEmitIntoClient)
14911491
UNINTERESTING_ATTR(Borrowed)
1492+
UNINTERESTING_ATTR(Borrowing)
14921493
UNINTERESTING_ATTR(CDecl)
14931494
UNINTERESTING_ATTR(Consuming)
14941495
UNINTERESTING_ATTR(Documentation)
@@ -1519,6 +1520,7 @@ namespace {
15191520
UNINTERESTING_ATTR(MoveOnly)
15201521
UNINTERESTING_ATTR(FixedLayout)
15211522
UNINTERESTING_ATTR(Lazy)
1523+
UNINTERESTING_ATTR(LegacyConsuming)
15221524
UNINTERESTING_ATTR(LLDBDebuggerFunction)
15231525
UNINTERESTING_ATTR(Mutating)
15241526
UNINTERESTING_ATTR(NonMutating)

lib/Sema/TypeCheckProtocol.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -3591,8 +3591,10 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
35913591

35923592
// FIXME: Once we support move-only types in generics, remove this if the
35933593
// conforming type is move-only. Until then, don't suggest printing
3594-
// __consuming on a protocol requirement.
3594+
// ownership modifiers on a protocol requirement.
3595+
Options.ExcludeAttrList.push_back(DAK_LegacyConsuming);
35953596
Options.ExcludeAttrList.push_back(DAK_Consuming);
3597+
Options.ExcludeAttrList.push_back(DAK_Borrowing);
35963598

35973599
Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) {
35983600
Printer << " {";

lib/Sema/TypeCheckStmt.cpp

+15-5
Original file line numberDiff line numberDiff line change
@@ -1324,13 +1324,23 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
13241324
// The 'self' parameter must be owned (aka "consuming").
13251325
if (!diagnosed) {
13261326
bool isConsuming = false;
1327-
if (auto *funcDecl = dyn_cast<FuncDecl>(fn))
1328-
isConsuming = funcDecl->isConsuming();
1329-
else if (auto *accessor = dyn_cast<AccessorDecl>(fn))
1330-
isConsuming = accessor->isConsuming();
1331-
else if (isa<ConstructorDecl>(fn))
1327+
if (auto *funcDecl = dyn_cast<FuncDecl>(fn)) {
1328+
switch (funcDecl->getSelfAccessKind()) {
1329+
case SelfAccessKind::LegacyConsuming:
1330+
case SelfAccessKind::Consuming:
1331+
isConsuming = true;
1332+
break;
1333+
1334+
case SelfAccessKind::Borrowing:
1335+
case SelfAccessKind::NonMutating:
1336+
case SelfAccessKind::Mutating:
1337+
isConsuming = false;
1338+
break;
1339+
}
1340+
} else if (isa<ConstructorDecl>(fn)) {
13321341
// constructors are implicitly "consuming" of the self instance.
13331342
isConsuming = true;
1343+
}
13341344

13351345
if (!isConsuming) {
13361346
ctx.Diags.diagnose(FS->getForgetLoc(),

lib/Serialization/Deserialization.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2508,8 +2508,12 @@ getActualSelfAccessKind(uint8_t raw) {
25082508
return swift::SelfAccessKind::NonMutating;
25092509
case serialization::SelfAccessKind::Mutating:
25102510
return swift::SelfAccessKind::Mutating;
2511+
case serialization::SelfAccessKind::LegacyConsuming:
2512+
return swift::SelfAccessKind::LegacyConsuming;
25112513
case serialization::SelfAccessKind::Consuming:
25122514
return swift::SelfAccessKind::Consuming;
2515+
case serialization::SelfAccessKind::Borrowing:
2516+
return swift::SelfAccessKind::Borrowing;
25132517
}
25142518
return None;
25152519
}

lib/Serialization/ModuleFormat.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 746; // `consuming` and `borrowing` parameter modifiers
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 747; // `consuming` and `borrowing` decl modifiers
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -405,9 +405,11 @@ using MetatypeRepresentationField = BCFixed<2>;
405405
enum class SelfAccessKind : uint8_t {
406406
NonMutating = 0,
407407
Mutating,
408+
LegacyConsuming,
408409
Consuming,
410+
Borrowing
409411
};
410-
using SelfAccessKindField = BCFixed<2>;
412+
using SelfAccessKindField = BCFixed<3>;
411413

412414
/// Translates an operator decl fixity to a Serialization fixity, whose values
413415
/// are guaranteed to be stable.

lib/Serialization/Serialization.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2216,8 +2216,12 @@ getStableSelfAccessKind(swift::SelfAccessKind MM) {
22162216
return serialization::SelfAccessKind::NonMutating;
22172217
case swift::SelfAccessKind::Mutating:
22182218
return serialization::SelfAccessKind::Mutating;
2219+
case swift::SelfAccessKind::LegacyConsuming:
2220+
return serialization::SelfAccessKind::LegacyConsuming;
22192221
case swift::SelfAccessKind::Consuming:
22202222
return serialization::SelfAccessKind::Consuming;
2223+
case swift::SelfAccessKind::Borrowing:
2224+
return serialization::SelfAccessKind::Borrowing;
22212225
}
22222226

22232227
llvm_unreachable("Unhandled StaticSpellingKind in switch.");

0 commit comments

Comments
 (0)