Skip to content

Commit a8f3634

Browse files
authored
Merge pull request #33149 from hborla/function-builder-body-result-diags
[Function Builders] Teach diagnostics about function builder body result types...
2 parents 4181722 + b1c513d commit a8f3634

8 files changed

+57
-6
lines changed

lib/Sema/BuilderTransform.cpp

+6-3
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

+7
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

+1-2
Original file line numberDiff line numberDiff line change
@@ -7556,10 +7556,9 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
75567556

75577557
// If there is a function builder to apply, do so now.
75587558
if (functionBuilderType) {
7559-
auto *calleeLocator = getCalleeLocator(getConstraintLocator(locator));
75607559
if (auto result = matchFunctionBuilder(
75617560
closure, functionBuilderType, closureType->getResult(),
7562-
ConstraintKind::Conversion, calleeLocator, locator)) {
7561+
ConstraintKind::Conversion, locator)) {
75637562
return result->isSuccess();
75647563
}
75657564
}

lib/Sema/ConstraintLocator.cpp

+9
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,10 @@ bool ConstraintLocator::isForOptionalTry() const {
249250
return directlyAt<OptionalTryExpr>();
250251
}
251252

253+
bool ConstraintLocator::isForFunctionBuilderBodyResult() const {
254+
return isFirstElement<LocatorPathElt::FunctionBuilderBodyResult>();
255+
}
256+
252257
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
253258
// Check whether we have a path that terminates at a generic parameter.
254259
return isForGenericParameter() ?
@@ -347,6 +352,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
347352
out << "function result";
348353
break;
349354

355+
case FunctionBuilderBodyResult:
356+
out << "function builder body result";
357+
break;
358+
350359
case SequenceElementType:
351360
out << "sequence element type";
352361
break;

lib/Sema/ConstraintLocator.h

+11
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,24 @@ 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 *>())
387390
return isa<E>(expr) && getPath().empty();
388391
return false;
389392
}
390393

394+
/// Check whether the first element in the path of this locator (if any)
395+
/// is a given \c LocatorPathElt subclass.
396+
template <class T>
397+
bool isFirstElement() const {
398+
auto path = getPath();
399+
return !path.empty() && path.front().is<T>();
400+
}
401+
391402
/// Attempts to cast the first path element of the locator to a specific
392403
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
393404
/// the locator has no path elements.

lib/Sema/ConstraintLocatorPathElts.def

+3
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

+7-1
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,12 @@ template <typename T> bool isExpr(ASTNode node) {
486486
return isa<T>(E);
487487
}
488488

489+
template <typename T = Decl> T *getAsDecl(ASTNode node) {
490+
if (auto *E = node.dyn_cast<Decl *>())
491+
return dyn_cast_or_null<T>(E);
492+
return nullptr;
493+
}
494+
489495
SourceLoc getLoc(ASTNode node);
490496
SourceRange getSourceRange(ASTNode node);
491497

@@ -4383,7 +4389,7 @@ class ConstraintSystem {
43834389
Optional<TypeMatchResult> matchFunctionBuilder(
43844390
AnyFunctionRef fn, Type builderType, Type bodyResultType,
43854391
ConstraintKind bodyResultConstraintKind,
4386-
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator);
4392+
ConstraintLocatorBuilder locator);
43874393

43884394
private:
43894395
/// The kind of bindings that are permitted.

test/Constraints/function_builder_diags.swift

+13
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)