Skip to content

Commit 7faf378

Browse files
committed
[Function Builders] Teach diagnostics about function builder body
result types in order to properly diagnose requirement failures on a builder-transformed type.
1 parent ab06af8 commit 7faf378

File tree

7 files changed

+51
-1
lines changed

7 files changed

+51
-1
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,8 +1583,12 @@ ConstraintSystem::matchFunctionBuilder(
15831583
// If builder is applied to the closure expression then
15841584
// `closure body` to `closure result` matching should
15851585
// use special locator.
1586-
if (auto *closure = fn.getAbstractClosureExpr())
1586+
if (auto *closure = fn.getAbstractClosureExpr()) {
15871587
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
1588+
} else {
1589+
locator = getConstraintLocator(locator.getAnchor(),
1590+
ConstraintLocator::FunctionBuilderBodyResult);
1591+
}
15881592

15891593
// Bind the body result type to the type of the transformed expression.
15901594
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,

lib/Sema/CSDiagnostics.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ Type FailureDiagnostic::restoreGenericParameters(
176176
});
177177
}
178178

179+
SourceLoc RequirementFailure::getLoc() const {
180+
if (getLocator()->isForFunctionBuilderBodyResult())
181+
return getConstraintSystem().DC->getAsDecl()->getLoc();
182+
183+
return FailureDiagnostic::getLoc();
184+
}
185+
179186
Type RequirementFailure::getOwnerType() const {
180187
auto anchor = getRawAnchor();
181188

@@ -250,6 +257,14 @@ ValueDecl *RequirementFailure::getDeclRef() const {
250257
return type->getAnyGeneric();
251258
};
252259

260+
// If the locator is for a function builder body result type, the requirement
261+
// came from the function's return type.
262+
if (getLocator()->isForFunctionBuilderBodyResult()) {
263+
auto *func = dyn_cast<FuncDecl>(getConstraintSystem().DC->getAsDecl());
264+
assert(getSolution().functionBuilderTransformed.count(func));
265+
return getAffectedDeclFromType(func->getResultInterfaceType());
266+
}
267+
253268
if (isFromContextualType())
254269
return getAffectedDeclFromType(getContextualType(getRawAnchor()));
255270

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ class RequirementFailure : public FailureDiagnostic {
269269
Apply = dyn_cast<ApplyExpr>(parentExpr);
270270
}
271271

272+
SourceLoc getLoc() const override;
273+
272274
unsigned getRequirementIndex() const {
273275
auto reqElt =
274276
getLocator()->castLastElementTo<LocatorPathElt::AnyRequirement>();

lib/Sema/ConstraintLocator.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
9090
case ConstraintLocator::ClosureResult:
9191
case ConstraintLocator::ClosureBody:
9292
case ConstraintLocator::ConstructorMember:
93+
case ConstraintLocator::FunctionBuilderBodyResult:
9394
case ConstraintLocator::InstanceType:
9495
case ConstraintLocator::AutoclosureResult:
9596
case ConstraintLocator::OptionalPayload:
@@ -247,6 +248,11 @@ bool ConstraintLocator::isForOptionalTry() const {
247248
return directlyAt<OptionalTryExpr>();
248249
}
249250

251+
bool ConstraintLocator::isForFunctionBuilderBodyResult() const {
252+
auto elt = getFirstElementAs<LocatorPathElt::FunctionBuilderBodyResult>();
253+
return elt.hasValue();
254+
}
255+
250256
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
251257
// Check whether we have a path that terminates at a generic parameter.
252258
return isForGenericParameter() ?
@@ -345,6 +351,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
345351
out << "function result";
346352
break;
347353

354+
case FunctionBuilderBodyResult:
355+
out << "function builder body result";
356+
break;
357+
348358
case SequenceElementType:
349359
out << "sequence element type";
350360
break;

lib/Sema/ConstraintLocator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ class ConstraintLocator : public llvm::FoldingSetNode {
375375
/// Determine whether this locator points to the `try?` expression.
376376
bool isForOptionalTry() const;
377377

378+
/// Determine whether this locator is for a function builder body result type.
379+
bool isForFunctionBuilderBodyResult() const;
380+
378381
/// Determine whether this locator points directly to a given expression.
379382
template <class E> bool directlyAt() const {
380383
auto *anchor = getAnchor();

lib/Sema/ConstraintLocatorPathElts.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ SIMPLE_LOCATOR_PATH_ELT(FunctionArgument)
7575
/// The result type of a function.
7676
SIMPLE_LOCATOR_PATH_ELT(FunctionResult)
7777

78+
/// The result type of a function builder body.
79+
SIMPLE_LOCATOR_PATH_ELT(FunctionBuilderBodyResult)
80+
7881
/// A generic argument.
7982
/// FIXME: Add support for named generic arguments?
8083
CUSTOM_LOCATOR_PATH_ELT(GenericArgument)

test/Constraints/function_builder_diags.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,16 @@ wrapperifyInfer(true) { x in // expected-error{{unable to infer type of a closur
572572
intValue + x
573573
}
574574

575+
struct DoesNotConform {}
576+
577+
struct MyView {
578+
@TupleBuilder var value: some P { // expected-error {{return type of property 'value' requires that 'DoesNotConform' conform to 'P'}}
579+
// expected-note@-1 {{opaque return type declared here}}
580+
DoesNotConform()
581+
}
582+
583+
@TupleBuilder func test() -> some P { // expected-error {{return type of instance method 'test()' requires that 'DoesNotConform' conform to 'P'}}
584+
// expected-note@-1 {{opaque return type declared here}}
585+
DoesNotConform()
586+
}
587+
}

0 commit comments

Comments
 (0)