Skip to content

Commit 5aa0330

Browse files
authored
Merge pull request #25926 from rjmccall/function-builder-func-opaque-result
Support opaque result types when applying a function builder to a func
2 parents 5b7f21f + faa3e34 commit 5aa0330

File tree

5 files changed

+52
-12
lines changed

5 files changed

+52
-12
lines changed

include/swift/AST/Decl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2873,7 +2873,13 @@ class OpaqueTypeDecl : public GenericTypeDecl {
28732873
assert(!NamingDecl && "already have naming decl");
28742874
NamingDecl = D;
28752875
}
2876-
2876+
2877+
/// Is this opaque type the opaque return type of the given function?
2878+
///
2879+
/// This is more complex than just checking `getNamingDecl` because the
2880+
/// function could also be the getter of a storage declaration.
2881+
bool isOpaqueReturnTypeOfFunction(const AbstractFunctionDecl *func) const;
2882+
28772883
GenericSignature *getOpaqueInterfaceGenericSignature() const {
28782884
return OpaqueInterfaceGenericSignature;
28792885
}

lib/AST/Decl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6575,6 +6575,21 @@ OpaqueTypeDecl::OpaqueTypeDecl(ValueDecl *NamingDecl,
65756575
setImplicit();
65766576
}
65776577

6578+
bool OpaqueTypeDecl::isOpaqueReturnTypeOfFunction(
6579+
const AbstractFunctionDecl *func) const {
6580+
// Either the function is declared with its own opaque return type...
6581+
if (getNamingDecl() == func)
6582+
return true;
6583+
6584+
// ...or the function is a getter for a property or subscript with an
6585+
// opaque return type.
6586+
if (auto accessor = dyn_cast<AccessorDecl>(func)) {
6587+
return accessor->isGetter() && getNamingDecl() == accessor->getStorage();
6588+
}
6589+
6590+
return false;
6591+
}
6592+
65786593
Identifier OpaqueTypeDecl::getOpaqueReturnTypeIdentifier() const {
65796594
assert(getNamingDecl() && "not an opaque return type");
65806595
if (!OpaqueReturnTypeIdentifier.empty())

lib/Sema/BuilderTransform.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,10 +490,16 @@ bool TypeChecker::typeCheckFunctionBuilderFuncBody(FuncDecl *FD,
490490
if (!returnType || returnType->hasError())
491491
return true;
492492

493+
TypeCheckExprOptions options = {};
494+
if (auto opaque = returnType->getAs<OpaqueTypeArchetypeType>()) {
495+
if (opaque->getDecl()->isOpaqueReturnTypeOfFunction(FD))
496+
options |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
497+
}
498+
493499
// Type-check the single result expression.
494500
Type returnExprType = typeCheckExpression(returnExpr, FD,
495501
TypeLoc::withoutLoc(returnType),
496-
CTP_ReturnStmt);
502+
CTP_ReturnStmt, options);
497503
if (!returnExprType)
498504
return true;
499505
assert(returnExprType->isEqual(returnType));

lib/Sema/TypeCheckStmt.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -484,16 +484,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
484484
auto funcDecl = TheFunc->getAbstractFunctionDecl();
485485
if (!funcDecl)
486486
return false;
487-
// Either the function is declared with its own opaque return type...
488-
if (opaque->getNamingDecl() == funcDecl)
489-
return true;
490-
// ...or the function is a getter for a property or subscript with an
491-
// opaque return type.
492-
if (auto accessor = dyn_cast<AccessorDecl>(funcDecl)) {
493-
return accessor->isGetter()
494-
&& opaque->getNamingDecl() == accessor->getStorage();
495-
}
496-
return false;
487+
488+
return opaque->isOpaqueReturnTypeOfFunction(funcDecl);
497489
};
498490

499491
if (auto opaque = ResultTy->getAs<OpaqueTypeArchetypeType>()) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -disable-availability-checking -typecheck -verify %s
2+
3+
protocol Taggable {}
4+
extension String: Taggable {}
5+
6+
@_functionBuilder
7+
struct TaggableBuilder {
8+
static func buildBlock(_ params: Taggable...) -> String {
9+
return "Your tags weren't worth keeping anyway"
10+
}
11+
}
12+
13+
@TaggableBuilder
14+
func testFuncWithOpaqueResult() -> some Taggable {
15+
"This is an amazing tag"
16+
}
17+
18+
@TaggableBuilder
19+
var testGetterWithOpaqueResult: some Taggable {
20+
"This is also an amazing tag"
21+
}

0 commit comments

Comments
 (0)