Skip to content

Commit c832696

Browse files
Merge pull request #80889 from nate-chandler/rdar149352777
[CoroutineAccessors] Require underscored override.
2 parents e55c9bf + c28d295 commit c832696

File tree

5 files changed

+148
-9
lines changed

5 files changed

+148
-9
lines changed

include/swift/AST/AvailabilityContext.h

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class AvailabilityContext {
7575
/// of the given declaration.
7676
static AvailabilityContext forDeclSignature(const Decl *decl);
7777

78+
/// Returns the unconstrained availability context.
79+
static AvailabilityContext forAlwaysAvailable(const ASTContext &ctx);
80+
7881
/// Returns the range of platform versions which may execute code in the
7982
/// availability context, starting at its introduction version.
8083
// FIXME: [availability] Remove; superseded by getAvailableRange().

lib/AST/AvailabilityContext.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,13 @@ AvailabilityContext AvailabilityContext::forDeclSignature(const Decl *decl) {
214214
return forLocation(decl->getLoc(), decl->getInnermostDeclContext());
215215
}
216216

217+
AvailabilityContext
218+
AvailabilityContext::forAlwaysAvailable(const ASTContext &ctx) {
219+
return AvailabilityContext(Storage::get(AvailabilityRange::alwaysAvailable(),
220+
/*isDeprecated=*/false,
221+
/*domainInfos=*/{}, ctx));
222+
}
223+
217224
AvailabilityRange AvailabilityContext::getPlatformRange() const {
218225
return storage->platformRange;
219226
}

lib/Sema/TypeCheckStorage.cpp

+52-9
Original file line numberDiff line numberDiff line change
@@ -2670,25 +2670,42 @@ RequiresOpaqueAccessorsRequest::evaluate(Evaluator &evaluator,
26702670
///
26712671
/// The underscored accessor could, however, still be required for ABI
26722672
/// stability.
2673-
bool AbstractStorageDecl::requiresCorrespondingUnderscoredCoroutineAccessor(
2674-
AccessorKind kind, AccessorDecl const *decl) const {
2675-
auto &ctx = getASTContext();
2673+
static bool requiresCorrespondingUnderscoredCoroutineAccessorImpl(
2674+
AbstractStorageDecl const *storage, AccessorKind kind,
2675+
AccessorDecl const *decl, AbstractStorageDecl const *derived) {
2676+
auto &ctx = storage->getASTContext();
26762677
assert(ctx.LangOpts.hasFeature(Feature::CoroutineAccessors));
26772678
assert(kind == AccessorKind::Modify2 || kind == AccessorKind::Read2);
26782679

2680+
// If any overridden decl requires the underscored version, then this decl
2681+
// does too. Otherwise dispatch to the underscored version on a value
2682+
// statically the super but dynamically this subtype would not dispatch to an
2683+
// override of the underscored version but rather (incorrectly) the
2684+
// supertype's implementation.
2685+
if (storage == derived) {
2686+
auto *current = storage;
2687+
while ((current = current->getOverriddenDecl())) {
2688+
auto *currentDecl = cast_or_null<AccessorDecl>(
2689+
decl ? decl->getOverriddenDecl() : nullptr);
2690+
if (requiresCorrespondingUnderscoredCoroutineAccessorImpl(
2691+
current, kind, currentDecl, derived)) {
2692+
return true;
2693+
}
2694+
}
2695+
}
2696+
26792697
// Non-stable modules have no ABI to keep stable.
2680-
if (getModuleContext()->getResilienceStrategy() !=
2698+
if (storage->getModuleContext()->getResilienceStrategy() !=
26812699
ResilienceStrategy::Resilient)
26822700
return false;
26832701

26842702
// Non-exported storage has no ABI to keep stable.
2685-
if (!isExported(this))
2703+
if (!isExported(storage))
26862704
return false;
26872705

26882706
// The non-underscored accessor is not present, the underscored accessor
26892707
// won't be either.
2690-
// TODO: CoroutineAccessors: What if only the underscored is written out?
2691-
auto *accessor = decl ? decl : getOpaqueAccessor(kind);
2708+
auto *accessor = decl ? decl : storage->getOpaqueAccessor(kind);
26922709
if (!accessor)
26932710
return false;
26942711

@@ -2699,17 +2716,43 @@ bool AbstractStorageDecl::requiresCorrespondingUnderscoredCoroutineAccessor(
26992716
if (!ctx.supportsVersionedAvailability())
27002717
return true;
27012718

2702-
auto modifyAvailability = AvailabilityContext::forLocation({}, accessor);
2719+
AvailabilityContext accessorAvailability = [&] {
2720+
if (storage->getModuleContext()->isMainModule()) {
2721+
return AvailabilityContext::forDeclSignature(accessor);
2722+
}
2723+
// Calculate the availability of the imported declaration ourselves starting
2724+
// from always available and constraining by walking the enclosing decl
2725+
// contexts.
2726+
auto retval = AvailabilityContext::forAlwaysAvailable(ctx);
2727+
auto declContext = storage->getInnermostDeclContext();
2728+
while (declContext) {
2729+
const Decl *decl = declContext->getInnermostDeclarationDeclContext();
2730+
if (!decl)
2731+
break;
2732+
2733+
retval.constrainWithDecl(decl);
2734+
declContext = decl->getDeclContext();
2735+
}
2736+
return retval;
2737+
}();
27032738
auto featureAvailability = ctx.getCoroutineAccessorsAvailability();
27042739
// If accessor was introduced only after the feature was, there's no old ABI
27052740
// to maintain.
2706-
if (modifyAvailability.getPlatformRange().isContainedIn(featureAvailability))
2741+
if (accessorAvailability.getPlatformRange().isContainedIn(
2742+
featureAvailability))
27072743
return false;
27082744

27092745
// The underscored accessor is required for ABI stability.
27102746
return true;
27112747
}
27122748

2749+
bool AbstractStorageDecl::requiresCorrespondingUnderscoredCoroutineAccessor(
2750+
AccessorKind kind, AccessorDecl const *decl) const {
2751+
return requiresCorrespondingUnderscoredCoroutineAccessorImpl(
2752+
this, kind, decl,
2753+
/*derived=*/this);
2754+
}
2755+
27132756
bool RequiresOpaqueModifyCoroutineRequest::evaluate(
27142757
Evaluator &evaluator, AbstractStorageDecl *storage,
27152758
bool isUnderscored) const {

test/SILGen/coroutine_accessors.swift

+46
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,52 @@ mutating func update(irm newValue: Int) throws -> Int {
160160
try coroutine_accessors.update(at: &irm, to: newValue)
161161
}
162162

163+
public var i_r_m: Int {
164+
// CHECK-LABEL: sil{{.*}} [ossa] @$s19coroutine_accessors1SV5i_r_mSivr :
165+
// CHECK-SAME: $@yield_once
166+
// CHECK-SAME: @convention(method)
167+
// CHECK-SAME: (@guaranteed S)
168+
// CHECK-SAME: ->
169+
// CHECK-SAME: @yields Int
170+
// CHECK-SAME: {
171+
// CHECK: } // end sil function '$s19coroutine_accessors1SV5i_r_mSivr'
172+
173+
_read {
174+
yield _i
175+
}
176+
// CHECK-NOT: sil [ossa] @$s19coroutine_accessors1SV5i_r_mSivx :
177+
// CHECK-LABEL: sil {{.*}}[ossa] @$s19coroutine_accessors1SV5i_r_mSivM :
178+
// CHECK-SAME: $@yield_once
179+
// CHECK-SAME: @convention(method)
180+
// CHECK-SAME: (@inout S)
181+
// CHECK-SAME: ->
182+
// CHECK-SAME: @yields @inout Int
183+
// CHECK-SAME: {
184+
// CHECK: } // end sil function '$s19coroutine_accessors1SV5i_r_mSivM'
185+
_modify {
186+
yield &_i
187+
}
188+
// CHECK-LABEL: sil {{.*}}[ossa] @$s19coroutine_accessors1SV5i_r_mSivs :
189+
// CHECK-SAME: $@convention(method)
190+
// CHECK-SAME: (Int, @inout S)
191+
// CHECK-SAME: ->
192+
// CHECK-SAME: ()
193+
// CHECK-SAME: {
194+
// CHECK: bb0(
195+
// CHECK-SAME: [[NEW_VALUE:%[^,]+]] :
196+
// CHECK-SAME: [[SELF:%[^,]+]] :
197+
// CHECK-SAME: ):
198+
// CHECK: [[SELF_ACCESS:%[^,]+]] = begin_access [modify] [unknown] [[SELF]]
199+
// CHECK: [[MODIFY_ACCESSOR:%[^,]+]] = function_ref @$s19coroutine_accessors1SV5i_r_mSivM
200+
// CHECK: ([[VALUE_ADDRESS:%[^,]+]],
201+
// CHECK-SAME: [[TOKEN:%[^)]+]])
202+
// CHECK-SAME: = begin_apply [[MODIFY_ACCESSOR]]([[SELF_ACCESS]])
203+
// CHECK: assign [[NEW_VALUE:%[^,]+]] to [[VALUE_ADDRESS]]
204+
// CHECK: end_apply [[TOKEN]]
205+
// CHECK: end_access [[SELF_ACCESS]]
206+
// CHECK-LABEL:} // end sil function '$s19coroutine_accessors1SV5i_r_mSivs'
207+
} // public var irm
208+
163209
} // public struct S
164210

165211
enum E : Error {

test/SILGen/coroutine_accessors_availability.swift

+40
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,21 @@ public func modifyOldNoninlinableNew(_ n: inout StructOld) {
223223
public func takeInt(_ i: Int) {
224224
}
225225

226+
open class BaseClassOld {
227+
public init(_ i : Int) {
228+
self._i = i
229+
}
230+
var _i: Int
231+
open var i: Int {
232+
read {
233+
yield _i
234+
}
235+
modify {
236+
yield &_i
237+
}
238+
}
239+
}
240+
226241
//--- Downstream.swift
227242

228243
import Library
@@ -348,3 +363,28 @@ func modifyOldOld() {
348363

349364
n.i.increment()
350365
}
366+
367+
public class DerivedOldFromBaseClassOld : BaseClassOld {
368+
public init(_ i : Int, _ j : Int) {
369+
self._j = j
370+
super.init(i)
371+
}
372+
var _j: Int
373+
override public var i: Int {
374+
read {
375+
yield _j
376+
}
377+
modify {
378+
yield &_j
379+
}
380+
}
381+
}
382+
383+
// CHECK-LABEL: sil_vtable [serialized] DerivedOldFromBaseClassOld {
384+
// CHECK-NEXT: #BaseClassOld.init!allocator
385+
// CHECK-NEXT: #BaseClassOld.i!read
386+
// CHECK-NEXT: #BaseClassOld.i!read2
387+
// CHECK-NEXT: #BaseClassOld.i!setter
388+
// CHECK-NEXT: #BaseClassOld.i!modify
389+
// CHECK-NEXT: #BaseClassOld.i!modify2
390+
// CHECK: }

0 commit comments

Comments
 (0)