Skip to content

Commit 16f97d7

Browse files
committed
Sema: Result builder inference from protocol req should look at getter, not storage
1 parent c996573 commit 16f97d7

File tree

2 files changed

+29
-18
lines changed

2 files changed

+29
-18
lines changed

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,8 @@ AttachedResultBuilderRequest::evaluate(Evaluator &evaluator,
200200

201201
/// Attempt to infer the result builder type for a declaration.
202202
static Type inferResultBuilderType(ValueDecl *decl) {
203-
auto dc = decl->getDeclContext();
204-
if (isa<ProtocolDecl>(dc))
205-
return Type();
206-
207203
auto funcDecl = dyn_cast<FuncDecl>(decl);
208-
if (!funcDecl || !funcDecl->hasBody() ||
209-
!decl->getDeclContext()->getParentSourceFile())
204+
if (!funcDecl)
210205
return Type();
211206

212207
// For a getter, always favor the result builder type of its storage
@@ -220,16 +215,20 @@ static Type inferResultBuilderType(ValueDecl *decl) {
220215
}
221216
}
222217

218+
auto *dc = decl->getDeclContext();
219+
if (isa<ProtocolDecl>(dc)) {
220+
return Type();
221+
}
222+
223223
// FIXME: We could infer from a dynamically replaced decl in non-type contexts too.
224224
if (!dc->isTypeContext()) {
225225
return Type();
226226
}
227227

228-
// Check whether there are any return statements in the function's body.
229-
// If there are, the result builder transform will be disabled,
230-
// so don't infer a result builder.
231-
if (!TypeChecker::findReturnStatements(funcDecl).empty())
228+
if (!funcDecl->hasBody() || !dc->getParentSourceFile() ||
229+
!TypeChecker::findReturnStatements(funcDecl).empty()) {
232230
return Type();
231+
}
233232

234233
// Find all of the potentially inferred result builder types.
235234
struct Match {
@@ -305,7 +304,22 @@ static Type inferResultBuilderType(ValueDecl *decl) {
305304
if (!requirement)
306305
continue;
307306

308-
Type resultBuilderType = requirement->getResultBuilderType();
307+
Type resultBuilderType;
308+
{
309+
auto *inferenceSource = requirement;
310+
311+
// If the given declaration is a witness to a storage declaration
312+
// requirement, then we are inferring for a getter and, hence, should
313+
// infer from the getter requirement.
314+
if (auto *storage = dyn_cast<AbstractStorageDecl>(requirement)) {
315+
if (auto *getter = storage->getAccessor(AccessorKind::Get)) {
316+
inferenceSource = getter;
317+
}
318+
}
319+
320+
resultBuilderType = inferenceSource->getResultBuilderType();
321+
}
322+
309323
if (!resultBuilderType)
310324
continue;
311325

test/Constraints/result_builder_infer.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,13 @@ protocol Tupled3 {
151151
struct TupleMe3: Tupled3 {
152152
var condition: Bool
153153

154-
// FIXME: Not inferred from getter requirement
155-
// expected-error@+1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
156154
var tuple: some Any {
157-
"hello" // expected-warning{{literal is unused}}
155+
"hello"
158156
if condition {
159-
"nested" // expected-warning{{literal is unused}}
157+
"nested"
160158
}
161-
3.14159 // expected-warning{{literal is unused}}
162-
"world" // expected-warning{{literal is unused}}
163-
// expected-note@-1 {{did you mean to return the last expression?}}
159+
3.14159
160+
"world"
164161
}
165162
}
166163

0 commit comments

Comments
 (0)