diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index f76e0fd36085e..28f30af1d870b 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -537,7 +537,8 @@ class ASTExtInfoBuilder { DifferentiabilityMaskOffset = 11, DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset, SendingResultMask = 1 << 14, - NumMaskBits = 15 + InOutResultMask = 1 << 15, + NumMaskBits = 16 }; static_assert(FunctionTypeIsolation::Mask == 0x7, "update mask manually"); @@ -660,6 +661,8 @@ class ASTExtInfoBuilder { globalActor); } + constexpr bool hasInOutResult() const { return bits & InOutResultMask; } + constexpr bool hasSelfParam() const { switch (getSILRepresentation()) { case SILFunctionTypeRepresentation::Thick: @@ -782,6 +785,11 @@ class ASTExtInfoBuilder { lifetimeDependencies); } + [[nodiscard]] ASTExtInfoBuilder withHasInOutResult() const { + return ASTExtInfoBuilder((bits | InOutResultMask), clangTypeInfo, + globalActor, thrownError, lifetimeDependencies); + } + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(bits); ID.AddPointer(clangTypeInfo.getType()); @@ -877,6 +885,8 @@ class ASTExtInfo { FunctionTypeIsolation getIsolation() const { return builder.getIsolation(); } + constexpr bool hasInOutResult() const { return builder.hasInOutResult(); } + /// Helper method for changing the representation. /// /// Prefer using \c ASTExtInfoBuilder::withRepresentation for chaining. diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index b67c7f908819e..169af248f413f 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -407,7 +407,7 @@ class alignas(1 << TypeAlignInBits) TypeBase } protected: - enum { NumAFTExtInfoBits = 15 }; + enum { NumAFTExtInfoBits = 16 }; enum { NumSILExtInfoBits = 14 }; // clang-format off @@ -444,8 +444,7 @@ class alignas(1 << TypeAlignInBits) TypeBase HasExtInfo : 1, HasClangTypeInfo : 1, HasThrownError : 1, - HasLifetimeDependencies : 1, - NumParams : 15 + HasLifetimeDependencies : 1 ); SWIFT_INLINE_BITFIELD_FULL(ArchetypeType, TypeBase, 1+1+16, @@ -3350,7 +3349,8 @@ END_CAN_TYPE_WRAPPER(DynamicSelfType, Type) /// represented at the binary level as a single function pointer. class AnyFunctionType : public TypeBase { const Type Output; - + uint16_t NumParams; + public: using Representation = FunctionTypeRepresentation; @@ -3611,8 +3611,8 @@ class AnyFunctionType : public TypeBase { Bits.AnyFunctionType.HasThrownError = false; Bits.AnyFunctionType.HasLifetimeDependencies = false; } - Bits.AnyFunctionType.NumParams = NumParams; - assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!"); + this->NumParams = NumParams; + assert(this->NumParams == NumParams && "Params dropped!"); if (Info && CONDITIONAL_ASSERT_enabled()) { unsigned maxLifetimeTarget = NumParams + 1; @@ -3650,7 +3650,7 @@ class AnyFunctionType : public TypeBase { Type getResult() const { return Output; } ArrayRef getParams() const; - unsigned getNumParams() const { return Bits.AnyFunctionType.NumParams; } + unsigned getNumParams() const { return NumParams; } GenericSignature getOptGenericSignature() const; diff --git a/include/swift/Sema/SyntacticElementTarget.h b/include/swift/Sema/SyntacticElementTarget.h index 674a429ccf7b8..7347b3cb179c7 100644 --- a/include/swift/Sema/SyntacticElementTarget.h +++ b/include/swift/Sema/SyntacticElementTarget.h @@ -262,8 +262,9 @@ class SyntacticElementTarget { unsigned patternBindingIndex, bool bindPatternVarsOneWay); /// Form an expression target for a ReturnStmt. - static SyntacticElementTarget - forReturn(ReturnStmt *returnStmt, Type contextTy, DeclContext *dc); + static SyntacticElementTarget forReturn(ReturnStmt *returnStmt, + Expr *returnExpr, Type contextTy, + DeclContext *dc); /// Form a target for the preamble of a for-in loop, excluding its where /// clause and body. diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 039f5db5bd67b..dca0ef13b3bd1 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -1097,9 +1097,15 @@ class Verifier : public ASTWalker { void verifyChecked(ReturnStmt *S) { auto func = Functions.back(); Type resultType; + bool hasInOutResult = false; + if (auto *FD = dyn_cast(func)) { resultType = FD->getResultInterfaceType(); resultType = FD->mapTypeIntoContext(resultType); + hasInOutResult = FD->getInterfaceType() + ->castTo() + ->getExtInfo() + .hasInOutResult(); } else if (auto closure = dyn_cast(func)) { resultType = closure->getResultType(); } else if (isa(func)) { @@ -1112,6 +1118,9 @@ class Verifier : public ASTWalker { auto result = S->getResult(); auto returnType = result->getType(); // Make sure that the return has the same type as the function. + if (hasInOutResult) { + resultType = InOutType::get(resultType); + } checkSameType(resultType, returnType, "return type"); } else { // Make sure that the function has a Void result type. diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index cfe23e0be7318..b6823c5a5f944 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -86,6 +86,7 @@ extension Parser.ExperimentalFeatures { mapFeature(.OldOwnershipOperatorSpellings, to: .oldOwnershipOperatorSpellings) mapFeature(.KeyPathWithMethodMembers, to: .keypathWithMethodMembers) mapFeature(.DefaultIsolationPerFile, to: .defaultIsolationPerFile) + mapFeature(.BorrowAndMutateAccessors, to: .borrowAndMutateAccessors) } } diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index ef314cc6a3531..d7981cc106d0e 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -1377,6 +1377,22 @@ class Conventions { } }; +static bool isBorrowAccessor(std::optional constant) { + if (!constant || !constant->hasDecl()) + return false; + + auto accessor = dyn_cast(constant->getDecl()); + return accessor && accessor->isBorrowAccessor(); +} + +static bool isMutateAccessor(std::optional constant) { + if (!constant || !constant->hasDecl()) + return false; + + auto accessor = dyn_cast(constant->getDecl()); + return accessor && accessor->isMutateAccessor(); +} + /// A visitor for breaking down formal result types into a SILResultInfo /// and possibly some number of indirect-out SILParameterInfos, /// matching the abstraction patterns of the original type. @@ -1386,22 +1402,21 @@ class DestructureResults { SmallVectorImpl &Results; TypeExpansionContext context; bool hasSendingResult; - bool isBorrowOrMutateAccessor; + std::optional constant; public: DestructureResults(TypeExpansionContext context, TypeConverter &TC, const Conventions &conventions, SmallVectorImpl &results, - bool hasSendingResult, bool isBorrowOrMutateAccessor) + bool hasSendingResult, std::optional constant) : TC(TC), Convs(conventions), Results(results), context(context), - hasSendingResult(hasSendingResult), - isBorrowOrMutateAccessor(isBorrowOrMutateAccessor) {} + hasSendingResult(hasSendingResult), constant(constant) {} void destructure(AbstractionPattern origType, CanType substType) { // Recur into tuples. // Do not explode tuples for borrow and mutate accessors since we cannot // explode and reconstruct addresses. - if (origType.isTuple() && !isBorrowOrMutateAccessor) { + if (origType.isTuple() && !isBorrowAccessor(constant)) { origType.forEachTupleElement(substType, [&](TupleElementGenerator &elt) { // If the original element type is not a pack expansion, just @@ -1411,7 +1426,7 @@ class DestructureResults { return; } - if (isBorrowOrMutateAccessor) { + if (isBorrowAccessor(constant)) { llvm_unreachable( "Returning packs from borrow/mutate accessor is not implemented"); } @@ -1448,17 +1463,17 @@ class DestructureResults { // Determine the result convention. ResultConvention convention; - if (isBorrowOrMutateAccessor) { + if (isBorrowAccessor(constant)) { if (substResultTL.isTrivial()) { convention = ResultConvention::Unowned; } else if (isFormallyReturnedIndirectly(origType, substType, substResultTLForConvention)) { - assert(Convs.getResult(substResultTLForConvention) == - ResultConvention::Guaranteed); convention = ResultConvention::GuaranteedAddress; } else { convention = ResultConvention::Guaranteed; } + } else if (isMutateAccessor(constant)) { + convention = ResultConvention::GuaranteedAddress; } else if (isFormallyReturnedIndirectly(origType, substType, substResultTLForConvention)) { convention = ResultConvention::Indirect; @@ -2368,17 +2383,6 @@ getAsCoroutineAccessor(std::optional constant) { return accessor; } -static bool isBorrowOrMutateAccessor(std::optional constant) { - if (!constant || !constant->hasDecl()) - return false; - - auto accessor = dyn_cast(constant->getDecl()); - if (!accessor) - return false; - - return accessor->isBorrowAccessor() || accessor->isMutateAccessor(); -} - static void destructureYieldsForReadAccessor(TypeConverter &TC, TypeExpansionContext expansion, AbstractionPattern origType, @@ -2728,8 +2732,7 @@ static CanSILFunctionType getSILFunctionType( SmallVector results; { DestructureResults destructurer(expansionContext, TC, conventions, results, - hasSendingResult, - isBorrowOrMutateAccessor(constant)); + hasSendingResult, constant); destructurer.destructure(origResultType, substFormalResultType); } @@ -3277,11 +3280,6 @@ static CanSILFunctionType getNativeSILFunctionType( TC, context, origType, substInterfaceType, extInfoBuilder, DefaultSetterConventions(), *constant); } - if (constant->isBorrowAccessor()) { - return getSILFunctionTypeForConventions( - DefaultConventions(NormalParameterConvention::Guaranteed, - ResultConvention::Guaranteed)); - } } return getSILFunctionTypeForConventions( DefaultConventions(NormalParameterConvention::Guaranteed)); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 9493f7ae886b8..aeee55e000354 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -5225,7 +5225,7 @@ class CallEmission { CleanupHandle applyCoroutine(SmallVectorImpl &yields); - ManagedValue applyBorrowAccessor(); + ManagedValue applyBorrowMutateAccessor(); RValue apply(SGFContext C = SGFContext()) { initialWritebackScope.verify(); @@ -5426,7 +5426,7 @@ CleanupHandle SILGenFunction::emitBeginApply( return endApplyHandle; } -ManagedValue CallEmission::applyBorrowAccessor() { +ManagedValue CallEmission::applyBorrowMutateAccessor() { auto origFormalType = callee.getOrigFormalType(); // Get the callee type information. auto calleeTypeInfo = callee.getTypeInfo(SGF); @@ -5453,14 +5453,14 @@ ManagedValue CallEmission::applyBorrowAccessor() { lookThroughMoveOnlyCheckerPattern(selfArgMV.getValue())); } - auto value = SGF.applyBorrowAccessor(uncurriedLoc.value(), fnValue, canUnwind, - callee.getSubstitutions(), uncurriedArgs, - calleeTypeInfo.substFnType, options); + auto value = SGF.applyBorrowMutateAccessor( + uncurriedLoc.value(), fnValue, canUnwind, callee.getSubstitutions(), + uncurriedArgs, calleeTypeInfo.substFnType, options); return value; } -ManagedValue SILGenFunction::applyBorrowAccessor( +ManagedValue SILGenFunction::applyBorrowMutateAccessor( SILLocation loc, ManagedValue fn, bool canUnwind, SubstitutionMap subs, ArrayRef args, CanSILFunctionType substFnType, ApplyOptions options) { @@ -7888,7 +7888,7 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor, return endApplyHandle; } -ManagedValue SILGenFunction::emitBorrowAccessor( +ManagedValue SILGenFunction::emitBorrowMutateAccessor( SILLocation loc, SILDeclRef accessor, SubstitutionMap substitutions, ArgumentSource &&selfValue, bool isSuper, bool isDirectUse, PreparedArguments &&subscriptIndices, bool isOnSelfParameter) { @@ -7913,7 +7913,7 @@ ManagedValue SILGenFunction::emitBorrowAccessor( emission.setCanUnwind(false); - return emission.applyBorrowAccessor(); + return emission.applyBorrowMutateAccessor(); } ManagedValue SILGenFunction::emitAsyncLetStart( diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 7f254b17d9864..504f50cbbbdae 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -2079,18 +2079,18 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SmallVectorImpl &yields, bool isOnSelfParameter); - ManagedValue emitBorrowAccessor(SILLocation loc, SILDeclRef accessor, - SubstitutionMap substitutions, - ArgumentSource &&selfValue, bool isSuper, - bool isDirectUse, - PreparedArguments &&subscriptIndices, - bool isOnSelfParameter); - - ManagedValue applyBorrowAccessor(SILLocation loc, ManagedValue fn, - bool canUnwind, SubstitutionMap subs, - ArrayRef args, - CanSILFunctionType substFnType, - ApplyOptions options); + ManagedValue emitBorrowMutateAccessor(SILLocation loc, SILDeclRef accessor, + SubstitutionMap substitutions, + ArgumentSource &&selfValue, + bool isSuper, bool isDirectUse, + PreparedArguments &&subscriptIndices, + bool isOnSelfParameter); + + ManagedValue applyBorrowMutateAccessor(SILLocation loc, ManagedValue fn, + bool canUnwind, SubstitutionMap subs, + ArrayRef args, + CanSILFunctionType substFnType, + ApplyOptions options); RValue emitApplyConversionFunction(SILLocation loc, Expr *funcExpr, diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 4d99d47ebac2c..9a24b81873af8 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1255,6 +1255,11 @@ namespace { if (!base.getType().isLoadable(SGF.F)) { return base; } + + if (base.getValue()->getType().isTrivial(SGF.F)) { + return SGF.B.createLoadTrivial(loc, base); + } + auto result = SGF.B.createLoadBorrow(loc, base.getValue()); // Mark the load_borrow as unchecked. We can't stop the source code from // trying to mutate or consume the same lvalue during this borrow, so @@ -2286,15 +2291,16 @@ namespace { namespace { /// A physical component which involves calling borrow accessors. -class BorrowAccessorComponent +class BorrowMutateAccessorComponent : public AccessorBasedComponent { public: - BorrowAccessorComponent(AbstractStorageDecl *decl, SILDeclRef accessor, - bool isSuper, bool isDirectAccessorUse, - SubstitutionMap substitutions, CanType baseFormalType, - LValueTypeData typeData, - ArgumentList *argListForDiagnostics, - PreparedArguments &&indices, bool isOnSelfParameter) + BorrowMutateAccessorComponent(AbstractStorageDecl *decl, SILDeclRef accessor, + bool isSuper, bool isDirectAccessorUse, + SubstitutionMap substitutions, + CanType baseFormalType, LValueTypeData typeData, + ArgumentList *argListForDiagnostics, + PreparedArguments &&indices, + bool isOnSelfParameter) : AccessorBasedComponent(BorrowMutateKind, decl, accessor, isSuper, isDirectAccessorUse, substitutions, baseFormalType, typeData, argListForDiagnostics, @@ -2311,14 +2317,14 @@ class BorrowAccessorComponent ManagedValue result; auto args = std::move(*this).prepareAccessorArgs(SGF, loc, base, Accessor); - auto value = SGF.emitBorrowAccessor( + auto value = SGF.emitBorrowMutateAccessor( loc, Accessor, Substitutions, std::move(args.base), IsSuper, IsDirectAccessorUse, std::move(args.Indices), IsOnSelfParameter); return value; } void dump(raw_ostream &OS, unsigned indent) const override { - printBase(OS, indent, "BorrowAccessorComponent"); + printBase(OS, indent, "BorrowMutateAccessorComponent"); } }; } // namespace @@ -3427,16 +3433,15 @@ namespace { AccessKind, FormalRValueType); return asImpl().emitUsingInitAccessor(accessor, isDirect, typeData); } - case AccessorKind::Borrow: { + case AccessorKind::Borrow: + case AccessorKind::Mutate: { auto typeData = getPhysicalStorageTypeData( SGF.getTypeExpansionContext(), SGF.SGM, AccessKind, Storage, Subs, FormalRValueType); - return asImpl().emitUsingBorrowAccessor(accessor, isDirect, typeData); + return asImpl().emitUsingBorrowMutateAccessor(accessor, isDirect, + typeData); } - case AccessorKind::Mutate: - llvm_unreachable("mutate accessor is not yet implemented"); } - llvm_unreachable("bad kind"); } }; @@ -3526,9 +3531,9 @@ void LValue::addNonMemberVarComponent( PreparedArguments(), /*isOnSelfParameter*/ false); } - void emitUsingBorrowAccessor(SILDeclRef accessor, bool isDirect, - LValueTypeData typeData) { - llvm_unreachable("borrow accessor is not implemented"); + void emitUsingBorrowMutateAccessor(SILDeclRef accessor, bool isDirect, + LValueTypeData typeData) { + llvm_unreachable("borrow/mutate accessor is not implemented"); } void emitUsingGetterSetter(SILDeclRef accessor, @@ -3584,7 +3589,8 @@ void LValue::addNonMemberVarComponent( std::optional enforcement; if (!Storage->isLet()) { - if (Options.IsNonAccessing) { + if (Options.IsNonAccessing || Options.ForGuaranteedReturn || + Options.ForGuaranteedAddressReturn) { enforcement = std::nullopt; } else if (Storage->getDeclContext()->isLocalContext()) { enforcement = SGF.getUnknownEnforcement(Storage); @@ -4211,10 +4217,10 @@ struct MemberStorageAccessEmitter : AccessEmitter { ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter); } - void emitUsingBorrowAccessor(SILDeclRef accessor, bool isDirect, - LValueTypeData typeData) { + void emitUsingBorrowMutateAccessor(SILDeclRef accessor, bool isDirect, + LValueTypeData typeData) { assert(!ActorIso); - LV.add( + LV.add( Storage, accessor, IsSuper, isDirect, Subs, BaseFormalType, typeData, ArgListForDiagnostics, std::move(Indices), IsOnSelfParameter); } @@ -5706,7 +5712,8 @@ std::optional SILGenFunction::tryEmitProjectedLValue(SILLocation loc, LValue &&src, TSanKind tsanKind) { assert(src.getAccessKind() == SGFAccessKind::BorrowedAddressRead || - src.getAccessKind() == SGFAccessKind::BorrowedObjectRead); + src.getAccessKind() == SGFAccessKind::BorrowedObjectRead || + src.getAccessKind() == SGFAccessKind::Write); for (auto component = src.begin(); component != src.end(); component++) { if (component->get()->getKind() != PathComponent::BorrowMutateKind && diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index 97db94e7072c6..3b2acae1a78a2 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -726,8 +726,8 @@ SILValue SILGenFunction::emitUncheckedGuaranteedConversion(SILValue value) { bool SILGenFunction::emitGuaranteedReturn( SILLocation loc, Expr *ret, SmallVectorImpl &directResults) { auto *afd = cast(FunctionDC->getAsDecl()); - assert(cast(afd)->isBorrowAccessor()); - + assert(cast(afd)->isBorrowAccessor() || + cast(afd)->isMutateAccessor()); auto emitLoadBorrowFromGuaranteedAddress = [&](ManagedValue guaranteedAddress) -> SILValue { @@ -762,13 +762,25 @@ bool SILGenFunction::emitGuaranteedReturn( // Emit return value at +0. FormalEvaluationScope scope(*this); LValueOptions options; + + if (cast(afd)->isMutateAccessor()) { + options = options.forGuaranteedAddressReturn(true); + } else { + assert(cast(afd)->isBorrowAccessor()); + if (F.getSelfArgument()->getType().isObject()) { + options = options.forGuaranteedReturn(true); + } else { + options = options.forGuaranteedAddressReturn(true); + } + } + auto lvalue = emitLValue(ret, F.getSelfArgument()->getType().isObject() ? SGFAccessKind::BorrowedObjectRead - : SGFAccessKind::BorrowedAddressRead, - F.getSelfArgument()->getType().isObject() - ? options.forGuaranteedReturn(true) - : options.forGuaranteedAddressReturn(true)); + : cast(afd)->isBorrowAccessor() + ? SGFAccessKind::BorrowedAddressRead + : SGFAccessKind::Write, + options); // If the accessor is annotated with @_unsafeSelfDependentResultAttr, // disable diagnosing the return expression. @@ -793,7 +805,7 @@ bool SILGenFunction::emitGuaranteedReturn( // } if (afd->getAttrs().hasAttribute()) { auto regularLoc = RegularLocation::getAutoGeneratedLocation(); - auto resultMV = emitBorrowedLValue(regularLoc, std::move(lvalue)); + auto resultMV = emitRawProjectedLValue(regularLoc, std::move(lvalue)); SILValue result = resultMV.getValue(); if (resultMV.getType().isAddress() && F.getConventions().hasGuaranteedResult()) { diff --git a/lib/Sema/SyntacticElementTarget.cpp b/lib/Sema/SyntacticElementTarget.cpp index 1984908b9f2d9..6aa7a9e33cdcd 100644 --- a/lib/Sema/SyntacticElementTarget.cpp +++ b/lib/Sema/SyntacticElementTarget.cpp @@ -170,13 +170,14 @@ SyntacticElementTarget SyntacticElementTarget::forInitialization( return result; } -SyntacticElementTarget -SyntacticElementTarget::forReturn(ReturnStmt *returnStmt, Type contextTy, - DeclContext *dc) { +SyntacticElementTarget SyntacticElementTarget::forReturn(ReturnStmt *returnStmt, + Expr *returnExpr, + Type contextTy, + DeclContext *dc) { assert(contextTy); assert(returnStmt->hasResult() && "Must have result to be type-checked"); ContextualTypeInfo contextInfo(contextTy, CTP_ReturnStmt); - SyntacticElementTarget target(returnStmt->getResult(), dc, contextInfo, + SyntacticElementTarget target(returnExpr, dc, contextInfo, /*isDiscarded*/ false); target.expression.parentReturnStmt = returnStmt; return target; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index b91c36536f66b..38b5e6f246f9f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2060,8 +2060,7 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { return TupleType::getEmpty(ctx); case AccessorKind::Mutate: - // TODO: Temporary result representation for mutate accessors. - return InOutType::get(storage->getValueInterfaceType()); + return storage->getValueInterfaceType(); // Addressor result types can get complicated because of the owner. case AccessorKind::Address: @@ -2591,7 +2590,10 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const { selfInfoBuilder = selfInfoBuilder.withLifetimeDependencies(*lifetimeDependenceInfo); } - + auto *accessor = dyn_cast(AFD); + if (accessor && accessor->isMutateAccessor()) { + selfInfoBuilder = selfInfoBuilder.withHasInOutResult(); + } // FIXME: Verify ExtInfo state is correct, not working by accident. auto selfInfo = selfInfoBuilder.build(); if (sig) { diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index b1fe8cf1e426c..f762d99a4768e 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1112,8 +1112,26 @@ class StmtChecker : public StmtVisitor { return RS; } + auto *accessor = TheFunc->getAccessorDecl(); + auto *exprToCheck = RS->getResult(); + InOutExpr *inout = nullptr; + + if (accessor && accessor->isMutateAccessor()) { + // Check that the returned expression is a &. + if ((inout = dyn_cast(exprToCheck))) { + ResultTy = InOutType::get(ResultTy); + } else { + getASTContext() + .Diags + .diagnose(exprToCheck->getLoc(), diag::missing_address_of_return) + .highlight(exprToCheck->getSourceRange()); + inout = new (getASTContext()) InOutExpr( + exprToCheck->getStartLoc(), exprToCheck, Type(), /*implicit*/ true); + } + } using namespace constraints; - auto target = SyntacticElementTarget::forReturn(RS, ResultTy, DC); + auto target = + SyntacticElementTarget::forReturn(RS, exprToCheck, ResultTy, DC); auto resultTarget = TypeChecker::typeCheckTarget(target); if (resultTarget) { RS->setResult(resultTarget->getAsExpr()); diff --git a/test/SIL/borrow_accessor_e2e.swift b/test/SIL/borrow_accessor_e2e.swift index 2a4e497d42489..13c29288ea8ca 100644 --- a/test/SIL/borrow_accessor_e2e.swift +++ b/test/SIL/borrow_accessor_e2e.swift @@ -7,7 +7,7 @@ // REQUIRES: executable_test public struct Container: ~Copyable { - var _storage: UnsafeBufferPointer + var _storage: UnsafeMutableBufferPointer var _count: Int var first: Element { @@ -15,6 +15,10 @@ public struct Container: ~Copyable { borrow { return _storage.baseAddress.unsafelyUnwrapped.pointee } + @_unsafeSelfDependentResult + mutate { + return &_storage.baseAddress.unsafelyUnwrapped.pointee + } } public subscript(index: Int) -> Element { @@ -23,6 +27,11 @@ public struct Container: ~Copyable { precondition(index >= 0 && index < _count, "Index out of bounds") return _storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee } + @_unsafeSelfDependentResult + mutate { + precondition(index >= 0 && index < _count, "Index out of bounds") + return &_storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee + } } } @@ -30,9 +39,10 @@ extension Container: Copyable where Element: Copyable {} func test() { let n = 10_000 - let arr = Array(0...n) - let sum = arr.withUnsafeBufferPointer { ubpointer in - let container = Container(_storage: ubpointer, _count: arr.count) + var arr = Array(0...n) + let count = arr.count + let sum = arr.withUnsafeMutableBufferPointer { ubpointer in + let container = Container(_storage: ubpointer, _count: count) var sum = 0 for i in 0.. Klass { - return Klass() -} +public struct NC : ~Copyable {} func use(_ t: Klass) {} -public struct NC : ~Copyable {} - func use(_ t: borrowing NC) {} -func consume(_ t: consuming T) {} - public struct S { var _k: Klass - var borrowKlass: Klass { + var k: Klass { borrow { return _k } - } - var getKlass: Klass { - get { - return _k - } - } - var readKlass: Klass { - _read { - yield _k + mutate { + return &_k } } } @@ -46,17 +31,8 @@ public struct Wrapper { borrow { return _s } - } - - var s_get: S { - get { - return _s - } - } - - var s_read: S { - _read { - yield _s + mutate { + return &_s } } @@ -64,101 +40,44 @@ public struct Wrapper { borrow { return _k } - } - - var k_complex: Klass { - borrow { - consume(self) - consume(_k) - return _k - } - } - - var nested_borrow: Klass { - borrow { - return _s.borrowKlass - } - } - - var nested_get1: Klass { - borrow { - return _s.getKlass // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - } - } - - var nested_get2: Klass { - borrow { - return s_get.borrowKlass // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &_k } } - var nested_get3: Int { + var nested_borrow1: Klass { borrow { - return _s.getKlass.id + return _s.k } - } - - var nested_get4: Int { - borrow { - return s_get.borrowKlass.id - } - } - - var nested_read1: Klass { - borrow { - return _s.readKlass // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - } - } - - var nested_read2: Klass { - borrow { - return s_read.readKlass // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &s._k } } - var owned_value_direct: Klass { - borrow { - return getKlass() // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - } - } - - var owned_value_projected: Klass { - borrow { - let w = Wrapper(_k: Klass(), _s: S(_k: Klass())) - return w.k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - } - } - - var nested: Klass { + var nested_borrow2: Klass { borrow { return k } + mutate { + return &_k + } } subscript(index: Int) -> Klass { borrow { return _k } + mutate { + return &_k + } } - + var nested_subscript: Klass { borrow { return self[0] } - } - - var if_klass: Klass { - borrow { - if Int.random(in: 1..<100) == 0 { - return _k - } - return _k // expected-error{{multiple return statements in borrow accessors are not yet supported}} - } - } - - var tuple_klass: (Klass, Klass) { - borrow { - return (_k, _k) // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &self[0] } } @@ -167,35 +86,17 @@ public struct Wrapper { return 0 } } - - var opt_klass: Klass? { - borrow { - if Int.random(in: 1..<100) == 0 { - return nil - } - return _k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - } - } } public struct SimpleWrapper { var _prop: T - var borrow_prop: T { + var prop: T { borrow { return _prop } - } - - var get_prop: T { - get { - return _prop - } - } - - var read_prop: T { - _read { - yield _prop + mutate { + return &_prop } } } @@ -203,61 +104,69 @@ public struct SimpleWrapper { public struct GenWrapper { var _prop: T var _w: SimpleWrapper - var _klass: Klass + var _k: Klass var _s: S public var prop: T { borrow { - return _prop + return _prop } - } - - var nested_prop: T { - borrow { - return _w.borrow_prop + mutate { + return &_prop } } - var get_prop: T { + var s: S { borrow { - return _w.get_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - + return _s } - } - - var read_prop: T { - borrow { - return _w.read_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &_s } } - - var s: S { + + var k: Klass { borrow { - return _s + return _k + } + mutate { + return &_k } } - var nested: T { + var nested_prop1: T { borrow { - return prop + return _w.prop + } + mutate { + return &_w.prop } } - var klass: Klass { + var nested_prop2: T { borrow { - return _klass + return prop + } + mutate { + return &prop } } - var nested_klass1: Klass { + var nested_k1: Klass { borrow { - return _s.borrowKlass + return _s.k + } + mutate { + return &_s.k } } - var nested_klass2: Klass { + var nested_k2: Klass { borrow { - return s.borrowKlass + return s.k + } + mutate { + return &s.k } } @@ -265,26 +174,17 @@ public struct GenWrapper { borrow { return _prop } + mutate { + return &_prop + } } - + var nested_subscript: T { borrow { return self[0] } - } - - var if_prop: T { - borrow { - if Int.random(in: 1..<100) == 0 { - return _prop - } - return _prop // expected-error{{multiple return statements in borrow accessors are not yet supported}} - } - } - - var tuple_prop: (T, T) { - borrow { - return (_prop, _prop) // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &self[0] } } @@ -293,181 +193,175 @@ public struct GenWrapper { return 0 } } - - var opt_T: T? { - borrow { - if Int.random(in: 1..<100) == 0 { - return nil - } - return _prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - - } - } } -public struct SimpleNCWrapper : ~Copyable { - var _prop: T +public struct NCS: ~Copyable { + var _nc: NC - var borrow_prop: T { + var nc: NC { borrow { - return _prop - } - } - - var get_prop: T { - get { - return _prop + return _nc } - } - - var read_prop: T { - _read { - yield _prop + mutate { + return &_nc } } } -public struct GenNCWrapper : ~Copyable { - var _prop: T - var _w: SimpleNCWrapper +public struct NCWrapper: ~Copyable { var _nc: NC - var _ncw: NCWrapper + var _s: NCS - public var prop: T { + var nc: NC { borrow { - return _prop + return _nc } - } - - var nested_prop: T { - borrow { - return _w.borrow_prop + mutate { + return &_nc } } - var nc: NC { + var nested1: NC { borrow { - return _nc + return _s.nc + } + mutate { + return &_s.nc } } - var ncw: NCWrapper { + var nested2: NC { borrow { - return _ncw + return nc + } + mutate { + return &nc } } - var nested_nc1: NC { + subscript(index: Int) -> NC { borrow { - return _ncw.nc + return _nc + } + mutate { + return &_nc } } - var nested_nc2: NC { + var nested_subscript: NC { borrow { - return ncw.nc + return self[0] + } + mutate { + return &self[0] } } - var nested_get: T { + var literal: Int { borrow { - return _w.get_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} - + return 0 } } - - var nested_read: T { - borrow { - return _w.read_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} +} - } - } - - var nested: T { +public struct SimpleNCWrapper : ~Copyable { + var _prop: T + + var prop: T { borrow { - return prop + return _prop + } + mutate { + return &_prop } } +} - subscript(index: Int) -> T { +public struct GenNCWrapper : ~Copyable { + var _prop: T + var _w: SimpleNCWrapper + var _nc: NC + var _ncw: NCWrapper + + public var prop: T { borrow { return _prop } - } - - var nested_subscript: T { - borrow { - return self[0] + mutate { + return &_prop } } - - var if_prop: T { + + var nc: NC { borrow { - if Int.random(in: 1..<100) == 0 { - return _prop - } - return _prop // expected-error{{multiple return statements in borrow accessors are not yet supported}} + return _nc + } + mutate { + return &_nc } } - var literal: Int { + var ncw: NCWrapper { borrow { - return 0 + return _ncw } - } - - var opt_T: T? { - borrow { - if Int.random(in: 1..<100) == 0 { - return nil - } - return _prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + mutate { + return &_ncw } } -} -public struct NCS: ~Copyable { - var _nc: NC - - var nc: NC { + var nested_prop1: T { borrow { - return _nc + return _w.prop + } + mutate { + return &_w.prop } } -} - -public struct NCWrapper: ~Copyable { - var _nc: NC - var _s: NCS - var nc: NC { + var nested_prop2: T { borrow { - return _nc + return prop + } + mutate { + return &prop } } - var nested1: NC { + var nested_nc1: NC { borrow { - return _s.nc + return _ncw.nc + } + mutate { + return &_ncw.nc } } - var nested2: NC { + var nested_nc2: NC { borrow { - return nc + return ncw.nc + } + mutate { + return &ncw.nc } } - subscript(index: Int) -> NC { + subscript(index: Int) -> T { borrow { - return _nc + return _prop + } + mutate { + return &_prop } } - var nested_subscript: NC { + var nested_subscript: T { borrow { return self[0] } + mutate { + return &self[0] + } } var literal: Int { @@ -477,148 +371,189 @@ public struct NCWrapper: ~Copyable { } } -func test() { - let w1 = Wrapper(_k: Klass(), _s: S(_k: Klass())) - use(w1.k) - var k1 = w1.k - use(k1) - k1 = Klass() - use(k1) - use(w1.nested_borrow) - use(w1.nested) - - let w2 = GenWrapper(_prop: Klass(), _w: SimpleWrapper(_prop: Klass()), _klass: Klass(), _s: S(_k: Klass())) - use(w2.prop) - var k2 = w2.prop - use(k2) - k2 = Klass() - use(k2) - use(w2.nested_prop) - use(w2.nested) -} +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV1sAA1SVvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed S { +// CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1 +// CHECK: [[REG2:%.*]] = struct_extract [[REG0]], #Wrapper._s +// CHECK: return [[REG2]] +// CHECK: } -func nctest() { - let w1 = GenNCWrapper(_prop: NC(), _w: SimpleNCWrapper(_prop: NC()), _nc: NC(), _ncw: NCWrapper(_nc: NC(), _s: NCS(_nc: NC()))) - use(w1.prop) - var k2 = w1.prop // MoveOnlyChecker diagnoses the copy - use(k2) - k2 = NC() - use(k2) -} +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV1sAA1SVvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr S { +// CHECK:bb0([[REG0:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #Wrapper._s +// CHECK: return [[REG2]] +// CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV1kAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG2:%.*]] = struct_extract [[REG0]], #Wrapper._k -// CHECK: return [[REG2]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1 +// CHECK: [[REG2:%.*]] = struct_extract [[REG0]], #Wrapper._k +// CHECK: return [[REG2]] +// CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV07nested_A0AA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { -// CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG2:%.*]] = struct_extract [[REG0]], #Wrapper._s -// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor1SV0A5KlassAA0C0Cvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass -// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) (@guaranteed S) -> @guaranteed Klass -// CHECK: return [[REG4]] -// CHECK: } +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV1kAA5KlassCvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #Wrapper._k +// CHECK: return [[REG2]] +// CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV11nested_get3Sivb : $@convention(method) (@guaranteed Wrapper) -> Int { +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV14nested_borrow1AA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1 // CHECK: [[REG2:%.*]] = struct_extract [[REG0]], #Wrapper._s -// CHECK: [[REG3:%.*]] = copy_value [[REG2]] -// CHECK: [[REG4:%.*]] = begin_borrow [[REG3]] -// CHECK: [[REG5:%.*]] = function_ref @$s15borrow_accessor1SV8getKlassAA0D0Cvg : $@convention(method) (@guaranteed S) -> @owned Klass -// CHECK: [[REG6:%.*]] = apply [[REG5]]([[REG4]]) : $@convention(method) (@guaranteed S) -> @owned Klass -// CHECK: end_borrow [[REG4]] -// CHECK: destroy_value [[REG3]] -// CHECK: [[REG9:%.*]] = begin_borrow [[REG6]] -// CHECK: [[REG10:%.*]] = class_method [[REG9]], #Klass.id!getter : (Klass) -> () -> Int, $@convention(method) (@guaranteed Klass) -> Int -// CHECK: [[REG11:%.*]] = apply [[REG10]]([[REG9]]) : $@convention(method) (@guaranteed Klass) -> Int -// CHECK: end_borrow [[REG9]] -// CHECK: destroy_value [[REG6]] -// CHECK: return [[REG11]] +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor1SV1kAA5KlassCvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) (@guaranteed S) -> @guaranteed Klass +// CHECK: return [[REG4]] // CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV11nested_get4Sivb : $@convention(method) (@guaranteed Wrapper) -> Int { -// CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor7WrapperV5s_getAA1SVvg : $@convention(method) (@guaranteed Wrapper) -> @owned S -// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) (@guaranteed Wrapper) -> @owned S -// CHECK: [[REG4:%.*]] = begin_borrow [[REG3]] -// CHECK: [[REG5:%.*]] = function_ref @$s15borrow_accessor1SV0A5KlassAA0C0Cvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass -// CHECK: [[REG6:%.*]] = apply [[REG5]]([[REG4]]) : $@convention(method) (@guaranteed S) -> @guaranteed Klass -// CHECK: [[REG7:%.*]] = copy_value [[REG6]] -// CHECK: end_borrow [[REG4]] -// CHECK: destroy_value [[REG3]] -// CHECK: [[REG10:%.*]] = begin_borrow [[REG7]] -// CHECK: [[REG11:%.*]] = class_method [[REG10]], #Klass.id!getter : (Klass) -> () -> Int, $@convention(method) (@guaranteed Klass) -> Int -// CHECK: [[REG12:%.*]] = apply [[REG11]]([[REG10]]) : $@convention(method) (@guaranteed Klass) -> Int -// CHECK: end_borrow [[REG10]] -// CHECK: destroy_value [[REG7]] -// CHECK: return [[REG12]] +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV14nested_borrow1AA5KlassCvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor7WrapperV1sAA1SVvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr S +// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) (@inout Wrapper) -> @guaranteed_addr S +// CHECK: [[REG4:%.*]] = struct_element_addr [[REG3]], #S._k +// CHECK: return [[REG4]] // CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV6nestedAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV14nested_borrow2AA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor7WrapperV1kAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass -// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass -// CHECK: return [[REG3]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1 +// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor7WrapperV1kAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass +// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV14nested_borrow2AA5KlassCvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #Wrapper._k +// CHECK: return [[REG2]] +// CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperVyAA5KlassCSicib : $@convention(method) (Int, @guaranteed Wrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG4:%.*]] = struct_extract [[REG1]], #Wrapper._k -// CHECK: return [[REG4]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], let, name "self", argno 2 +// CHECK: [[REG4:%.*]] = struct_extract [[REG1]], #Wrapper._k +// CHECK: return [[REG4]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperVyAA5KlassCSiciz : $@convention(method) (Int, @inout Wrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = struct_element_addr [[REG1]], #Wrapper._k +// CHECK: return [[REG4]] +// CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV16nested_subscriptAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 -// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type -// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor7WrapperVyAA5KlassCSicib : $@convention(method) (Int, @guaranteed Wrapper) -> @guaranteed Klass -// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) (Int, @guaranteed Wrapper) -> @guaranteed Klass -// CHECK: return [[REG7]] -// CHECK: } - -// TODO-CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV8if_klassAA5KlassCvb : $@convention(method) (@guaranteed Wrapper) -> @guaranteed Klass { -// TODO-CHECK: bb0([[REG0:%.*]] : @guaranteed $Wrapper): -// TODO-CHECK: cond_br {{.*}}, bb1, bb2 -// TODO-CHECK: bb1: -// TODO-CHECK: [[EX1:%.*]] = struct_extract [[REG0]], #Wrapper._k -// TODO-CHECK: br bb3([[EX1]]) -// TODO-CHECK: bb2: -// TODO-CHECK: [[EX2:%.*]] = struct_extract [[REG0]], #Wrapper._k -// TODO-CHECK: br bb3([[EX2]]) -// TODO-CHECK: bb3([[PHI:%.*]] : @guaranteed $Klass): -// TODO-CHECK: return [[PHI]] -// TODO-CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1 +// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor7WrapperVyAA5KlassCSicib : $@convention(method) (Int, @guaranteed Wrapper) -> @guaranteed Klass +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) (Int, @guaranteed Wrapper) -> @guaranteed Klass +// CHECK: return [[REG7]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor7WrapperV16nested_subscriptAA5KlassCvz : $@convention(method) (@inout Wrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*Wrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor7WrapperVyAA5KlassCSiciz : $@convention(method) (Int, @inout Wrapper) -> @guaranteed_addr Klass +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) (Int, @inout Wrapper) -> @guaranteed_addr Klass +// CHECK: return [[REG7]] +// CHECK: } // CHECK: sil [ossa] @$s15borrow_accessor10GenWrapperV4propxvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { // CHECK: bb0([[REG0:%.*]] : $*GenWrapper): -// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._prop -// CHECK: return [[REG2]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._prop +// CHECK: return [[REG2]] +// CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV11nested_propxvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { +// CHECK: sil [ossa] @$s15borrow_accessor10GenWrapperV4propxvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._prop +// CHECK: return [[REG2]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV1sAA1SVvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed S { // CHECK: bb0([[REG0:%.*]] : $*GenWrapper): -// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._w -// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor13SimpleWrapperV0A5_propxvb : $@convention(method) <τ_0_0> (@in_guaranteed SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0> (@in_guaranteed SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: return [[REG4]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._s +// CHECK: [[REG3:%.*]] = load_borrow [[REG2]] +// CHECK: [[REG4:%.*]] = unchecked_ownership_conversion [[REG3]], @guaranteed to @unowned +// CHECK: [[REG5:%.*]] = unchecked_ownership_conversion [[REG4]], @unowned to @guaranteed +// CHECK: end_borrow [[REG3]] +// CHECK: return [[REG5]] +// CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV6nestedxvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV1sAA1SVvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr S { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._s +// CHECK: return [[REG2]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV1kAA5KlassCvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : $*GenWrapper): -// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor10GenWrapperV4propxvb : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: return [[REG3]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._k +// CHECK: [[REG3:%.*]] = load_borrow [[REG2]] +// CHECK: [[REG4:%.*]] = unchecked_ownership_conversion [[REG3]], @guaranteed to @unowned +// CHECK: [[REG5:%.*]] = unchecked_ownership_conversion [[REG4]], @unowned to @guaranteed +// CHECK: end_borrow [[REG3]] +// CHECK: return [[REG5]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV1kAA5KlassCvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._k +// CHECK: return [[REG2]] +// CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV13nested_klass1AA5KlassCvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed Klass { +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV12nested_prop1xvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._w +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor13SimpleWrapperV4propxvb : $@convention(method) <τ_0_0> (@in_guaranteed SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0> (@in_guaranteed SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: return [[REG4]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV12nested_prop1xvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._w +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor13SimpleWrapperV4propxvz : $@convention(method) <τ_0_0> (@inout SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0> (@inout SimpleWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: return [[REG4]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV12nested_prop2xvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor10GenWrapperV4propxvb : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV9nested_k1AA5KlassCvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : $*GenWrapper): // CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref // CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._s // CHECK: [[REG3:%.*]] = load_borrow [[REG2]] -// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor1SV0A5KlassAA0C0Cvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor1SV1kAA5KlassCvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass // CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) (@guaranteed S) -> @guaranteed Klass // CHECK: [[REG6:%.*]] = unchecked_ownership_conversion [[REG5]], @guaranteed to @unowned // CHECK: [[REG7:%.*]] = unchecked_ownership_conversion [[REG6]], @unowned to @guaranteed @@ -626,32 +561,172 @@ func nctest() { // CHECK: return [[REG7]] // CHECK: } -// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV13nested_klass2AA5KlassCvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed Klass { +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV9nested_k1AA5KlassCvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = struct_element_addr [[REG0]], #GenWrapper._s +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor1SV1kAA5KlassCvz : $@convention(method) (@inout S) -> @guaranteed_addr Klass +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) (@inout S) -> @guaranteed_addr Klass +// CHECK: return [[REG4]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV9nested_k2AA5KlassCvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed Klass { // CHECK: bb0([[REG0:%.*]] : $*GenWrapper): // CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref // CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor10GenWrapperV1sAA1SVvb : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed S // CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) <τ_0_0> (@in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed S -// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor1SV0A5KlassAA0C0Cvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor1SV1kAA5KlassCvb : $@convention(method) (@guaranteed S) -> @guaranteed Klass // CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) (@guaranteed S) -> @guaranteed Klass // CHECK: return [[REG5]] // CHECK: } +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV9nested_k2AA5KlassCvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr Klass { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = function_ref @$s15borrow_accessor10GenWrapperV1sAA1SVvz : $@convention(method) <τ_0_0> (@inout GenWrapper<τ_0_0>) -> @guaranteed_addr S +// CHECK: [[REG3:%.*]] = apply [[REG2]]([[REG0]]) : $@convention(method) <τ_0_0> (@inout GenWrapper<τ_0_0>) -> @guaranteed_addr S +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor1SV1kAA5KlassCvz : $@convention(method) (@inout S) -> @guaranteed_addr Klass +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) (@inout S) -> @guaranteed_addr Klass +// CHECK: return [[REG5]] +// CHECK: } + // CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperVyxSicib : $@convention(method) (Int, @in_guaranteed GenWrapper) -> @guaranteed_addr T { // CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*GenWrapper): -// CHECK: [[REG4:%.*]] = struct_element_addr [[REG1]], #GenWrapper._prop -// CHECK: return [[REG4]] -// CHECK: } +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], let, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = struct_element_addr [[REG1]], #GenWrapper._prop +// CHECK: return [[REG4]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperVyxSiciz : $@convention(method) (Int, @inout GenWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = struct_element_addr [[REG1]], #GenWrapper._prop +// CHECK: return [[REG4]] +// CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV16nested_subscriptxvb : $@convention(method) (@in_guaranteed GenWrapper) -> @guaranteed_addr T { -// CHECK: bb0([[REG0]] : $*GenWrapper): -// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 -// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type -// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor10GenWrapperVyxSicib : $@convention(method) <τ_0_0> (Int, @in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) <τ_0_0> (Int, @in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 -// CHECK: return [[REG7]] -// CHECK: } +// CHECK: bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor10GenWrapperVyxSicib : $@convention(method) <τ_0_0> (Int, @in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) <τ_0_0> (Int, @in_guaranteed GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: return [[REG7]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor10GenWrapperV16nested_subscriptxvz : $@convention(method) (@inout GenWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG3:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG4:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG2]], [[REG3]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor10GenWrapperVyxSiciz : $@convention(method) <τ_0_0> (Int, @inout GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]], [[REG0]]) : $@convention(method) <τ_0_0> (Int, @inout GenWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: return [[REG7]] +// CHECK: } + +// CHECK: sil [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE4propxvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._prop +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE4propxvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._prop +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE2ncAA2NCVvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed NC { +// CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._nc +// CHECK: [[REG4:%.*]] = load_borrow [[REG3]] +// CHECK: [[REG5:%.*]] = unchecked_ownership_conversion [[REG4]], @guaranteed to @unowned +// CHECK: [[REG6:%.*]] = unchecked_ownership_conversion [[REG5]], @unowned to @guaranteed +// CHECK: end_borrow [[REG4]] +// CHECK: return [[REG6]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE2ncAA2NCVvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr NC { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._nc +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE3ncwAA0D0Vvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed NCWrapper { +// CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._ncw +// CHECK: [[REG4:%.*]] = load_borrow [[REG3]] +// CHECK: [[REG5:%.*]] = unchecked_ownership_conversion [[REG4]], @guaranteed to @unowned +// CHECK: [[REG6:%.*]] = unchecked_ownership_conversion [[REG5]], @unowned to @guaranteed +// CHECK: end_borrow [[REG4]] +// CHECK: return [[REG6]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE3ncwAA0D0Vvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr NCWrapper { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._ncw +// CHECK: return [[REG3]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE12nested_prop1xvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._w +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor15SimpleNCWrapperVAARi_zrlE4propxvb : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed SimpleNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed SimpleNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG6:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG5]] +// CHECK: return [[REG6]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE12nested_prop1xvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._w +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor15SimpleNCWrapperVAARi_zrlE4propxvz : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout SimpleNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout SimpleNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG6:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG5]] +// CHECK: return [[REG6]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE12nested_prop2xvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor12GenNCWrapperVAARi_zrlE4propxvb : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@in_guaranteed GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG5:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG4]] +// CHECK: return [[REG5]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE12nested_prop2xvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor12GenNCWrapperVAARi_zrlE4propxvz : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG5:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG4]] +// CHECK: return [[REG5]] +// CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE10nested_nc1AA2NCVvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed NC { // CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): @@ -672,15 +747,15 @@ func nctest() { // CHECK: return [[REG8]] // CHECK: } -// CHECK-LABEL: sil hidden [ossa] @$s15borrow_accessor9NCWrapperV2ncAA2NCVvb : $@convention(method) (@guaranteed NCWrapper) -> @guaranteed NC { -// CHECK: bb0([[REG0]] : @guaranteed $NCWrapper): -// CHECK: [[REG1:%.*]] = copy_value [[REG0]] -// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG1]] -// CHECK: [[REG4:%.*]] = begin_borrow [[REG2]] -// CHECK: [[REG5:%.*]] = struct_extract [[REG0]], #NCWrapper._nc -// CHECK: end_borrow [[REG4]] -// CHECK: destroy_value [[REG2]] -// CHECK: return [[REG5]] +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE10nested_nc1AA2NCVvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr NC { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #GenNCWrapper._ncw +// CHECK: [[REG4:%.*]] = function_ref @$s15borrow_accessor9NCWrapperV2ncAA2NCVvz : $@convention(method) (@inout NCWrapper) -> @guaranteed_addr NC +// CHECK: [[REG5:%.*]] = apply [[REG4]]([[REG3]]) : $@convention(method) (@inout NCWrapper) -> @guaranteed_addr NC +// CHECK: [[REG6:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG5]] +// CHECK: return [[REG6]] // CHECK: } // CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE10nested_nc2AA2NCVvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed NC { @@ -704,53 +779,62 @@ func nctest() { // CHECK: return [[REG9]] // CHECK: } -// CHECK-LABEL: sil hidden [ossa] @$s15borrow_accessor9NCWrapperV7nested1AA2NCVvb : $@convention(method) (@guaranteed NCWrapper) -> @guaranteed NC { -// CHECK: bb0([[REG0]] : @guaranteed $NCWrapper): -// CHECK: [[REG1:%.*]] = copy_value [[REG0]] -// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG1]] -// CHECK: [[REG4:%.*]] = begin_borrow [[REG2]] -// CHECK: [[REG5:%.*]] = struct_extract [[REG0]], #NCWrapper._s -// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor3NCSV2ncAA2NCVvb : $@convention(method) (@guaranteed NCS) -> @guaranteed NC -// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]]) : $@convention(method) (@guaranteed NCS) -> @guaranteed NC -// CHECK: [[REG8:%.*]] = copy_value [[REG7]] -// CHECK: [[REG9:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG8]] -// CHECK: [[REG10:%.*]] = begin_borrow [[REG9]] -// CHECK: end_borrow [[REG10]] -// CHECK: destroy_value [[REG9]] -// CHECK: end_borrow [[REG4]] -// CHECK: destroy_value [[REG2]] -// CHECK: return [[REG7]] -// CHECK-LABEL: } - -// CHECK-LABEL: sil hidden [ossa] @$s15borrow_accessor9NCWrapperVyAA2NCVSicib : $@convention(method) (Int, @guaranteed NCWrapper) -> @guaranteed NC { -// CHECK: bb0([[REG0]] : $Int, [[REG1]] : @guaranteed $NCWrapper): -// CHECK: [[REG3:%.*]] = copy_value [[REG1]] -// CHECK: [[REG4:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG3]] -// CHECK: [[REG6:%.*]] = begin_borrow [[REG4]] -// CHECK: [[REG7:%.*]] = struct_extract [[REG1]], #NCWrapper._nc -// CHECK: end_borrow [[REG6]] -// CHECK: destroy_value [[REG4]] -// CHECK: return [[REG7]] +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE10nested_nc2AA2NCVvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr NC { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = function_ref @$s15borrow_accessor12GenNCWrapperVAARi_zrlE3ncwAA0D0Vvz : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr NCWrapper +// CHECK: [[REG4:%.*]] = apply [[REG3]]([[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (@inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr NCWrapper +// CHECK: [[REG5:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG4]] +// CHECK: [[REG6:%.*]] = function_ref @$s15borrow_accessor9NCWrapperV2ncAA2NCVvz : $@convention(method) (@inout NCWrapper) -> @guaranteed_addr NC +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG5]]) : $@convention(method) (@inout NCWrapper) -> @guaranteed_addr NC +// CHECK: [[REG8:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG7]] +// CHECK: return [[REG8]] // CHECK: } -// CHECK-LABEL: sil hidden [ossa] @$s15borrow_accessor9NCWrapperV16nested_subscriptAA2NCVvb : $@convention(method) (@guaranteed NCWrapper) -> @guaranteed NC { -// CHECK: bb0([[REG0]] : @guaranteed $NCWrapper): -// CHECK: [[REG1:%.*]] = copy_value [[REG0]] -// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG1]] -// CHECK: [[REG4:%.*]] = begin_borrow [[REG2]] -// CHECK: [[REG5:%.*]] = integer_literal $Builtin.IntLiteral, 0 -// CHECK: [[REG6:%.*]] = metatype $@thin Int.Type -// CHECK: [[REG7:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG8:%.*]] = apply [[REG7]]([[REG5]], [[REG6]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int -// CHECK: [[REG9:%.*]] = function_ref @$s15borrow_accessor9NCWrapperVyAA2NCVSicib : $@convention(method) (Int, @guaranteed NCWrapper) -> @guaranteed NC -// CHECK: [[REG10:%.*]] = apply [[REG9]]([[REG8]], [[REG0]]) : $@convention(method) (Int, @guaranteed NCWrapper) -> @guaranteed NC -// CHECK: [[REG11:%.*]] = copy_value [[REG10]] -// CHECK: [[REG12:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG11]] -// CHECK: [[REG13:%.*]] = begin_borrow [[REG12]] -// CHECK: end_borrow [[REG13]] -// CHECK: destroy_value [[REG12]] -// CHECK: end_borrow [[REG4]] -// CHECK: destroy_value [[REG2]] -// CHECK: return [[REG10]] +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlEyxSicib : $@convention(method) (Int, @in_guaranteed GenNCWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], let, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG1]] +// CHECK: [[REG5:%.*]] = struct_element_addr [[REG4]], #GenNCWrapper._prop +// CHECK: return [[REG5]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlEyxSiciz : $@convention(method) (Int, @inout GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG1]] +// CHECK: [[REG5:%.*]] = struct_element_addr [[REG4]], #GenNCWrapper._prop +// CHECK: return [[REG5]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE16nested_subscriptxvb : $@convention(method) (@in_guaranteed GenNCWrapper) -> @guaranteed_addr T { +// CHECK: bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], let, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG0]] +// CHECK: [[REG3:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG4:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG5:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = apply [[REG5]]([[REG3]], [[REG4]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG7:%.*]] = function_ref @$s15borrow_accessor12GenNCWrapperVAARi_zrlEyxSicib : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @in_guaranteed GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG8:%.*]] = apply [[REG7]]([[REG6]], [[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @in_guaranteed GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG9:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG8]] +// CHECK: return [[REG9]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s15borrow_accessor12GenNCWrapperVAARi_zrlE16nested_subscriptxvz : $@convention(method) (@inout GenNCWrapper) -> @guaranteed_addr T { +// CHECK:bb0([[REG0:%.*]] : $*GenNCWrapper): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = integer_literal $Builtin.IntLiteral, 0 +// CHECK: [[REG4:%.*]] = metatype $@thin Int.Type +// CHECK: [[REG5:%.*]] = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG6:%.*]] = apply [[REG5]]([[REG3]], [[REG4]]) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK: [[REG7:%.*]] = function_ref @$s15borrow_accessor12GenNCWrapperVAARi_zrlEyxSiciz : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG8:%.*]] = apply [[REG7]]([[REG6]], [[REG2]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (Int, @inout GenNCWrapper<τ_0_0>) -> @guaranteed_addr τ_0_0 +// CHECK: [[REG9:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG8]] +// CHECK: return [[REG9]] // CHECK: } diff --git a/test/SILGen/borrow_accessor_container.swift b/test/SILGen/borrow_accessor_container.swift index e6a8c7cc1aad7..02a1fed16e061 100644 --- a/test/SILGen/borrow_accessor_container.swift +++ b/test/SILGen/borrow_accessor_container.swift @@ -11,6 +11,10 @@ public struct Container: ~Copyable { borrow { return _storage.baseAddress.unsafelyUnwrapped.pointee } + @_unsafeSelfDependentResult + mutate { + return &_storage.baseAddress.unsafelyUnwrapped.pointee + } } public subscript(index: Int) -> Element { @@ -19,11 +23,72 @@ public struct Container: ~Copyable { precondition(index >= 0 && index < _count, "Index out of bounds") return _storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee } + @_unsafeSelfDependentResult + mutate { + precondition(index >= 0 && index < _count, "Index out of bounds") + return &_storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee + } } } extension Container: Copyable where Element: Copyable {} +// CHECK: sil hidden [ossa] @$s25borrow_accessor_container9ContainerVAARi_zrlE5firstxvb : $@convention(method) (@guaranteed Container) -> @guaranteed_addr Element { +// CHECK: bb0([[REG0:%.*]] : @guaranteed $Container): +// CHECK: [[REG1:%.*]] = copy_value [[REG0]] +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG1]] +// CHECK: debug_value [[REG2]], let, name "self", argno 1 +// CHECK: [[REG4:%.*]] = begin_borrow [[REG2]] +// CHECK: [[REG5:%.*]] = struct_extract [[REG0]], #Container._storage +// CHECK: [[REG6:%.*]] = alloc_stack $Optional> +// CHECK: [[REG7:%.*]] = function_ref @$sSr11baseAddressSpyxGSgvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG8:%.*]] = apply [[REG7]]([[REG5]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: store [[REG8]] to [trivial] [[REG6]] +// CHECK: [[REG10:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG11:%.*]] = function_ref @$sSq17unsafelyUnwrappedxvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG12:%.*]] = apply [[REG11]]>([[REG10]], [[REG6]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG13:%.*]] = load [trivial] [[REG10]] +// CHECK: [[REG14:%.*]] = function_ref @$sSpsRi_zrlE7pointeexvlu : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafePointer<τ_0_0> +// CHECK: [[REG15:%.*]] = apply [[REG14]]([[REG13]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafePointer<τ_0_0> +// CHECK: [[REG16:%.*]] = struct_extract [[REG15]], #UnsafePointer._rawValue +// CHECK: [[REG17:%.*]] = pointer_to_address [[REG16]] to [strict] $*Element +// CHECK: [[REG18:%.*]] = mark_dependence [unresolved] [[REG17]] on [[REG13]] +// CHECK: [[REG19:%.*]] = begin_access [read] [unsafe] [[REG18]] +// CHECK: [[REG20:%.*]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[REG19]] +// CHECK: end_access [[REG19]] +// CHECK: dealloc_stack [[REG10]] +// CHECK: dealloc_stack [[REG6]] +// CHECK: end_borrow [[REG4]] +// CHECK: destroy_value [[REG2]] +// CHECK: return [[REG20]] +// CHECK: } + +// CHECK: sil hidden [ossa] @$s25borrow_accessor_container9ContainerVAARi_zrlE5firstxvz : $@convention(method) (@inout Container) -> @guaranteed_addr Element { +// CHECK: bb0([[REG0:%.*]] : $*Container): +// CHECK: debug_value [[REG0]], var, name "self", argno 1, expr op_deref +// CHECK: [[REG2:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG0]] +// CHECK: [[REG3:%.*]] = struct_element_addr [[REG2]], #Container._storage +// CHECK: [[REG4:%.*]] = load [trivial] [[REG3]] +// CHECK: [[REG5:%.*]] = alloc_stack $Optional> +// CHECK: [[REG6:%.*]] = function_ref @$sSr11baseAddressSpyxGSgvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG7:%.*]] = apply [[REG6]]([[REG4]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: store [[REG7]] to [trivial] [[REG5]] +// CHECK: [[REG9:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG10:%.*]] = function_ref @$sSq17unsafelyUnwrappedxvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG11:%.*]] = apply [[REG10]]>([[REG9]], [[REG5]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG12:%.*]] = load [trivial] [[REG9]] +// CHECK: [[REG13:%.*]] = function_ref @$sSpsRi_zrlE7pointeexvau : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG14:%.*]] = apply [[REG13]]([[REG12]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG15:%.*]] = struct_extract [[REG14]], #UnsafeMutablePointer._rawValue +// CHECK: [[REG16:%.*]] = pointer_to_address [[REG15]] to [strict] $*Element +// CHECK: [[REG17:%.*]] = mark_dependence [unresolved] [[REG16]] on [[REG12]] +// CHECK: [[REG18:%.*]] = begin_access [modify] [unsafe] [[REG17]] +// CHECK: [[REG19:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG18]] +// CHECK: end_access [[REG18]] +// CHECK: dealloc_stack [[REG9]] +// CHECK: dealloc_stack [[REG5]] +// CHECK: return [[REG19]] +// CHECK: } // CHECK: sil [ossa] @$s25borrow_accessor_container9ContainerVAARi_zrlEyxSicib : $@convention(method) (Int, @guaranteed Container) -> @guaranteed_addr Element { // CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : @guaranteed $Container): @@ -61,7 +126,45 @@ extension Container: Copyable where Element: Copyable {} // CHECK: destroy_value [[REG4]] // CHECK: return [[REG32]] // CHECK: } - + +// CHECK: sil [ossa] @$s25borrow_accessor_container9ContainerVAARi_zrlEyxSiciz : $@convention(method) (Int, @inout Container) -> @guaranteed_addr Element { +// CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*Container): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG1]] +// CHECK: [[REG5:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG6:%.*]] = begin_access [read] [unknown] [[REG4]] +// CHECK: [[REG7:%.*]] = struct_element_addr [[REG6]], #Container._storage +// CHECK: [[REG8:%.*]] = load [trivial] [[REG7]] +// CHECK: end_access [[REG6]] +// CHECK: [[REG10:%.*]] = function_ref @$sSr11baseAddressSpyxGSgvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG11:%.*]] = apply [[REG10]]([[REG8]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG12:%.*]] = alloc_stack $Optional> +// CHECK: store [[REG11]] to [trivial] [[REG12]] +// CHECK: [[REG14:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG15:%.*]] = function_ref @$sSq17unsafelyUnwrappedxvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG16:%.*]] = apply [[REG15]]>([[REG14]], [[REG12]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG17:%.*]] = load [trivial] [[REG14]] +// CHECK: [[REG18:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: store [[REG17]] to [trivial] [[REG18]] +// CHECK: [[REG20:%.*]] = function_ref @$ss8_PointerPsE8advanced2byxSi_tF : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: [[REG21:%.*]] = apply [[REG20]]>([[REG5]], [[REG0]], [[REG18]]) : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: dealloc_stack [[REG18]] +// CHECK: dealloc_stack [[REG14]] +// CHECK: dealloc_stack [[REG12]] +// CHECK: [[REG25:%.*]] = load [trivial] [[REG5]] +// CHECK: [[REG26:%.*]] = function_ref @$sSpsRi_zrlE7pointeexvau : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG27:%.*]] = apply [[REG26]]([[REG25]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG28:%.*]] = struct_extract [[REG27]], #UnsafeMutablePointer._rawValue +// CHECK: [[REG29:%.*]] = pointer_to_address [[REG28]] to [strict] $*Element +// CHECK: [[REG30:%.*]] = mark_dependence [unresolved] [[REG29]] on [[REG25]] +// CHECK: [[REG31:%.*]] = begin_access [modify] [unsafe] [[REG30]] +// CHECK: [[REG32:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG31]] +// CHECK: end_access [[REG31]] +// CHECK: dealloc_stack [[REG5]] +// CHECK: return [[REG32]] +// CHECK: } + public class Klass {} public struct S { @@ -85,6 +188,11 @@ public struct CopyableContainer { precondition(index >= 0 && index < _count, "Index out of bounds") return _storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee._k } + @_unsafeSelfDependentResult + mutate { + precondition(index >= 0 && index < _count, "Index out of bounds") + return &_storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee._k + } } } @@ -124,6 +232,43 @@ public struct CopyableContainer { // CHECK: return [[REG32]] // CHECK: } +// CHECK: sil [ossa] @$s25borrow_accessor_container17CopyableContainerVyAA5KlassCSiciz : $@convention(method) (Int, @inout CopyableContainer) -> @guaranteed_addr Klass { +// CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*CopyableContainer): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG5:%.*]] = begin_access [read] [unknown] [[REG1]] +// CHECK: [[REG6:%.*]] = struct_element_addr [[REG5]], #CopyableContainer._storage +// CHECK: [[REG7:%.*]] = load [trivial] [[REG6]] +// CHECK: end_access [[REG5]] +// CHECK: [[REG9:%.*]] = function_ref @$sSr11baseAddressSpyxGSgvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG10:%.*]] = apply [[REG9]]([[REG7]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG11:%.*]] = alloc_stack $Optional> +// CHECK: store [[REG10]] to [trivial] [[REG11]] +// CHECK: [[REG13:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG14:%.*]] = function_ref @$sSq17unsafelyUnwrappedxvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG15:%.*]] = apply [[REG14]]>([[REG13]], [[REG11]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG16:%.*]] = load [trivial] [[REG13]] +// CHECK: [[REG17:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: store [[REG16]] to [trivial] [[REG17]] +// CHECK: [[REG19:%.*]] = function_ref @$ss8_PointerPsE8advanced2byxSi_tF : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: [[REG20:%.*]] = apply [[REG19]]>([[REG4]], [[REG0]], [[REG17]]) : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: dealloc_stack [[REG17]] +// CHECK: dealloc_stack [[REG13]] +// CHECK: dealloc_stack [[REG11]] +// CHECK: [[REG24:%.*]] = load [trivial] [[REG4]] +// CHECK: [[REG25:%.*]] = function_ref @$sSpsRi_zrlE7pointeexvau : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG26:%.*]] = apply [[REG25]]([[REG24]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG27:%.*]] = struct_extract [[REG26]], #UnsafeMutablePointer._rawValue +// CHECK: [[REG28:%.*]] = pointer_to_address [[REG27]] to [strict] $*S +// CHECK: [[REG29:%.*]] = mark_dependence [unresolved] [[REG28]] on [[REG24]] +// CHECK: [[REG30:%.*]] = begin_access [modify] [unsafe] [[REG29]] +// CHECK: [[REG31:%.*]] = struct_element_addr [[REG30]], #S._k +// CHECK: end_access [[REG30]] +// CHECK: dealloc_stack [[REG4]] +// CHECK: return [[REG31]] +// CHECK: } + public struct NC : ~Copyable {} public struct NonCopyableContainer : ~Copyable { @@ -143,6 +288,11 @@ public struct NonCopyableContainer : ~Copyable { precondition(index >= 0 && index < _count, "Index out of bounds") return _storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee } + @_unsafeSelfDependentResult + mutate { + precondition(index >= 0 && index < _count, "Index out of bounds") + return &_storage.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee + } } } @@ -187,4 +337,41 @@ public struct NonCopyableContainer : ~Copyable { // CHECK: destroy_value [[REG4]] // CHECK: return [[REG36]] // CHECK: } - + +// CHECK: sil [ossa] @$s25borrow_accessor_container20NonCopyableContainerVyAA2NCVSiciz : $@convention(method) (Int, @inout NonCopyableContainer) -> @guaranteed_addr NC { +// CHECK: bb0([[REG0:%.*]] : $Int, [[REG1:%.*]] : $*NonCopyableContainer): +// CHECK: debug_value [[REG0]], let, name "index", argno 1 +// CHECK: debug_value [[REG1]], var, name "self", argno 2, expr op_deref +// CHECK: [[REG4:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG1]] +// CHECK: [[REG5:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG6:%.*]] = begin_access [read] [unknown] [[REG4]] +// CHECK: [[REG7:%.*]] = struct_element_addr [[REG6]], #NonCopyableContainer._storage +// CHECK: [[REG8:%.*]] = load [trivial] [[REG7]] +// CHECK: end_access [[REG6]] +// CHECK: [[REG10:%.*]] = function_ref @$sSr11baseAddressSpyxGSgvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG11:%.*]] = apply [[REG10]]([[REG8]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutableBufferPointer<τ_0_0>) -> Optional> +// CHECK: [[REG12:%.*]] = alloc_stack $Optional> +// CHECK: store [[REG11]] to [trivial] [[REG12]] +// CHECK: [[REG14:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: [[REG15:%.*]] = function_ref @$sSq17unsafelyUnwrappedxvg : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG16:%.*]] = apply [[REG15]]>([[REG14]], [[REG12]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Escapable> (@in_guaranteed Optional<τ_0_0>) -> @lifetime(copy 0) @out τ_0_0 +// CHECK: [[REG17:%.*]] = load [trivial] [[REG14]] +// CHECK: [[REG18:%.*]] = alloc_stack $UnsafeMutablePointer +// CHECK: store [[REG17]] to [trivial] [[REG18]] +// CHECK: [[REG20:%.*]] = function_ref @$ss8_PointerPsE8advanced2byxSi_tF : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: [[REG21:%.*]] = apply [[REG20]]>([[REG5]], [[REG0]], [[REG18]]) : $@convention(method) <τ_0_0 where τ_0_0 : _Pointer> (Int, @in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: dealloc_stack [[REG18]] +// CHECK: dealloc_stack [[REG14]] +// CHECK: dealloc_stack [[REG12]] +// CHECK: [[REG25:%.*]] = load [trivial] [[REG5]] +// CHECK: [[REG26:%.*]] = function_ref @$sSpsRi_zrlE7pointeexvau : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG27:%.*]] = apply [[REG26]]([[REG25]]) : $@convention(method) <τ_0_0 where τ_0_0 : ~Copyable> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> +// CHECK: [[REG28:%.*]] = struct_extract [[REG27]], #UnsafeMutablePointer._rawValue +// CHECK: [[REG29:%.*]] = pointer_to_address [[REG28]] to [strict] $*NC +// CHECK: [[REG30:%.*]] = mark_dependence [unresolved] [[REG29]] on [[REG25]] +// CHECK: [[REG31:%.*]] = begin_access [modify] [unsafe] [[REG30]] +// CHECK: [[REG32:%.*]] = mark_unresolved_non_copyable_value [consumable_and_assignable] [[REG31]] +// CHECK: end_access [[REG31]] +// CHECK: dealloc_stack [[REG5]] +// CHECK: return [[REG32]] +// CHECK: } diff --git a/test/SILGen/borrow_accessor_failues.swift b/test/SILGen/borrow_accessor_failues.swift new file mode 100644 index 0000000000000..488665bacc6d3 --- /dev/null +++ b/test/SILGen/borrow_accessor_failues.swift @@ -0,0 +1,270 @@ +// RUN:%target-swift-frontend -emit-silgen %s -verify -enable-experimental-feature BorrowAndMutateAccessors + +// REQUIRES: swift_feature_BorrowAndMutateAccessors + +public class Klass { + var id: Int = 0 +} + +func get_k() -> Klass { + return Klass() +} + +public struct S { + var _k: Klass + + var borrow_k: Klass { + borrow { + return _k + } + } + var get_k: Klass { + get { + return _k + } + } + var read_k: Klass { + _read { + yield _k + } + } +} + +public struct Wrapper { + var _k: Klass + var _s: S + + var k: Klass { + borrow { + return _k + } + } + + var s: S { + borrow { + return _s + } + } + + var s_get: S { + get { + return _s + } + } + + var s_read: S { + _read { + yield _s + } + } + + var nested_get1: Klass { + borrow { + return _s.get_k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var nested_get2: Klass { + borrow { + return s_get.borrow_k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var nested_get3: Int { + borrow { + return _s.get_k.id // TODO: Diagnose this case + } + } + + var nested_get4: Int { + borrow { + return s_get.borrow_k.id // TODO: Diagnose this case + } + } + + var nested_read1: Klass { + borrow { + return _s.read_k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var nested_read2: Klass { + borrow { + return s_read.read_k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var owned_value_direct: Klass { + borrow { + return get_k() // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var owned_value_projected: Klass { + borrow { + let w = Wrapper(_k: Klass(), _s: S(_k: Klass())) + return w.k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var if_klass: Klass { + borrow { + if Int.random(in: 1..<100) == 0 { + return _k + } + return _k // expected-error{{multiple return statements in borrow accessors are not yet supported}} + } + } + + var tuple_klass: (Klass, Klass) { + borrow { + return (_k, _k) // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var opt_klass: Klass? { + borrow { + if Int.random(in: 1..<100) == 0 { + return nil + } + return _k // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } +} + +public struct SimpleWrapper { + var _prop: T + + var borrow_prop: T { + borrow { + return _prop + } + } + + var get_prop: T { + get { + return _prop + } + } + + var read_prop: T { + _read { + yield _prop + } + } +} + +public struct GenWrapper { + var _prop: T + var _w: SimpleWrapper + + public var prop: T { + borrow { + return _prop + } + } + + var get_prop: T { + borrow { + return _w.get_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + + } + } + + var read_prop: T { + borrow { + return _w.read_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var if_prop: T { + borrow { + if Int.random(in: 1..<100) == 0 { + return _prop + } + return _prop // expected-error{{multiple return statements in borrow accessors are not yet supported}} + } + } + + var tuple_prop: (T, T) { + borrow { + return (_prop, _prop) // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } + + var opt_T: T? { + borrow { + if Int.random(in: 1..<100) == 0 { + return nil + } + return _prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + + } + } +} + +public struct SimpleNCWrapper : ~Copyable { + var _prop: T + + var borrow_prop: T { + borrow { + return _prop + } + } + + var get_prop: T { + get { + return _prop + } + } + + var read_prop: T { + _read { + yield _prop + } + } +} + +public struct GenNCWrapper : ~Copyable { + var _prop: T + var _w: SimpleNCWrapper + + public var prop: T { + borrow { + return _prop + } + } + + var nested_get: T { + borrow { + return _w.get_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + + } + } + + var nested_read: T { + borrow { + return _w.read_prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + + } + } + + var if_prop: T { + borrow { + if Int.random(in: 1..<100) == 0 { + return _prop + } + return _prop // expected-error{{multiple return statements in borrow accessors are not yet supported}} + } + } + + var opt_T: T? { + borrow { + if Int.random(in: 1..<100) == 0 { + return nil + } + return _prop // expected-error{{invalid return value from borrow accessor}} // expected-note{{borrow accessors can return either literals, stored properties or computed properties that have borrow accessors}} + } + } +} +