Skip to content

Commit

Permalink
Merge pull request swiftlang#77661 from nate-chandler/general-coro/20…
Browse files Browse the repository at this point in the history
…241115/1

[CoroutineAccessors] Default implementations are transparent.
  • Loading branch information
nate-chandler authored Mar 7, 2025
2 parents 7cab35b + bdf662a commit 38c8cc8
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 32 deletions.
5 changes: 5 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8624,6 +8624,11 @@ class AccessorDecl final : public FuncDecl {
/// even when it does not have one _yet_.
bool doesAccessorHaveBody() const;

/// Whether this accessor is a protocol requirement for which a default
/// implementation must be provided for back-deployment. For example, read2
/// and modify2 requirements with early enough availability.
bool isRequirementWithSynthesizedDefaultImplementation() const;

static bool classof(const Decl *D) {
return D->getKind() == DeclKind::Accessor;
}
Expand Down
33 changes: 33 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10921,6 +10921,39 @@ ArrayRef<VarDecl *> AccessorDecl::getAccessedProperties() const {
return {};
}

bool AccessorDecl::isRequirementWithSynthesizedDefaultImplementation() const {
if (!isa<ProtocolDecl>(getDeclContext()))
return false;

if (!getASTContext().LangOpts.hasFeature(Feature::CoroutineAccessors)) {
return false;
}
if (!requiresFeatureCoroutineAccessors(getAccessorKind())) {
return false;
}
if (getStorage()->getOverrideLoc()) {
return false;
}
return getStorage()->requiresCorrespondingUnderscoredCoroutineAccessor(
getAccessorKind(), this);
}

bool AccessorDecl::doesAccessorHaveBody() const {
auto *accessor = this;
auto *storage = accessor->getStorage();

if (isa<ProtocolDecl>(accessor->getDeclContext())) {
return isRequirementWithSynthesizedDefaultImplementation();
}

// NSManaged getters and setters don't have bodies.
if (storage->getAttrs().hasAttribute<NSManagedAttr>(/*AllowInvalid=*/true))
if (accessor->isGetterOrSetter())
return false;

return true;
}

StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const {
assert(getDeclContext()->isTypeContext());
if (!isStatic())
Expand Down
6 changes: 3 additions & 3 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3913,7 +3913,7 @@ static bool isCurrentFunctionAccessor(SILGenFunction &SGF,
contextAccessorDecl->getAccessorKind() == accessorKind;
}

static bool isSynthesizedDefaultImplementionatThunk(SILGenFunction &SGF) {
static bool isSynthesizedDefaultImplementionThunk(SILGenFunction &SGF) {
if (!SGF.FunctionDC)
return false;

Expand Down Expand Up @@ -3956,7 +3956,7 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
AccessStrategy strategy = var->getAccessStrategy(
accessSemantics, getFormalAccessKind(accessKind),
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
/*useOldABI=*/isSynthesizedDefaultImplementionatThunk(SGF));
/*useOldABI=*/isSynthesizedDefaultImplementionThunk(SGF));

bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);

Expand Down Expand Up @@ -4165,7 +4165,7 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
auto strategy = decl->getAccessStrategy(
accessSemantics, getFormalAccessKind(accessKind),
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
/*useOldABI=*/isSynthesizedDefaultImplementionatThunk(SGF));
/*useOldABI=*/isSynthesizedDefaultImplementionThunk(SGF));

bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);
bool isContextRead = isCurrentFunctionAccessor(SGF, AccessorKind::Read);
Expand Down
33 changes: 5 additions & 28 deletions lib/Sema/TypeCheckStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -948,34 +948,6 @@ buildIndexForwardingParamList(AbstractStorageDecl *storage,
return ParameterList::create(context, elements);
}

bool AccessorDecl::doesAccessorHaveBody() const {
auto *accessor = this;
auto *storage = accessor->getStorage();

if (isa<ProtocolDecl>(accessor->getDeclContext())) {
if (!accessor->getASTContext().LangOpts.hasFeature(
Feature::CoroutineAccessors)) {
return false;
}
if (!requiresFeatureCoroutineAccessors(accessor->getAccessorKind())) {
return false;
}
if (storage->getOverrideLoc()) {
return false;
}
return accessor->getStorage()
->requiresCorrespondingUnderscoredCoroutineAccessor(
accessor->getAccessorKind(), accessor);
}

// NSManaged getters and setters don't have bodies.
if (storage->getAttrs().hasAttribute<NSManagedAttr>(/*AllowInvalid=*/true))
if (accessor->isGetterOrSetter())
return false;

return true;
}

/// Build an argument list referencing the subscript parameters for this
/// subscript accessor.
static ArgumentList *buildSubscriptArgumentList(ASTContext &ctx,
Expand Down Expand Up @@ -2798,6 +2770,11 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator,
if (accessor->getAttrs().hasAttribute<TransparentAttr>())
return true;

// Default implementations of read2 and modify2 provided for back-deployment
// are transparent.
if (accessor->isRequirementWithSynthesizedDefaultImplementation())
return true;

if (!accessor->isImplicit())
return false;

Expand Down
33 changes: 33 additions & 0 deletions test/SILGen/coroutine_accessors_skip.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %target-swift-emit-silgen \
// RUN: %s \
// RUN: -experimental-skip-non-inlinable-function-bodies \
// RUN: -enable-library-evolution \
// RUN: -enable-experimental-feature CoroutineAccessors \
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NOUNWIND

// RUN: %target-swift-emit-silgen \
// RUN: %s \
// RUN: -experimental-skip-non-inlinable-function-bodies \
// RUN: -enable-library-evolution \
// RUN: -enable-experimental-feature CoroutineAccessors \
// RUN: -enable-experimental-feature CoroutineAccessorsUnwindOnCallerError \
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-UNWIND

// REQUIRES: swift_feature_CoroutineAccessors
// REQUIRES: swift_feature_CoroutineAccessorsUnwindOnCallerError

// CHECK-LABEL: sil_default_witness_table MutatableAssociatedField {
// CHECK-NEXT: no_default
// CHECK-NEXT: no_default
// CHECK-NEXT: method #MutatableAssociatedField.field!read2
// CHECK-SAME: : @$s24coroutine_accessors_skip24MutatableAssociatedFieldP5field5AssocQzvy
// CHECK-NEXT: no_default
// CHECK-NEXT: no_default
// CHECK-NEXT: method #MutatableAssociatedField.field!modify2
// CHECK-SAME: : @$s24coroutine_accessors_skip24MutatableAssociatedFieldP5field5AssocQzvx
// CHECK-NEXT: }
public protocol MutatableAssociatedField {
associatedtype Assoc

var field: Assoc { read set }
}
2 changes: 1 addition & 1 deletion test/SILGen/read_requirements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public protocol P1 : ~Copyable {
// CHECK: unwind
// CHECK-LABEL: } // end sil function '$s17read_requirements2P1P4ubgsAA1UVvy'

// CHECK-LABEL: sil [ossa] @$s17read_requirements2P1P4ubgsAA1UVvx : {{.*}} {
// CHECK-LABEL: sil{{.*}} [ossa] @$s17read_requirements2P1P4ubgsAA1UVvx : {{.*}} {
// CHECK: bb0(
// CHECK-SAME: [[SELF_UNCHECKED:%[^:]+]]
// CHECK-SAME: ):
Expand Down

0 comments on commit 38c8cc8

Please sign in to comment.