diff --git a/include/swift/AST/AnyFunctionRef.h b/include/swift/AST/AnyFunctionRef.h index 49522eb1e3ff3..fe60d8aaf01ba 100644 --- a/include/swift/AST/AnyFunctionRef.h +++ b/include/swift/AST/AnyFunctionRef.h @@ -116,6 +116,11 @@ class AnyFunctionRef { if (auto *AFD = TheFunction.dyn_cast()) { if (auto *FD = dyn_cast(AFD)) return FD->mapTypeIntoContext(FD->getResultInterfaceType()); + if (auto *CD = dyn_cast(AFD)) { + if (CD->hasLifetimeDependentReturn()) { + return CD->getResultInterfaceType(); + } + } return TupleType::getEmpty(AFD->getASTContext()); } return TheFunction.get()->getResultType(); diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index ac5772f6b8db4..6bab682f4696d 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -8299,15 +8299,18 @@ class ConstructorDecl : public AbstractFunctionDecl { /// inserted at the end of the initializer by SILGen. Expr *CallToSuperInit = nullptr; + /// Valid when lifetime dependence specifiers are present. + TypeLoc InitRetType; + public: - ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, + ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, bool Async, SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, TypeLoc thrownTy, ParameterList *BodyParams, - GenericParamList *GenericParams, - DeclContext *Parent); + GenericParamList *GenericParams, + DeclContext *Parent, TypeRepr *InitRetTy); static ConstructorDecl * createImported(ASTContext &ctx, ClangNode clangNode, DeclName name, @@ -8329,6 +8332,10 @@ class ConstructorDecl : public AbstractFunctionDecl { /// Get the interface type of the initializing constructor. Type getInitializerInterfaceType(); + TypeRepr *getResultTypeRepr() const { return InitRetType.getTypeRepr(); } + + void setDeserializedResultTypeLoc(TypeLoc ResultTyR); + /// Get the typechecked call to super.init expression, which needs to be /// inserted at the end of the initializer by SILGen. Expr *getSuperInitCall() { return CallToSuperInit; } @@ -8408,6 +8415,8 @@ class ConstructorDecl : public AbstractFunctionDecl { Bits.ConstructorDecl.HasStubImplementation = stub; } + bool hasLifetimeDependentReturn() const; + ConstructorDecl *getOverriddenDecl() const { return cast_or_null( AbstractFunctionDecl::getOverriddenDecl()); diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 35df14af2f232..88971d17f9112 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -2179,6 +2179,10 @@ ERROR(requires_experimental_feature, none, "%2 is enabled", (StringRef, bool, StringRef)) +//------------------------------------------------------------------------------ +// MARK: Lifetime dependence +//------------------------------------------------------------------------------ + ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken, "expected '(' after lifetime dependence specifier", ()) @@ -2193,5 +2197,9 @@ ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken, ERROR(expected_param_index_lifetime_dependence, PointsToFirstBadToken, "expected unsigned parameter index in lifetime dependence specifier", ()) +ERROR(lifetime_dependence_invalid_init_return, PointsToFirstBadToken, + "expected Self return type for initializers with lifetime dependence " + "specifiers", + ()) #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9ed5354cd0069..8cea6abdfaff4 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7827,5 +7827,9 @@ ERROR(pack_iteration_where_clause_not_supported, none, "cannot infer lifetime dependence, no ~Escapable or ~Copyable " "parameters with ownership modifiers present", ()) + ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none, + "expected nil or self as return values in an initializer with " + "lifetime dependent specifiers", + ()) #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/lib/AST/ASTBridging.cpp b/lib/AST/ASTBridging.cpp index 553cdc06ac7ae..eff7e296c6563 100644 --- a/lib/AST/ASTBridging.cpp +++ b/lib/AST/ASTBridging.cpp @@ -943,12 +943,13 @@ BridgedConstructorDecl BridgedConstructorDecl_createParsed( auto throwsLoc = cThrowsLoc.unbridged(); auto failabilityMarkLoc = cFailabilityMarkLoc.unbridged(); // FIXME: rethrows - + // TODO: Handle LifetimeDependentReturnTypeRepr here. auto *decl = new (context) ConstructorDecl( declName, cInitKeywordLoc.unbridged(), failabilityMarkLoc.isValid(), failabilityMarkLoc, asyncLoc.isValid(), asyncLoc, throwsLoc.isValid(), throwsLoc, thrownType.unbridged(), parameterList, - genericParams.unbridged(), cDeclContext.unbridged()); + genericParams.unbridged(), cDeclContext.unbridged(), + /*InitRetTy*/ nullptr); decl->setTrailingWhereClause(genericWhereClause.unbridged()); decl->setImplicitlyUnwrappedOptional(isIUO); diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 72b483a3fa4fd..e2eda05ff998a 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -1075,17 +1075,25 @@ class Verifier : public ASTWalker { resultType = FD->mapTypeIntoContext(resultType); } else if (auto closure = dyn_cast(func)) { resultType = closure->getResultType(); + } else if (auto *CD = dyn_cast(func)) { + if (CD->hasLifetimeDependentReturn()) { + resultType = CD->getResultInterfaceType(); + } else { + resultType = TupleType::getEmpty(Ctx); + } } else { resultType = TupleType::getEmpty(Ctx); } - + if (S->hasResult()) { - if (isa(func)) { - Out << "Expected ReturnStmt not to have a result. A constructor " - "should not return a result. Returned expression: "; - S->getResult()->dump(Out); - Out << "\n"; - abort(); + if (auto *CD = dyn_cast(func)) { + if (!CD->hasLifetimeDependentReturn()) { + Out << "Expected ReturnStmt not to have a result. A constructor " + "should not return a result. Returned expression: "; + S->getResult()->dump(Out); + Out << "\n"; + abort(); + } } auto result = S->getResult(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1acf5fe782825..48b58f9466246 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3577,6 +3577,8 @@ TypeRepr *ValueDecl::getResultTypeRepr() const { returnRepr = SD->getElementTypeRepr(); } else if (auto *MD = dyn_cast(this)) { returnRepr = MD->resultType.getTypeRepr(); + } else if (auto *CD = dyn_cast(this)) { + returnRepr = CD->getResultTypeRepr(); } return returnRepr; @@ -10383,7 +10385,7 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, TypeLoc ThrownType, ParameterList *BodyParams, GenericParamList *GenericParams, - DeclContext *Parent) + DeclContext *Parent, TypeRepr *ResultTyR) : AbstractFunctionDecl(DeclKind::Constructor, Parent, Name, ConstructorLoc, Async, AsyncLoc, Throws, ThrowsLoc, ThrownType, /*HasImplicitSelfDecl=*/true, @@ -10393,7 +10395,8 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, { if (BodyParams) setParameters(BodyParams); - + + InitRetType = TypeLoc(ResultTyR); Bits.ConstructorDecl.HasStubImplementation = 0; Bits.ConstructorDecl.Failable = Failable; @@ -10414,11 +10417,16 @@ ConstructorDecl *ConstructorDecl::createImported( failable, failabilityLoc, async, asyncLoc, throws, throwsLoc, TypeLoc::withoutLoc(thrownType), - bodyParams, genericParams, parent); + bodyParams, genericParams, parent, + /*LifetimeDependenceTypeRepr*/ nullptr); ctor->setClangNode(clangNode); return ctor; } +void ConstructorDecl::setDeserializedResultTypeLoc(TypeLoc ResultTyR) { + InitRetType = ResultTyR; +} + bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { // The initializer must have a single, non-empty argument name. if (getName().getArgumentNames().size() != 1 || @@ -10432,6 +10440,10 @@ bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { return params->get(0)->getInterfaceType()->isVoid(); } +bool ConstructorDecl::hasLifetimeDependentReturn() const { + return isa_and_nonnull(getResultTypeRepr()); +} + DestructorDecl::DestructorDecl(SourceLoc DestructorLoc, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Destructor, Parent, DeclBaseName::createDestructor(), DestructorLoc, diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 18633a2f3b0e1..aefd19a79d387 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3646,7 +3646,8 @@ namespace { /*failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*ThrownType=*/TypeLoc(), bodyParams, genericParams, dc); + /*ThrownType=*/TypeLoc(), bodyParams, genericParams, dc, + /*LifetimeDependentReturnTypeRepr*/ nullptr); } else { auto resultTy = importedType.getType(); @@ -6221,7 +6222,8 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer( failable, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), - parameterList, /*GenericParams=*/nullptr, dc); + parameterList, /*GenericParams=*/nullptr, dc, + /*LifetimeDependentReturnTypeRepr*/ nullptr); result->setImplicitlyUnwrappedOptional(isIUO); result->getASTContext().evaluator.cacheOutput(InitKindRequest{result}, std::move(initKind)); @@ -6735,7 +6737,8 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/importedName.getErrorInfo().has_value(), /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), bodyParams, - /*GenericParams=*/nullptr, const_cast(dc)); + /*GenericParams=*/nullptr, const_cast(dc), + /*LifetimeDependentReturnTypeRepr*/ nullptr); addObjCAttribute(result, selector); recordMemberInContext(dc, result); diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index a8847241c1b8f..bc48c1f99131e 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -493,9 +493,10 @@ SwiftDeclSynthesizer::createDefaultConstructor(NominalTypeDecl *structDecl) { ConstructorDecl(name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), emptyPL, - /*GenericParams=*/nullptr, structDecl); + /*GenericParams=*/nullptr, structDecl, + /*LifetimeDependentReturnTypeRepr*/ nullptr); constructor->setAccess(AccessLevel::Public); @@ -623,9 +624,10 @@ ConstructorDecl *SwiftDeclSynthesizer::createValueConstructor( ConstructorDecl(name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), paramList, - /*GenericParams=*/nullptr, structDecl); + /*GenericParams=*/nullptr, structDecl, + /*LifetimeDependentReturnTypeRepr*/ nullptr); constructor->setAccess(AccessLevel::Public); @@ -1271,13 +1273,14 @@ SwiftDeclSynthesizer::makeEnumRawValueConstructor(EnumDecl *enumDecl) { auto paramPL = ParameterList::createWithoutLoc(param); DeclName name(C, DeclBaseName::createConstructor(), paramPL); - auto *ctorDecl = new (C) - ConstructorDecl(name, enumDecl->getLoc(), - /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), - /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*ThrownType=*/TypeLoc(), paramPL, - /*GenericParams=*/nullptr, enumDecl); + auto *ctorDecl = + new (C) ConstructorDecl(name, enumDecl->getLoc(), + /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), + /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*ThrownType=*/TypeLoc(), paramPL, + /*GenericParams=*/nullptr, enumDecl, + /*LifetimeDependentReturnTypeRepr*/ nullptr); ctorDecl->setImplicit(); ctorDecl->setAccess(AccessLevel::Public); ctorDecl->setBodySynthesizer(synthesizeEnumRawValueConstructorBody, enumDecl); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2781235839818..e69062dde8dfe 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -9817,7 +9817,16 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { isAsync = true; } - if (FuncRetTy) { + if (auto *lifetimeTyR = + dyn_cast_or_null(FuncRetTy)) { + auto *identTyR = dyn_cast(lifetimeTyR->getBase()); + if (!identTyR || + identTyR->getNameRef().getBaseIdentifier() != Context.Id_Self) { + diagnose(FuncRetTy->getStartLoc(), + diag::lifetime_dependence_invalid_init_return); + return nullptr; + } + } else if (FuncRetTy) { diagnose(FuncRetTy->getStartLoc(), diag::initializer_result_type) .fixItRemove(FuncRetTy->getSourceRange()); } @@ -9836,7 +9845,7 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { isAsync, asyncLoc, throwsLoc.isValid(), throwsLoc, thrownTy, BodyParams, GenericParams, - CurDeclContext); + CurDeclContext, FuncRetTy); CD->setImplicitlyUnwrappedOptional(IUO); CD->getAttrs() = Attributes; diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 5ec5666d448f2..97871c2bb3c7a 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -680,10 +680,13 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { // Create a basic block to jump to for the implicit 'self' return. // We won't emit this until after we've emitted the body. // The epilog takes a void return because the return of 'self' is implicit. + // When lifetime dependence specifiers are present, epilog will take the + // explicit 'self' return. prepareEpilog(ctor, - llvm::None, - ctor->getEffectiveThrownErrorType(), - CleanupLocation(ctor)); + ctor->hasLifetimeDependentReturn() + ? llvm::Optional(ctor->getResultInterfaceType()) + : llvm::None, + ctor->getEffectiveThrownErrorType(), CleanupLocation(ctor)); // If the constructor can fail, set up an alternative epilog for constructor // failure. @@ -767,7 +770,11 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { // Emit the constructor body. emitStmt(ctor->getTypecheckedBody()); - + if (ctor->hasLifetimeDependentReturn()) { + emitEpilog(ctor, /*UsesCustomEpilog*/ false); + return; + } + // Build a custom epilog block, since the AST representation of the // constructor decl (which has no self in the return type) doesn't match the // SIL representation. diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 94b6d3a68848b..205fd1ac76b88 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -330,7 +330,8 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), - paramList, /*GenericParams=*/nullptr, decl); + paramList, /*GenericParams=*/nullptr, decl, + /*LifetimeDependentReturnTypeRepr*/ nullptr); // Mark implicit. ctor->setImplicit(); @@ -830,7 +831,8 @@ createDesignatedInitOverride(ClassDecl *classDecl, /*Throws=*/superclassCtor->hasThrows(), /*ThrowsLoc=*/SourceLoc(), TypeLoc::withoutLoc(thrownType), - bodyParams, genericParams, implCtx); + bodyParams, genericParams, implCtx, + /*LifetimeDependentReturnTypeRepr*/ nullptr); ctor->setImplicit(); diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index fbafe602bfd88..88bce0b5b1e81 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -1888,11 +1888,12 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) { auto *initDecl = new (C) ConstructorDecl(name, SourceLoc(), - /*Failable=*/false,SourceLoc(), + /*Failable=*/false, SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/true, SourceLoc(), /*ThrownType=*/TypeLoc(), paramList, - /*GenericParams=*/nullptr, conformanceDC); + /*GenericParams=*/nullptr, conformanceDC, + /*LifetimeDependentReturnTypeRepr*/ nullptr); initDecl->setImplicit(); initDecl->setSynthesized(); diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index 7c975d81822b3..8e933e6059348 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -133,7 +133,8 @@ static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), paramList, - /*GenericParams=*/nullptr, parentDC); + /*GenericParams=*/nullptr, parentDC, + /*LifetimeDependentReturnTypeRepr*/ nullptr); initDecl->setImplicit(); diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index 6673d600bfd1b..9175ec1c52e7d 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -423,15 +423,16 @@ deriveRawRepresentable_init(DerivedConformance &derived) { auto paramList = ParameterList::createWithoutLoc(rawDecl); DeclName name(C, DeclBaseName::createConstructor(), paramList); - + auto initDecl = - new (C) ConstructorDecl(name, SourceLoc(), - /*Failable=*/ true, /*FailabilityLoc=*/SourceLoc(), - /*Async=*/false, /*AsyncLoc=*/SourceLoc(), - /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*ThrownType=*/TypeLoc(), paramList, - /*GenericParams=*/nullptr, parentDC); - + new (C) ConstructorDecl(name, SourceLoc(), + /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), + /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + /*ThrownType=*/TypeLoc(), paramList, + /*GenericParams=*/nullptr, parentDC, + /*LifetimeDependentReturnTypeRepr*/ nullptr); + initDecl->setImplicit(); initDecl->setBodySynthesizer(&deriveBodyRawRepresentable_init); addNonIsolatedToSynthesized(enumDecl, initDecl); diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index c83fcbe17dad7..d4222cccfe2ab 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1713,6 +1713,25 @@ Stmt *PreCheckReturnStmtRequest::evaluate(Evaluator &evaluator, ReturnStmt *RS, // 'nil'. auto *nilExpr = dyn_cast(E->getSemanticsProvidingExpr()); if (!nilExpr) { + if (ctor->hasLifetimeDependentReturn()) { + // Typecheck the expression unconditionally. + TypeChecker::typeCheckExpression(E, DC, {}); + + auto *checkE = E; + if (auto *load = dyn_cast(checkE)) + checkE = load->getSubExpr(); + bool isSelf = false; + if (auto DRE = dyn_cast(checkE)) + isSelf = DRE->getDecl() == ctor->getImplicitSelfDecl(); + + if (!isSelf) { + ctx.Diags.diagnose( + RS->getStartLoc(), + diag::lifetime_dependence_ctor_non_self_or_nil_return); + RS->setResult(nullptr); + } + return RS; + } ctx.Diags.diagnose(RS->getReturnLoc(), diag::return_init_non_nil) .highlight(E->getSourceRange()); RS->setResult(nullptr); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 7d66cc04983e0..55f6178012e74 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3540,7 +3540,8 @@ class DeclDeserializer { /*ThrowsLoc=*/SourceLoc(), TypeLoc::withoutLoc(thrownType), /*BodyParams=*/nullptr, - genericParams, parent); + genericParams, parent, + nullptr); declOrOffset = ctor; ctor->setGenericSignature(MF.getGenericSignature(genericSigID)); @@ -3554,6 +3555,15 @@ class DeclDeserializer { assert(bodyParams && "missing parameters for constructor"); ctor->setParameters(bodyParams); + SmallVector specifierList; + if (MF.maybeReadLifetimeDependence(specifierList, bodyParams->size())) { + auto SelfType = ctor->getDeclaredInterfaceType(); + auto typeRepr = new (ctx) FixedTypeRepr(SelfType, SourceLoc()); + auto lifetimeTypeRepr = + LifetimeDependentReturnTypeRepr::create(ctx, typeRepr, specifierList); + ctor->setDeserializedResultTypeLoc(TypeLoc(lifetimeTypeRepr, SelfType)); + } + if (auto errorConvention = MF.maybeReadForeignErrorConvention()) ctor->setForeignErrorConvention(*errorConvention); if (auto asyncConvention = MF.maybeReadForeignAsyncConvention()) diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 787f326e10bd1..0b35b07252e4f 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -4783,6 +4783,12 @@ class Serializer::DeclSerializer : public DeclVisitor { writeGenericParams(ctor->getGenericParams()); writeParameterList(ctor->getParameters()); + auto fnType = ty->getAs(); + if (fnType && fnType->hasLifetimeDependenceInfo()) { + assert(!fnType->getLifetimeDependenceInfo().empty()); + writeLifetimeDependenceInfo(fnType->getLifetimeDependenceInfo()); + } + if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); if (auto asyncConvention = ctor->getForeignAsyncConvention()) diff --git a/test/Parse/explicit_lifetime_dependence_specifiers.swift b/test/Parse/explicit_lifetime_dependence_specifiers.swift index a2939967037a4..9abe4f0fd4be4 100644 --- a/test/Parse/explicit_lifetime_dependence_specifiers.swift +++ b/test/Parse/explicit_lifetime_dependence_specifiers.swift @@ -8,6 +8,37 @@ struct BufferView : ~Escapable { init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } + init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) { + if (i % 2 == 0) { + return nil + } + self.ptr = ptr + } + init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> _borrow(a) Self { + self.ptr = ptr + return self + } + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array) -> _consume(a) Self { + self.ptr = ptr + return self + } + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array, b: borrowing Array) -> _consume(a) _borrow(b) Self { + self.ptr = ptr + return self + } + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array, b: borrowing Array, c: Double) -> _consume(a) _borrow(b) Int { // expected-error{{expected Self return type for initializers with lifetime dependence specifiers}} + self.ptr = ptr + return 0 + } + /* TODO: Enable this test once stdlib builds with NonescapableTypes support + init?(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array, _ i: Int) -> _borrow(a) Self { + if (i % 2 == 0) { + self.ptr = ptr + return self + } + return nil + } + */ } struct MutableBufferView : ~Escapable, ~Copyable { diff --git a/test/SIL/explicit_lifetime_dependence_specifiers.swift b/test/SIL/explicit_lifetime_dependence_specifiers.swift index 8a29f068a766a..4fd46dbb4b695 100644 --- a/test/SIL/explicit_lifetime_dependence_specifiers.swift +++ b/test/SIL/explicit_lifetime_dependence_specifiers.swift @@ -1,7 +1,6 @@ // RUN: %target-swift-frontend %s \ // RUN: -emit-sil \ // RUN: -enable-builtin-module \ -// RUN: -Xllvm -disable-lifetime-dependence-diagnostics \ // RUN: -enable-experimental-feature NonescapableTypes \ // RUN: -disable-experimental-parser-round-trip \ // RUN: -enable-experimental-feature NoncopyableGenerics \ @@ -17,6 +16,28 @@ struct BufferView : ~Escapable { init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } + @_unsafeNonescapableResult + init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) { + if (i % 2 == 0) { + return nil + } + self.ptr = ptr + } +// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _borrow(2) @owned BufferView { + init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> _borrow(a) Self { + self.ptr = ptr + return self + } +// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySdGtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Array, @thin BufferView.Type) -> _inherit(2) @owned BufferView { + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array) -> _consume(a) Self { + self.ptr = ptr + return self + } +// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySdGSaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Array, @guaranteed Array, @thin BufferView.Type) -> _inherit(2)_borrow(3) @owned BufferView { + init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array, _ b: borrowing Array) -> _consume(a) _borrow(b) Self { + self.ptr = ptr + return self + } } struct MutableBufferView : ~Escapable, ~Copyable { diff --git a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift index 2e681df4d900c..8dee7dcbdb1f3 100644 --- a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift @@ -4,6 +4,18 @@ public struct BufferView : ~Escapable { public init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } + public init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array) -> _borrow(a) Self { + self.ptr = ptr + return self + } + public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array) -> _consume(a) Self { + self.ptr = ptr + return self + } + public init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array, _ b: borrowing Array) -> _consume(a) _borrow(b) Self { + self.ptr = ptr + return self + } } public struct MutableBufferView : ~Escapable, ~Copyable { diff --git a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift index bb7e22428d1ea..fa0eb3e7e51e9 100644 --- a/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_implicit_lifetime_dependence.swift @@ -4,6 +4,9 @@ public struct BufferView : ~Escapable { public init(_ ptr: UnsafeRawBufferPointer) { self.ptr = ptr } + public init(_ otherBV: borrowing BufferView) { + self.ptr = otherBV.ptr + } } public struct MutableBufferView : ~Escapable, ~Copyable { diff --git a/test/Serialization/explicit_lifetime_dependence.swift b/test/Serialization/explicit_lifetime_dependence.swift index 086f62255d2e4..a32da352c6ea0 100644 --- a/test/Serialization/explicit_lifetime_dependence.swift +++ b/test/Serialization/explicit_lifetime_dependence.swift @@ -28,7 +28,22 @@ func testBasic() { } } +func testInitializers() { + let capacity = 4 + let a = Array(0.. _borrow(1) @owned BufferView // CHECK: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView // CHECK: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _borrow(1) @owned BufferView // CHECK: sil @$s32def_explicit_lifetime_dependence16deriveThisOrThatyAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> _borrow(1, 2) @owned BufferView + +// CHECK: sil @$s32def_explicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array, @thin BufferView.Type) -> _borrow(2) @owned BufferView + +// CHECK: sil @$s32def_explicit_lifetime_dependence10BufferViewVyACSW_SaySiGADhtcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Array, @guaranteed Array, @thin BufferView.Type) -> _inherit(2)_borrow(3) @owned BufferView diff --git a/test/Serialization/implicit_lifetime_dependence.swift b/test/Serialization/implicit_lifetime_dependence.swift index eb9aac1eea579..3a9a3765f199c 100644 --- a/test/Serialization/implicit_lifetime_dependence.swift +++ b/test/Serialization/implicit_lifetime_dependence.swift @@ -28,7 +28,26 @@ func testBasic() { } } +func testInitializers() { + let capacity = 4 + let a = Array(0.. _borrow(1) @owned BufferView // CHECK: sil @$s32def_implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView // CHECK: sil @$s32def_implicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _borrow(1) @owned BufferView +// CHECK: sil @$s32def_implicit_lifetime_dependence10BufferViewVyA2ChcfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> _borrow(1) @owned BufferView