Skip to content

Commit 9baca13

Browse files
committed
[Function Builders] Teach diagnostics about function builder body
result types in order to properly diagnose requirement failures that aren't anchored at an expression.
1 parent 5e7bafc commit 9baca13

File tree

8 files changed

+50
-6
lines changed

8 files changed

+50
-6
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,6 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
15291529

15301530
if (auto result = cs.matchFunctionBuilder(
15311531
func, builderType, resultContextType, resultConstraintKind,
1532-
cs.getConstraintLocator(func->getBody()),
15331532
cs.getConstraintLocator(func->getBody()))) {
15341533
if (result->isFailure())
15351534
return nullptr;
@@ -1583,7 +1582,7 @@ Optional<ConstraintSystem::TypeMatchResult>
15831582
ConstraintSystem::matchFunctionBuilder(
15841583
AnyFunctionRef fn, Type builderType, Type bodyResultType,
15851584
ConstraintKind bodyResultConstraintKind,
1586-
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator) {
1585+
ConstraintLocatorBuilder locator) {
15871586
auto builder = builderType->getAnyNominal();
15881587
assert(builder && "Bad function builder type");
15891588
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
@@ -1657,8 +1656,12 @@ ConstraintSystem::matchFunctionBuilder(
16571656
// If builder is applied to the closure expression then
16581657
// `closure body` to `closure result` matching should
16591658
// use special locator.
1660-
if (auto *closure = fn.getAbstractClosureExpr())
1659+
if (auto *closure = fn.getAbstractClosureExpr()) {
16611660
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
1661+
} else {
1662+
locator = getConstraintLocator(fn.getAbstractFunctionDecl(),
1663+
ConstraintLocator::FunctionBuilderBodyResult);
1664+
}
16621665

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

lib/Sema/CSDiagnostics.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ ValueDecl *RequirementFailure::getDeclRef() const {
240240
return type->getAnyGeneric();
241241
};
242242

243+
// If the locator is for a function builder body result type, the requirement
244+
// came from the function's return type.
245+
if (getLocator()->isForFunctionBuilderBodyResult()) {
246+
auto *func = getAsDecl<FuncDecl>(getAnchor());
247+
return getAffectedDeclFromType(func->getResultInterfaceType());
248+
}
249+
243250
if (isFromContextualType())
244251
return getAffectedDeclFromType(getContextualType(getRawAnchor()));
245252

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7443,10 +7443,9 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
74437443

74447444
// If there is a function builder to apply, do so now.
74457445
if (functionBuilderType) {
7446-
auto *calleeLocator = getCalleeLocator(getConstraintLocator(locator));
74477446
if (auto result = matchFunctionBuilder(
74487447
closure, functionBuilderType, closureType->getResult(),
7449-
ConstraintKind::Conversion, calleeLocator, locator)) {
7448+
ConstraintKind::Conversion, locator)) {
74507449
return result->isSuccess();
74517450
}
74527451
}

lib/Sema/ConstraintLocator.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
9191
case ConstraintLocator::ClosureResult:
9292
case ConstraintLocator::ClosureBody:
9393
case ConstraintLocator::ConstructorMember:
94+
case ConstraintLocator::FunctionBuilderBodyResult:
9495
case ConstraintLocator::InstanceType:
9596
case ConstraintLocator::AutoclosureResult:
9697
case ConstraintLocator::OptionalPayload:
@@ -249,6 +250,11 @@ bool ConstraintLocator::isForOptionalTry() const {
249250
return directlyAt<OptionalTryExpr>();
250251
}
251252

253+
bool ConstraintLocator::isForFunctionBuilderBodyResult() const {
254+
auto elt = getFirstElementAs<LocatorPathElt::FunctionBuilderBodyResult>();
255+
return elt.hasValue();
256+
}
257+
252258
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
253259
// Check whether we have a path that terminates at a generic parameter.
254260
return isForGenericParameter() ?
@@ -347,6 +353,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
347353
out << "function result";
348354
break;
349355

356+
case FunctionBuilderBodyResult:
357+
out << "function builder body result";
358+
break;
359+
350360
case SequenceElementType:
351361
out << "sequence element type";
352362
break;

lib/Sema/ConstraintLocator.h

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

384+
/// Determine whether this locator is for a function builder body result type.
385+
bool isForFunctionBuilderBodyResult() const;
386+
384387
/// Determine whether this locator points directly to a given expression.
385388
template <typename E> bool directlyAt() const {
386389
if (auto *expr = getAnchor().dyn_cast<Expr *>())

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)

lib/Sema/ConstraintSystem.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,12 @@ template <typename T> bool isExpr(ASTNode node) {
477477
return isa<T>(E);
478478
}
479479

480+
template <typename T = Decl> T *getAsDecl(ASTNode node) {
481+
if (auto *E = node.dyn_cast<Decl *>())
482+
return dyn_cast_or_null<T>(E);
483+
return nullptr;
484+
}
485+
480486
SourceLoc getLoc(ASTNode node);
481487
SourceRange getSourceRange(ASTNode node);
482488

@@ -4341,7 +4347,7 @@ class ConstraintSystem {
43414347
Optional<TypeMatchResult> matchFunctionBuilder(
43424348
AnyFunctionRef fn, Type builderType, Type bodyResultType,
43434349
ConstraintKind bodyResultConstraintKind,
4344-
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator);
4350+
ConstraintLocatorBuilder locator);
43454351

43464352
private:
43474353
/// The kind of bindings that are permitted.

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)