diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index c070e1e0c42de..cef4f821235f5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1798,9 +1798,16 @@ ERROR(mutating_invalid_classes,none, "%0 is not valid on %kindonly1s in " ERROR(functions_mutating_and_not,none, "method must not be declared both %0 and %1", (SelfAccessKind, SelfAccessKind)) + ERROR(static_functions_not_mutating,none, "static functions must not be declared mutating", ()) +ERROR(consuming_invalid_borrow_mutate_accessor, none, + "%0 cannot be declared consuming", (StringRef)) + +ERROR(ownership_modifier_unsupported_borrow_mutate_accessor, none, + "%0 ownership modifier is not yet supported on %1", (StringRef, StringRef)) + ERROR(readwriter_mutatingness_differs_from_reader_or_writer_mutatingness,none, "%0 cannot be %1 when " "%select{both the %3 is %4 and the %5 is not %6|either the %3 is not %4 or the %5 is %6|the %3 is not %4|the %5 is %6}2", diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a90887793eced..531f93de2bf2f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3264,6 +3264,10 @@ static AccessStrategy getOpaqueReadAccessStrategy( return AccessStrategy::getAccessor(AccessorKind::Read2, dispatch); if (storage->requiresOpaqueReadCoroutine()) return AccessStrategy::getAccessor(AccessorKind::Read, dispatch); + + if (storage->getParsedAccessor(AccessorKind::Borrow)) { + return AccessStrategy::getAccessor(AccessorKind::Borrow, dispatch); + } return AccessStrategy::getAccessor(AccessorKind::Get, dispatch); } @@ -3435,11 +3439,6 @@ bool AbstractStorageDecl::requiresOpaqueSetter() const { if (!supportsMutation()) { return false; } - - // If a mutate accessor is present, we don't need a setter. - if (getAccessor(AccessorKind::Mutate)) { - return false; - } return true; } @@ -3450,7 +3449,7 @@ bool AbstractStorageDecl::requiresOpaqueReadCoroutine() const { AccessorKind::Read2); // If a borrow accessor is present, we don't need a read coroutine. - if (getAccessor(AccessorKind::Borrow)) { + if (getParsedAccessor(AccessorKind::Borrow)) { return false; } return getOpaqueReadOwnership() != OpaqueReadOwnership::Owned; @@ -3462,7 +3461,7 @@ bool AbstractStorageDecl::requiresOpaqueRead2Coroutine() const { return false; // If a borrow accessor is present, we don't need a read coroutine. - if (getAccessor(AccessorKind::Borrow)) { + if (getParsedAccessor(AccessorKind::Borrow)) { return false; } return getOpaqueReadOwnership() != OpaqueReadOwnership::Owned; @@ -7595,7 +7594,7 @@ StringRef swift::getAccessorNameForDiagnostic(AccessorKind accessorKind, case AccessorKind::Init: return article ? "an init accessor" : "init accessor"; case AccessorKind::Borrow: - return article ? " a 'borrow' accessor" : "borrow accessor"; + return article ? "a 'borrow' accessor" : "borrow accessor"; case AccessorKind::Mutate: return article ? "a 'mutate' accessor" : "mutate accessor"; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index d7f039864f12a..18c85bc97269a 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -708,6 +708,31 @@ void AttributeChecker::visitMutationAttr(DeclAttribute *attr) { // Verify that we don't have a static function. if (FD->isStatic()) diagnoseAndRemoveAttr(attr, diag::static_functions_not_mutating); + + auto *accessor = dyn_cast(FD); + if (accessor && + (accessor->isBorrowAccessor() || accessor->isMutateAccessor())) { + if (attrModifier == SelfAccessKind::Consuming || + attrModifier == SelfAccessKind::LegacyConsuming) { + diagnoseAndRemoveAttr( + attr, diag::consuming_invalid_borrow_mutate_accessor, + getAccessorNameForDiagnostic(accessor, /*article*/ true)); + } + if (attrModifier == SelfAccessKind::NonMutating && + accessor->isMutateAccessor()) { + diagnoseAndRemoveAttr( + attr, diag::ownership_modifier_unsupported_borrow_mutate_accessor, + attr->getAttrName(), + getAccessorNameForDiagnostic(accessor, /*article*/ true)); + } + if (attrModifier == SelfAccessKind::Mutating && + accessor->isBorrowAccessor()) { + diagnoseAndRemoveAttr( + attr, diag::ownership_modifier_unsupported_borrow_mutate_accessor, + attr->getAttrName(), + getAccessorNameForDiagnostic(accessor, /*article*/ true)); + } + } } void AttributeChecker::visitDynamicAttr(DynamicAttr *attr) { diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index b4533b79623e9..4bbb1e5f49477 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -1875,6 +1875,13 @@ synthesizeModify2CoroutineSetterBody(AccessorDecl *setter, ASTContext &ctx) { setter, TargetImpl::Implementation, setter->getStorage(), ctx); } +static std::pair +synthesizeMutateSetterBody(AccessorDecl *setter, ASTContext &ctx) { + // This should call the mutate accessor. + return synthesizeTrivialSetterBodyWithStorage( + setter, TargetImpl::Implementation, setter->getStorage(), ctx); +} + static Expr *maybeWrapInOutExpr(Expr *expr, ASTContext &ctx) { if (auto lvalueType = expr->getType()->getAs()) { auto type = lvalueType->getObjectType(); @@ -2071,7 +2078,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) { return synthesizeModify2CoroutineSetterBody(setter, ctx); case WriteImplKind::Mutate: - llvm_unreachable("synthesizing setter from mutate"); + return synthesizeMutateSetterBody(setter, ctx); } llvm_unreachable("bad WriteImplKind"); } @@ -2476,7 +2483,9 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, } break; case WriteImplKind::Mutate: - llvm_unreachable("mutate accessor is not yet implemented"); + if (auto mutate = storage->getOpaqueAccessor(AccessorKind::Mutate)) { + asAvailableAs.push_back(mutate); + } } if (!asAvailableAs.empty()) { @@ -2804,11 +2813,6 @@ bool RequiresOpaqueModifyCoroutineRequest::evaluate( if (protoDecl->isObjC()) return false; - // If a mutate accessor is present, we don't need a modify coroutine - if (storage->getAccessor(AccessorKind::Mutate)) { - return false; - } - return true; } @@ -2937,9 +2941,8 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, case WriteImplKind::MutableAddress: case WriteImplKind::Modify: case WriteImplKind::Modify2: - break; case WriteImplKind::Mutate: - llvm_unreachable("mutate accessor is not yet implemented"); + break; } break; @@ -2950,14 +2953,12 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, case AccessorKind::Init: break; case AccessorKind::Borrow: - llvm_unreachable("borrow accessor is not yet implemented"); case AccessorKind::WillSet: case AccessorKind::DidSet: case AccessorKind::Address: case AccessorKind::MutableAddress: - llvm_unreachable("bad synthesized function kind"); case AccessorKind::Mutate: - llvm_unreachable("mutate accessor is not yet implemented"); + llvm_unreachable("bad synthesized function kind"); } switch (storage->getReadWriteImpl()) { diff --git a/test/IRGen/borrow_accessor_large.swift b/test/IRGen/borrow_accessor_large.swift index 753e6a95e3f9c..8b8dfec0980ca 100644 --- a/test/IRGen/borrow_accessor_large.swift +++ b/test/IRGen/borrow_accessor_large.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -c %s -Xllvm -sil-print-after=loadable-address -enable-experimental-feature BorrowAndMutateAccessors 2>&1 | %FileCheck %s +// RUN: %target-swift-frontend -emit-irgen %s -enable-experimental-feature BorrowAndMutateAccessors 2>&1 | %FileCheck --check-prefixes=CHECK-IRGEN %s // REQUIRES: swift_feature_BorrowAndMutateAccessors // REQUIRES: OS=macosx @@ -137,9 +138,9 @@ func nctest() { // CHECK: } // IRGen result type is PtrTy because we are returning a class reference -// CHECK-IRGEN: define hidden swiftcc ptr @"$s21borrow_accessor_large11LargeStructV0A5KlassAA0F0Cvb"(ptr noalias nocapture swiftself dereferenceable(208) [[REG0]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc ptr @"$s21borrow_accessor_large11LargeStructV0A5KlassAA0F0Cvb"(ptr noalias swiftself captures(none) dereferenceable(208) [[REG0:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._k = getelementptr inbounds %T21borrow_accessor_large11LargeStructV, ptr [[REG0]], i32 0, i32 0 +// CHECK-IRGEN: %._k = getelementptr inbounds nuw %T21borrow_accessor_large11LargeStructV, ptr [[REG0]], i32 0, i32 0 // CHECK-IRGEN: [[REG1:%.*]] = load ptr, ptr %._k, align 8 // CHECK-IRGEN: ret ptr [[REG1]] // CHECK-IRGEN: } @@ -151,11 +152,11 @@ func nctest() { // CHECK: return [[REG3]] // CHECK: } -// CHECK-IRGEN: define hidden swiftcc i64 @"$s21borrow_accessor_large11LargeStructV0a5SmallE0AA0fE0Vvb"(ptr noalias nocapture swiftself dereferenceable(208) [[REG0]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc i64 @"$s21borrow_accessor_large11LargeStructV0a5SmallE0AA0fE0Vvb"(ptr noalias swiftself captures(none) dereferenceable(208) [[REG0:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._smallStruct = getelementptr inbounds %T21borrow_accessor_large11LargeStructV, ptr [[REG0]], i32 0, i32 4 -// CHECK-IRGEN: %._smallStruct.id = getelementptr inbounds %T21borrow_accessor_large11SmallStructV, ptr %._smallStruct, i32 0, i32 0 -// CHECK-IRGEN: %._smallStruct.id._value = getelementptr inbounds %TSi, ptr %._smallStruct.id, i32 0, i32 0 +// CHECK-IRGEN: %._smallStruct = getelementptr inbounds nuw %T21borrow_accessor_large11LargeStructV, ptr [[REG0]], i32 0, i32 4 +// CHECK-IRGEN: %._smallStruct.id = getelementptr inbounds nuw %T21borrow_accessor_large11SmallStructV, ptr %._smallStruct, i32 0, i32 0 +// CHECK-IRGEN: %._smallStruct.id._value = getelementptr inbounds nuw %TSi, ptr %._smallStruct.id, i32 0, i32 0 // CHECK-IRGEN: [[REG1:%.*]] = load i64, ptr %._smallStruct.id._value, align 8 // CHECK-IRGEN: ret i64 [[REG1]] // CHECK-IRGEN: } @@ -169,9 +170,9 @@ func nctest() { // CHECK: return [[REG5]] // CHECK: } -// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large11LargeStructV0C10PropBorrowAA0dF0Vvb"(ptr noalias nocapture sret(%T21borrow_accessor_large9LargePropV) [[REG0]], ptr noalias nocapture swiftself dereferenceable(208) [[REG1]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large11LargeStructV0C10PropBorrowAA0dF0Vvb"(ptr noalias sret(%T21borrow_accessor_large9LargePropV) captures(none) [[REG0:%.*]], ptr noalias swiftself captures(none) dereferenceable(208) [[REG1:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._largeProp = getelementptr inbounds %T21borrow_accessor_large11LargeStructV, ptr [[REG1]], i32 0, i32 3 +// CHECK-IRGEN: %._largeProp = getelementptr inbounds nuw %T21borrow_accessor_large11LargeStructV, ptr [[REG1]], i32 0, i32 3 // CHECK-IRGEN: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[REG0]], ptr align 8 %._largeProp, i64 64, i1 false) // CHECK-IRGEN: ret void // CHECK-IRGEN: } @@ -184,40 +185,40 @@ func nctest() { // CHECK: return [[REG3]] // CHECK: } -// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large11LargeStructV0C11TupleBorrowAA5KlassC_A7Ftvb"(ptr noalias nocapture sret(<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>) [[REG0]], ptr noalias nocapture swiftself dereferenceable(208) [[REG1]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large11LargeStructV0C11TupleBorrowAA5KlassC_A7Ftvb"(ptr noalias sret(<{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>) captures(none) [[REG0:%.*]], ptr noalias swiftself captures(none) dereferenceable(208) [[REG1:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._largeTuple = getelementptr inbounds %T21borrow_accessor_large11LargeStructV, ptr [[REG1]], i32 0, i32 2 -// CHECK-IRGEN: %._largeTuple.elt = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 0 +// CHECK-IRGEN: %._largeTuple = getelementptr inbounds nuw %T21borrow_accessor_large11LargeStructV, ptr [[REG1]], i32 0, i32 2 +// CHECK-IRGEN: %._largeTuple.elt = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 0 // CHECK-IRGEN: [[REG2:%.*]] = load ptr, ptr %._largeTuple.elt, align 8 -// CHECK-IRGEN: %._largeTuple.elt1 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 1 +// CHECK-IRGEN: %._largeTuple.elt1 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 1 // CHECK-IRGEN: [[REG3:%.*]] = load ptr, ptr %._largeTuple.elt1, align 8 -// CHECK-IRGEN: %._largeTuple.elt2 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 2 +// CHECK-IRGEN: %._largeTuple.elt2 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 2 // CHECK-IRGEN: [[REG4:%.*]] = load ptr, ptr %._largeTuple.elt2, align 8 -// CHECK-IRGEN: %._largeTuple.elt3 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 3 +// CHECK-IRGEN: %._largeTuple.elt3 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 3 // CHECK-IRGEN: [[REG5:%.*]] = load ptr, ptr %._largeTuple.elt3, align 8 -// CHECK-IRGEN: %._largeTuple.elt4 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 4 +// CHECK-IRGEN: %._largeTuple.elt4 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 4 // CHECK-IRGEN: [[REG6:%.*]] = load ptr, ptr %._largeTuple.elt4, align 8 -// CHECK-IRGEN: %._largeTuple.elt5 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 5 +// CHECK-IRGEN: %._largeTuple.elt5 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 5 // CHECK-IRGEN: [[REG7:%.*]] = load ptr, ptr %._largeTuple.elt5, align 8 -// CHECK-IRGEN: %._largeTuple.elt6 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 6 +// CHECK-IRGEN: %._largeTuple.elt6 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 6 // CHECK-IRGEN: [[REG8:%.*]] = load ptr, ptr %._largeTuple.elt6, align 8 -// CHECK-IRGEN: %._largeTuple.elt7 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 7 +// CHECK-IRGEN: %._largeTuple.elt7 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr %._largeTuple, i32 0, i32 7 // CHECK-IRGEN: [[REG9:%.*]] = load ptr, ptr %._largeTuple.elt7, align 8 -// CHECK-IRGEN: %.elt = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 0 +// CHECK-IRGEN: %.elt = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 0 // CHECK-IRGEN: store ptr [[REG2]], ptr %.elt, align 8 -// CHECK-IRGEN: %.elt8 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 1 +// CHECK-IRGEN: %.elt8 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 1 // CHECK-IRGEN: store ptr [[REG3]], ptr %.elt8, align 8 -// CHECK-IRGEN: %.elt9 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 2 +// CHECK-IRGEN: %.elt9 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 2 // CHECK-IRGEN: store ptr [[REG4]], ptr %.elt9, align 8 -// CHECK-IRGEN: %.elt10 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 3 +// CHECK-IRGEN: %.elt10 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 3 // CHECK-IRGEN: store ptr [[REG5]], ptr %.elt10, align 8 -// CHECK-IRGEN: %.elt11 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 4 +// CHECK-IRGEN: %.elt11 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 4 // CHECK-IRGEN: store ptr [[REG6]], ptr %.elt11, align 8 -// CHECK-IRGEN: %.elt12 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 5 +// CHECK-IRGEN: %.elt12 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 5 // CHECK-IRGEN: store ptr [[REG7]], ptr %.elt12, align 8 -// CHECK-IRGEN: %.elt13 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 6 +// CHECK-IRGEN: %.elt13 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 6 // CHECK-IRGEN: store ptr [[REG8]], ptr %.elt13, align 8 -// CHECK-IRGEN: %.elt14 = getelementptr inbounds <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 7 +// CHECK-IRGEN: %.elt14 = getelementptr inbounds nuw <{ ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }>, ptr [[REG0]], i32 0, i32 7 // CHECK-IRGEN: store ptr [[REG9]], ptr %.elt14, align 8 // CHECK-IRGEN: ret void // CHECK-IRGEN: } @@ -229,11 +230,11 @@ func nctest() { // CHECK: return [[REG3]] // CHECK: } -// CHECK-IRGEN: define hidden swiftcc i64 @"$s21borrow_accessor_large13NCLargeStructV0A2NCAA0F0Vvb"(ptr noalias nocapture swiftself dereferenceable(72) [[REG0]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc i64 @"$s21borrow_accessor_large13NCLargeStructV0A2NCAA0F0Vvb"(ptr noalias swiftself captures(none) dereferenceable(72) [[REG0:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._k = getelementptr inbounds %T21borrow_accessor_large13NCLargeStructV, ptr [[REG0]], i32 0, i32 0 -// CHECK-IRGEN: %._k.id = getelementptr inbounds %T21borrow_accessor_large2NCV, ptr %._k, i32 0, i32 0 -// CHECK-IRGEN: %._k.id._value = getelementptr inbounds %TSi, ptr %._k.id, i32 0, i32 0 +// CHECK-IRGEN: %._k = getelementptr inbounds nuw %T21borrow_accessor_large13NCLargeStructV, ptr [[REG0]], i32 0, i32 0 +// CHECK-IRGEN: %._k.id = getelementptr inbounds nuw %T21borrow_accessor_large2NCV, ptr %._k, i32 0, i32 0 +// CHECK-IRGEN: %._k.id._value = getelementptr inbounds nuw %TSi, ptr %._k.id, i32 0, i32 0 // CHECK-IRGEN: [[REG1:%.*]] = load i64, ptr %._k.id._value, align 8 // CHECK-IRGEN: ret i64 [[REG1]] // CHECK-IRGEN: } @@ -247,9 +248,9 @@ func nctest() { // CHECK: return [[REG5]] // CHECK: } -// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large13NCLargeStructV0C10PropBorrowAA11LargeNCPropVvb"(ptr noalias nocapture sret(%T21borrow_accessor_large11LargeNCPropV) [[REG0]], ptr noalias nocapture swiftself dereferenceable(72) [[REG1]]) {{.*}} { +// CHECK-IRGEN: define hidden swiftcc void @"$s21borrow_accessor_large13NCLargeStructV0C10PropBorrowAA11LargeNCPropVvb"(ptr noalias sret(%T21borrow_accessor_large11LargeNCPropV) captures(none) [[REG0]], ptr noalias swiftself captures(none) dereferenceable(72) [[REG1:%.*]]) {{.*}} { // CHECK-IRGEN: entry: -// CHECK-IRGEN: %._largeProp = getelementptr inbounds %T21borrow_accessor_large13NCLargeStructV, ptr [[REG1]], i32 0, i32 1 +// CHECK-IRGEN: %._largeProp = getelementptr inbounds nuw %T21borrow_accessor_large13NCLargeStructV, ptr [[REG1]], i32 0, i32 1 // CHECK-IRGEN: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[REG0]], ptr align 8 %._largeProp, i64 64, i1 false) // CHECK-IRGEN: ret void // CHECK-IRGEN: } diff --git a/test/Parse/borrow_and_mutate_accessors.swift b/test/Parse/borrow_and_mutate_accessors.swift index f45e71fadd6d8..a723fb7f979bc 100644 --- a/test/Parse/borrow_and_mutate_accessors.swift +++ b/test/Parse/borrow_and_mutate_accessors.swift @@ -15,7 +15,7 @@ struct Wrapper { } } var k2: Klass { - borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a getter}} + borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a getter}} return _k } get { // expected-note{{getter defined here}} @@ -23,7 +23,7 @@ struct Wrapper { } } var k3: Klass { - borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a '_read' accessor}} + borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a '_read' accessor}} return _k } _read { // expected-note{{'_read' accessor defined here}} @@ -31,7 +31,7 @@ struct Wrapper { } } var k4: Klass { - borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a 'read' accessor}} + borrow { // expected-error{{variable cannot provide both a 'borrow' accessor and a 'read' accessor}} return _k } read { // expected-note{{'read' accessor defined here}} diff --git a/test/SILGen/borrow_accessor_synthesis.swift b/test/SILGen/borrow_accessor_synthesis.swift new file mode 100644 index 0000000000000..77873de6ea7f3 --- /dev/null +++ b/test/SILGen/borrow_accessor_synthesis.swift @@ -0,0 +1,478 @@ +// RUN:%target-swift-frontend -emit-silgen %s -enable-experimental-feature BorrowAndMutateAccessors -enable-experimental-feature SuppressedAssociatedTypes -enable-library-evolution | %FileCheck %s + +// REQUIRES: swift_feature_BorrowAndMutateAccessors +// REQUIRES: swift_feature_SuppressedAssociatedTypes + +public protocol P { + associatedtype Element + var prop1: Element { get set } + var prop2: Element { get set } + var prop3: Element { get set } +} + +public class Klass {} + +public struct W: P { + var _prop: Element + public var prop1: Element { + borrow { + return _prop + } + mutate { + return &_prop + } + } + + public var prop2: Element { + _read { + yield _prop + } + _modify { + yield &_prop + } + } + + public var prop3: Element { + get { + return _prop + } + set { + _prop = newValue + } + } +} + +public protocol NCP: ~Copyable { + associatedtype Element: ~Copyable + var prop1: Element { get set } + var prop2: Element { get set } + var prop3: Element { get set } +} + +public struct NC: NCP & ~Copyable { + var _prop: Element + + public var prop1: Element { + borrow { + return _prop + } + mutate { + return &_prop + } + } + + public var prop2: Element { + _read { + yield _prop + } + _modify { + yield &_prop + } + } + + public var prop3: Element +} + +func use(_ t: borrowing T) {} + +func mutate(_ t: inout T) {} + +// CHECK-LABEL: sil hidden [ossa] @$s25borrow_accessor_synthesis6testP1yyxAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () { +// CHECK: bb0([[REG0:%.*]] : $*τ_0_0): +// CHECK: [[REG2:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG3:%.*]] = witness_method $τ_0_0, #P.prop1!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG4:%.*]] = apply [[REG3]]<τ_0_0>([[REG2]], [[REG0]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG5:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG6:%.*]] = apply [[REG5]]<(τ_0_0).Element>([[REG2]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG2]] +// CHECK: dealloc_stack [[REG2]] +// CHECK: [[REG9:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG10:%.*]] = witness_method $τ_0_0, #P.prop2!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG11:%.*]] = apply [[REG10]]<τ_0_0>([[REG9]], [[REG0]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG12:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG13:%.*]] = apply [[REG12]]<(τ_0_0).Element>([[REG9]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG9]] +// CHECK: dealloc_stack [[REG9]] +// CHECK: [[REG16:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG17:%.*]] = witness_method $τ_0_0, #P.prop3!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG18:%.*]] = apply [[REG17]]<τ_0_0>([[REG16]], [[REG0]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG19:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG20:%.*]] = apply [[REG19]]<(τ_0_0).Element>([[REG16]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG16]] +// CHECK: dealloc_stack [[REG16]] +// CHECK-LABEL: } // end sil function '$s25borrow_accessor_synthesis6testP1yyxAA1PRzlF' +func testP1(_ p: some P) { + // For Copyable types, all opaque read accesses go through getter + // Conforming types can synthesize the getter from stored property, get, _read or borrow + use(p.prop1) + use(p.prop2) + use(p.prop3) +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis6testP2yyxzAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> () { +// CHECK: bb0([[REG0:%.*]] : $*τ_0_0): +// CHECK: [[REG2:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG3:%.*]] = witness_method $τ_0_0, #P.prop1!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG4]], [[REG5]]) = begin_apply [[REG3]]<τ_0_0>([[REG2]]) : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG6:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG7:%.*]] = apply [[REG6]]<(τ_0_0).Element>([[REG4]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG8:%.*]] = end_apply [[REG5]] as $() +// CHECK: end_access [[REG2]] +// CHECK: [[REG10:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG11:%.*]] = witness_method $τ_0_0, #P.prop2!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG12:%.*]], [[REG13:%.*]]) = begin_apply [[REG11]]<τ_0_0>([[REG10]]) : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG14:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG15:%.*]] = apply [[REG14]]<(τ_0_0).Element>([[REG12]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG16:%.*]] = end_apply [[REG13]] as $() +// CHECK: end_access [[REG10]] +// CHECK: [[REG18:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG19:%.*]] = witness_method $τ_0_0, #P.prop3!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG20:%.*]], [[REG21:%.*]]) = begin_apply [[REG19]]<τ_0_0>([[REG18]]) : $@yield_once @convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG22:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG23:%.*]] = apply [[REG22]]<(τ_0_0).Element>([[REG20]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG24:%.*]] = end_apply [[REG21]] as $() +// CHECK: end_access [[REG18]] +// CHECK: [[REG26:%.*]] = tuple () +// CHECK: return [[REG26]] +// CHECK: } +func testP2(_ p: inout some P) { + // For Copyable types, all opaque modify accesses go through modify + // Conforming types can synthesize the modify from stored property, _modify or mutate + mutate(&p.prop1) + mutate(&p.prop2) + mutate(&p.prop3) +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis6testP3yyxzAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@inout τ_0_0) -> () { +// CHECK: bb0([[REG0:%.*]] : $*τ_0_0): +// CHECK: [[REG2:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG3:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG4:%.*]] = witness_method $τ_0_0, #P.prop1!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG5:%.*]] = apply [[REG4]]<τ_0_0>([[REG3]], [[REG2]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: end_access [[REG2]] +// CHECK: [[REG7:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG8:%.*]] = witness_method $τ_0_0, #P.prop1!setter : (inout Self) -> (Self.Element) -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: [[REG9:%.*]] = apply [[REG8]]<τ_0_0>([[REG3]], [[REG7]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: end_access [[REG7]] +// CHECK: dealloc_stack [[REG3]] +// CHECK: [[REG12:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG13:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG14:%.*]] = witness_method $τ_0_0, #P.prop2!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG15:%.*]] = apply [[REG14]]<τ_0_0>([[REG13]], [[REG12]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: end_access [[REG12]] +// CHECK: [[REG17:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG18:%.*]] = witness_method $τ_0_0, #P.prop2!setter : (inout Self) -> (Self.Element) -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: [[REG19:%.*]] = apply [[REG18]]<τ_0_0>([[REG13]], [[REG17]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: end_access [[REG17]] +// CHECK: dealloc_stack [[REG13]] +// CHECK: [[REG22:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG23:%.*]] = alloc_stack $(τ_0_0).Element +// CHECK: [[REG24:%.*]] = witness_method $τ_0_0, #P.prop3!getter : (Self) -> () -> Self.Element : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: [[REG25:%.*]] = apply [[REG24]]<τ_0_0>([[REG23]], [[REG22]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.Element +// CHECK: end_access [[REG22]] +// CHECK: [[REG27:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG28:%.*]] = witness_method $τ_0_0, #P.prop3!setter : (inout Self) -> (Self.Element) -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: [[REG29:%.*]] = apply [[REG28]]<τ_0_0>([[REG23]], [[REG27]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in τ_0_0.Element, @inout τ_0_0) -> () +// CHECK: end_access [[REG27]] +// CHECK: dealloc_stack [[REG23]] +// CHECK: [[REG32:%.*]] = tuple () +// CHECK: return [[REG32]] +// CHECK: } +func testP3(_ p: inout some P) { + // For Copyable types, all opaque set accesses go through set + // Conforming types can synthesize the set from stored property, setter, _modify or mutate + p.prop1 = p.prop1 + p.prop2 = p.prop2 + p.prop3 = p.prop3 +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis8testNCP1yyxAA3NCPRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : NCP> (@in_guaranteed τ_0_0) -> () { +// CHECK: bb0([[REG0:%.*]] : $*τ_0_0): +// CHECK: [[REG2:%.*]] = witness_method $τ_0_0, #NCP.prop1!read : (Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: ([[REG3:%.*]], [[REG4:%.*]]) = begin_apply [[REG2]]<τ_0_0>([[REG0]]) : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: [[REG5:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG3]] +// CHECK: [[REG6:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG7:%.*]] = apply [[REG6]]<(τ_0_0).Element>([[REG5]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG8:%.*]] = end_apply [[REG4]] as $() +// CHECK: [[REG9:%.*]] = witness_method $τ_0_0, #NCP.prop2!read : (Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: ([[REG10:%.*]], [[REG11:%.*]]) = begin_apply [[REG9]]<τ_0_0>([[REG0]]) : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: [[REG12:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG10]] +// CHECK: [[REG13:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG14:%.*]] = apply [[REG13]]<(τ_0_0).Element>([[REG12]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG15:%.*]] = end_apply [[REG11]] as $() +// CHECK: [[REG16:%.*]] = witness_method $τ_0_0, #NCP.prop3!read : (Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: [[REG19:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG17]] +// CHECK: [[REG20:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG21:%.*]] = apply [[REG20]]<(τ_0_0).Element>([[REG19]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG22:%.*]] = end_apply [[REG18]] as $() +// CHECK: } +func testNCP1(_ p: some NCP) { + use(p.prop1) + use(p.prop2) + use(p.prop3) +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis8testNCP2yyxzAA3NCPRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : NCP> (@inout τ_0_0) -> () { +// CHECK: bb0([[REG0:%.*]] : $*τ_0_0): +// CHECK: [[REG2:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG3:%.*]] = witness_method $τ_0_0, #NCP.prop1!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG4:%.*]], [[REG5:%.*]]) = begin_apply [[REG3]]<τ_0_0>([[REG2]]) : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG6:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG4]] +// CHECK: [[REG7:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG8:%.*]] = apply [[REG7]]<(τ_0_0).Element>([[REG6]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG9:%.*]] = end_apply [[REG5]] as $() +// CHECK: end_access [[REG2]] +// CHECK: [[REG11:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG12:%.*]] = witness_method $τ_0_0, #NCP.prop2!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG13:%.*]], [[REG14:%.*]]) = begin_apply [[REG12]]<τ_0_0>([[REG11]]) : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG15:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG13]] +// CHECK: [[REG16:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG17:%.*]] = apply [[REG16]]<(τ_0_0).Element>([[REG15]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG18:%.*]] = end_apply [[REG14]] as $() +// CHECK: end_access [[REG11]] +// CHECK: [[REG20:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG21:%.*]] = witness_method $τ_0_0, #NCP.prop3!modify : (inout Self) -> () -> () : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: ([[REG22:%.*]], [[REG23:%.*]]) = begin_apply [[REG21]]<τ_0_0>([[REG20]]) : $@yield_once @convention(witness_method: NCP) <τ_0_0 where τ_0_0 : NCP, τ_0_0 : ~Copyable> (@inout τ_0_0) -> @yields @inout τ_0_0.Element +// CHECK: [[REG24:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG22]] +// CHECK: [[REG25:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG26:%.*]] = apply [[REG25]]<(τ_0_0).Element>([[REG24]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG27:%.*]] = end_apply [[REG23]] as $() +// CHECK: end_access [[REG20]] +// CHECK: [[REG29:%.*]] = tuple () +// CHECK: return [[REG29]] +// CHECK: } +func testNCP2(_ p: inout some NCP) { + mutate(&p.prop1) + mutate(&p.prop2) + mutate(&p.prop3) +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis6testW1yyAA1WVyxGlF : $@convention(thin) (@in_guaranteed W) -> () { +// CHECK: bb0([[REG0:%.*]] : $*W): +// CHECK: [[REG2:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop1xvb : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG4:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG3]] to [init] [[REG4]] +// CHECK: [[REG6:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG4]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG4]] +// CHECK: dealloc_stack [[REG4]] +// CHECK: [[REG10:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop2xvr : $@yield_once @convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: ([[REG11:%.*]], [[REG12:%.*]]) = begin_apply [[REG10]]([[REG0]]) : $@yield_once @convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: [[REG13:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG11]] to [init] [[REG13]] +// CHECK: [[REG15:%.*]] = end_apply [[REG12]] as $() +// CHECK: [[REG16:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG17:%.*]] = apply [[REG16]]([[REG13]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG13]] +// CHECK: dealloc_stack [[REG13]] +// CHECK: [[REG20:%.*]] = alloc_stack $T +// CHECK: [[REG21:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop3xvg : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: [[REG22:%.*]] = apply [[REG21]]([[REG20]], [[REG0]]) : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: [[REG23:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG24:%.*]] = apply [[REG23]]([[REG20]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG20]] +// CHECK: dealloc_stack [[REG20]] +// CHECK: [[REG27:%.*]] = tuple () +// CHECK: return [[REG27]] +// CHECK: } +func testW1(_ p: W) { + use(p.prop1) // resolves to borrow + use(p.prop2) // resolves to _read + use(p.prop3) // resolves to getter +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis6testW2yyAA1WVyxGzlF : $@convention(thin) (@inout W) -> () { +// CHECK: bb0([[REG0:%.*]] : $*W): +// CHECK: [[REG2:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop1xvz : $@convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @inout τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @inout τ_0_0 +// CHECK: [[REG5:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG6:%.*]] = apply [[REG5]]([[REG4]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: end_access [[REG2]] +// CHECK: [[REG8:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG9:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop2xvM : $@yield_once @convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: ([[REG10:%.*]], [[REG11:%.*]]) = begin_apply [[REG9]]([[REG8]]) : $@yield_once @convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: [[REG12:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG13:%.*]] = apply [[REG12]]([[REG10]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG14:%.*]] = end_apply [[REG11]] as $() +// CHECK: end_access [[REG8]] +// CHECK: [[REG16:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG17:%.*]] = alloc_stack $T +// CHECK: [[REG18:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop3xvg : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: [[REG19:%.*]] = apply [[REG18]]([[REG17]], [[REG16]]) : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: [[REG20:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG21:%.*]] = apply [[REG20]]([[REG17]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG22:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop3xvs : $@convention(method) <τ_0_0> (@in τ_0_0, @inout W<τ_0_0>) -> () +// CHECK: [[REG23:%.*]] = apply [[REG22]]([[REG17]], [[REG16]]) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout W<τ_0_0>) -> () +// CHECK: end_access [[REG16]] +// CHECK: dealloc_stack [[REG17]] +// CHECK: } +func testW2(_ p: inout W) { + mutate(&p.prop1) // resolves to mutate + mutate(&p.prop2) // resolves to _modify + mutate(&p.prop3) // resolves to get, set, _modify +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis6testW3yyAA1WVyxGzlF : $@convention(thin) (@inout W) -> () { +// CHECK: bb0([[REG0:%.*]] : $*W): +// CHECK: [[REG2:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop1xvb : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG5:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG4]] to [init] [[REG5]] +// CHECK: end_access [[REG2]] +// CHECK: [[REG8:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG9:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop1xvz : $@convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @inout τ_0_0 +// CHECK: [[REG10:%.*]] = apply [[REG9]]([[REG8]]) : $@convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @inout τ_0_0 +// CHECK: copy_addr [take] [[REG5]] to [[REG10]] +// CHECK: end_access [[REG8]] +// CHECK: dealloc_stack [[REG5]] +// CHECK: [[REG14:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG15:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop2xvr : $@yield_once @convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: ([[REG16:%.*]], [[REG17:%.*]]) = begin_apply [[REG15]]([[REG14]]) : $@yield_once @convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: [[REG18:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG16]] to [init] [[REG18]] +// CHECK: [[REG20:%.*]] = end_apply [[REG17]] as $() +// CHECK: end_access [[REG14]] +// CHECK: [[REG22:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG23:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop2xvM : $@yield_once @convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: ([[REG24:%.*]], [[REG25:%.*]]) = begin_apply [[REG23]]([[REG22]]) : $@yield_once @convention(method) <τ_0_0> (@inout W<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: copy_addr [take] [[REG18]] to [[REG24]] +// CHECK: [[REG27:%.*]] = end_apply [[REG25]] as $() +// CHECK: end_access [[REG22]] +// CHECK: dealloc_stack [[REG18]] +// CHECK: [[REG30:%.*]] = begin_access [read] [unknown] [[REG0]] +// CHECK: [[REG31:%.*]] = alloc_stack $T +// CHECK: [[REG32:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop3xvg : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: [[REG33:%.*]] = apply [[REG32]]([[REG31]], [[REG30]]) : $@convention(method) <τ_0_0> (@in_guaranteed W<τ_0_0>) -> @out τ_0_0 +// CHECK: end_access [[REG30]] +// CHECK: [[REG35:%.*]] = begin_access [modify] [unknown] [[REG0]] +// CHECK: [[REG36:%.*]] = function_ref @$s25borrow_accessor_synthesis1WV5prop3xvs : $@convention(method) <τ_0_0> (@in τ_0_0, @inout W<τ_0_0>) -> () +// CHECK: [[REG37:%.*]] = apply [[REG36]]([[REG31]], [[REG35]]) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout W<τ_0_0>) -> () +// CHECK: end_access [[REG35]] +// CHECK: dealloc_stack [[REG31]] +// CHECK: } +func testW3(_ p: inout W) { + p.prop1 = p.prop1 + p.prop2 = p.prop2 + p.prop3 = p.prop3 +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis7testNC1yyAA2NCVyxGlF : $@convention(thin) (@in_guaranteed NC) -> () { +// CHECK: bb0([[REG0:%.*]] : $*NC): +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s25borrow_accessor_synthesis2NCVAARi_zrlE5prop1xvb : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed NC<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed NC<τ_0_0>) -> @guaranteed_address τ_0_0 +// CHECK: [[REG5:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG4]] to [init] [[REG5]] +// CHECK: [[REG7:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG8:%.*]] = apply [[REG7]]([[REG5]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG5]] +// CHECK: dealloc_stack [[REG5]] +// CHECK: [[REG11:%.*]] = function_ref @$s25borrow_accessor_synthesis2NCVAARi_zrlE5prop2xvr : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed NC<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: ([[REG12:%.*]], [[REG13:%.*]]) = begin_apply [[REG11]]([[REG2]]) : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed NC<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: [[REG14:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG12]] to [init] [[REG14]] +// CHECK: [[REG16:%.*]] = end_apply [[REG13]] as $() +// CHECK: [[REG17:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG18:%.*]] = apply [[REG17]]([[REG14]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG14]] +// CHECK: dealloc_stack [[REG14]] +// CHECK: [[REG21:%.*]] = struct_element_addr [[REG2]], #NC.prop3 +// CHECK: [[REG22:%.*]] = alloc_stack $T +// CHECK: copy_addr [[REG21]] to [init] [[REG22]] +// CHECK: [[REG24:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG25:%.*]] = apply [[REG24]]([[REG22]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: destroy_addr [[REG22]] +// CHECK: dealloc_stack [[REG22]] +// CHECK: [[REG28:%.*]] = tuple () +// CHECK: return [[REG28]] +// CHECK: } +func testNC1(_ p: borrowing NC) { + use(p.prop1) // resolves to borrow + use(p.prop2) // resolves to _read + use(p.prop3) // resolves to stored property +} + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis7testNC2yyAA2NCVyxGzlF : $@convention(thin) (@inout NC) -> () { +// CHECK: bb0([[REG0:%.*]] : $*NC): +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = begin_access [modify] [unknown] [[REG2]] +// CHECK: [[REG4:%.*]] = function_ref @$s25borrow_accessor_synthesis2NCVAARi_zrlE5prop1xvz : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout NC<τ_0_0>) -> @inout τ_0_0 +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout NC<τ_0_0>) -> @inout τ_0_0 +// CHECK: [[REG6:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: end_access [[REG3]] +// CHECK: [[REG9:%.*]] = begin_access [modify] [unknown] [[REG2]] +// CHECK: [[REG10:%.*]] = function_ref @$s25borrow_accessor_synthesis2NCVAARi_zrlE5prop2xvM : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout NC<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: ([[REG11:%.*]], [[REG12:%.*]]) = begin_apply [[REG10]]([[REG9]]) : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout NC<τ_0_0>) -> @yields @inout τ_0_0 +// CHECK: [[REG13:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG14:%.*]] = apply [[REG13]]([[REG11]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG15:%.*]] = end_apply [[REG12]] as $() +// CHECK: end_access [[REG9]] +// CHECK: [[REG17:%.*]] = begin_access [modify] [unknown] [[REG2]] +// CHECK: [[REG18:%.*]] = struct_element_addr [[REG17]], #NC.prop3 +// CHECK: [[REG19:%.*]] = function_ref @$s25borrow_accessor_synthesis6mutateyyxzRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: [[REG20:%.*]] = apply [[REG19]]([[REG18]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@inout τ_0_0) -> () +// CHECK: end_access [[REG17]] +// CHECK: } +func testNC2(_ p: inout NC) { + mutate(&p.prop1) // resolves to mutate + mutate(&p.prop2) // resolves to _modify + mutate(&p.prop3) // resolves to stored property +} + +public protocol Container: ~Copyable { + associatedtype Element: ~Copyable + subscript(index: Int) -> Element { get set } +} + +public struct RigidWrapper: Container & ~Copyable { + var _element: T + + public subscript(index: Int) -> T { + borrow { + return _element + } + mutate { + return &_element + } + } +} + +// CHECK: sil [ossa] @$s25borrow_accessor_synthesis12RigidWrapperVAARi_zrlEyxSicib : $@convention(method) (Int, @in_guaranteed RigidWrapper) -> @guaranteed_address T { +// CHECK: bb0(%0 : $Int, %1 : $*RigidWrapper): +// CHECK: %4 = mark_unresolved_non_copyable_value [no_consume_or_assign] %1 +// CHECK: %5 = struct_element_addr %4, #RigidWrapper._element +// CHECK: return %5 +// CHECK: } + +// CHECK: sil private [transparent] [thunk] [ossa] @$s25borrow_accessor_synthesis12RigidWrapperVyxGAA9ContainerAARi_zrlAaEPy7ElementQzSicirTW : $@yield_once @convention(witness_method: Container) <τ_0_0 where τ_0_0 : ~Copyable> @substituted <τ_0_0, τ_0_1> (Int, @in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_1 for , τ_0_0> { +// CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*RigidWrapper<τ_0_0>): +// CHECK: [[REG2:%.*]] = function_ref @$s25borrow_accessor_synthesis12RigidWrapperVAARi_zrlEyxSicir : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @in_guaranteed RigidWrapper<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: ([[REG3:%.*]], [[REG4:%.*]]) = begin_apply [[REG2]]<τ_0_0>([[REG0]], [[REG1]]) : $@yield_once @convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @in_guaranteed RigidWrapper<τ_0_0>) -> @yields @in_guaranteed τ_0_0 +// CHECK: yield [[REG3]], resume bb1, unwind bb2 +// CHECK: bb1: +// CHECK: [[REG6:%.*]] = end_apply [[REG4]] as $() +// CHECK: [[REG7:%.*]] = tuple () +// CHECK: return [[REG7]] +// CHECK: bb2: +// CHECK: abort_apply [[REG4]] +// CHECK: unwind +// CHECK: } + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_synthesis13testContaineryyx_SitAA0E0RzlF : $@convention(thin) (@in_guaranteed T, Int) -> () { +// CHECK: bb0([[REG0:%.*]] : $*T, [[REG1:%.*]] : $Int): +// CHECK: [[REG4:%.*]] = witness_method $T, #Container.subscript!read : (Self) -> (Int) -> () : $@yield_once @convention(witness_method: Container) <τ_0_0 where τ_0_0 : Container, τ_0_0 : ~Copyable> (Int, @in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: ([[REG5:%.*]], [[REG6:%.*]]) = begin_apply [[REG4]]([[REG1]], [[REG0]]) : $@yield_once @convention(witness_method: Container) <τ_0_0 where τ_0_0 : Container, τ_0_0 : ~Copyable> (Int, @in_guaranteed τ_0_0) -> @yields @in_guaranteed τ_0_0.Element +// CHECK: [[REG7:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG5]] +// CHECK: [[REG8:%.*]] = function_ref @$s25borrow_accessor_synthesis3useyyxRi_zlF : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG9:%.*]] = apply [[REG8]]([[REG7]]) : $@convention(thin) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed τ_0_0) -> () +// CHECK: [[REG10:%.*]] = end_apply [[REG6]] as $() +// CHECK: [[REG11:%.*]] = tuple () +// CHECK: return [[REG11]] +// CHECK: } +func testContainer(_ c: T, _ index: Int) { + use(c[index]) // resolved to subscript.read which maybe synthesized using borrow accessor for conformance +} diff --git a/test/Sema/borrow_and_mutate_accessors.swift b/test/Sema/borrow_and_mutate_accessors.swift index 2e22978fc22ce..9cf9bb40f88a3 100644 --- a/test/Sema/borrow_and_mutate_accessors.swift +++ b/test/Sema/borrow_and_mutate_accessors.swift @@ -9,6 +9,34 @@ class Klass { struct Struct { var _i: Int = 0 + var _k: Klass + + var k1: Klass { + consuming borrow { // expected-error{{a 'borrow' accessor cannot be declared consuming}} + return _k + } + consuming mutate { // expected-error{{a 'mutate' accessor cannot be declared consuming}} + return &_k + } + } + + var k2: Klass { + mutating borrow { // expected-error{{mutating ownership modifier is not yet supported on a 'borrow' accessor}} + return _k + } + nonmutating mutate { // expected-error{{nonmutating ownership modifier is not yet supported on a 'mutate' accessor}} + return &_k // expected-error{{'&' may only be used to pass an argument to inout parameter}} + } + } + + var k3: Klass { + nonmutating borrow { + return _k + } + mutating mutate { + return &_k + } + } } extension Klass {