diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index b029c970746ad..47985eb224145 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -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; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0a2614d9d015e..cc57bfe32bf72 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -10921,6 +10921,39 @@ ArrayRef AccessorDecl::getAccessedProperties() const { return {}; } +bool AccessorDecl::isRequirementWithSynthesizedDefaultImplementation() const { + if (!isa(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(accessor->getDeclContext())) { + return isRequirementWithSynthesizedDefaultImplementation(); + } + + // NSManaged getters and setters don't have bodies. + if (storage->getAttrs().hasAttribute(/*AllowInvalid=*/true)) + if (accessor->isGetterOrSetter()) + return false; + + return true; +} + StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const { assert(getDeclContext()->isTypeContext()); if (!isStatic()) diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 57b50b414366b..d18a12d9833b2 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -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; @@ -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); @@ -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); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index e4bde168694de..a45a97c22a991 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -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(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(/*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, @@ -2798,6 +2770,11 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, if (accessor->getAttrs().hasAttribute()) return true; + // Default implementations of read2 and modify2 provided for back-deployment + // are transparent. + if (accessor->isRequirementWithSynthesizedDefaultImplementation()) + return true; + if (!accessor->isImplicit()) return false; diff --git a/test/SILGen/coroutine_accessors_skip.swift b/test/SILGen/coroutine_accessors_skip.swift new file mode 100644 index 0000000000000..d5717302be901 --- /dev/null +++ b/test/SILGen/coroutine_accessors_skip.swift @@ -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 } +} diff --git a/test/SILGen/read_requirements.swift b/test/SILGen/read_requirements.swift index 5354f56a5a393..dee6d8bb78815 100644 --- a/test/SILGen/read_requirements.swift +++ b/test/SILGen/read_requirements.swift @@ -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: ):