Skip to content

[5.3][Function Builders] Teach diagnostics about function builder body result types... #33174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/Sema/BuilderTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1583,8 +1583,12 @@ ConstraintSystem::matchFunctionBuilder(
// If builder is applied to the closure expression then
// `closure body` to `closure result` matching should
// use special locator.
if (auto *closure = fn.getAbstractClosureExpr())
if (auto *closure = fn.getAbstractClosureExpr()) {
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
} else {
locator = getConstraintLocator(locator.getAnchor(),
ConstraintLocator::FunctionBuilderBodyResult);
}

// Bind the body result type to the type of the transformed expression.
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ Type FailureDiagnostic::restoreGenericParameters(
});
}

SourceLoc RequirementFailure::getLoc() const {
if (getLocator()->isForFunctionBuilderBodyResult())
return getConstraintSystem().DC->getAsDecl()->getLoc();

return FailureDiagnostic::getLoc();
}

Type RequirementFailure::getOwnerType() const {
auto anchor = getRawAnchor();

Expand Down Expand Up @@ -250,6 +257,14 @@ ValueDecl *RequirementFailure::getDeclRef() const {
return type->getAnyGeneric();
};

// If the locator is for a function builder body result type, the requirement
// came from the function's return type.
if (getLocator()->isForFunctionBuilderBodyResult()) {
auto *func = dyn_cast<FuncDecl>(getConstraintSystem().DC->getAsDecl());
assert(getSolution().functionBuilderTransformed.count(func));
return getAffectedDeclFromType(func->getResultInterfaceType());
}

if (isFromContextualType())
return getAffectedDeclFromType(getContextualType(getRawAnchor()));

Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ class RequirementFailure : public FailureDiagnostic {
Apply = dyn_cast<ApplyExpr>(parentExpr);
}

SourceLoc getLoc() const override;

unsigned getRequirementIndex() const {
auto reqElt =
getLocator()->castLastElementTo<LocatorPathElt::AnyRequirement>();
Expand Down
9 changes: 9 additions & 0 deletions lib/Sema/ConstraintLocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
case ConstraintLocator::ClosureResult:
case ConstraintLocator::ClosureBody:
case ConstraintLocator::ConstructorMember:
case ConstraintLocator::FunctionBuilderBodyResult:
case ConstraintLocator::InstanceType:
case ConstraintLocator::AutoclosureResult:
case ConstraintLocator::OptionalPayload:
Expand Down Expand Up @@ -247,6 +248,10 @@ bool ConstraintLocator::isForOptionalTry() const {
return directlyAt<OptionalTryExpr>();
}

bool ConstraintLocator::isForFunctionBuilderBodyResult() const {
return isFirstElement<LocatorPathElt::FunctionBuilderBodyResult>();
}

GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
// Check whether we have a path that terminates at a generic parameter.
return isForGenericParameter() ?
Expand Down Expand Up @@ -345,6 +350,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
out << "function result";
break;

case FunctionBuilderBodyResult:
out << "function builder body result";
break;

case SequenceElementType:
out << "sequence element type";
break;
Expand Down
11 changes: 11 additions & 0 deletions lib/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,23 @@ class ConstraintLocator : public llvm::FoldingSetNode {
/// Determine whether this locator points to the `try?` expression.
bool isForOptionalTry() const;

/// Determine whether this locator is for a function builder body result type.
bool isForFunctionBuilderBodyResult() const;

/// Determine whether this locator points directly to a given expression.
template <class E> bool directlyAt() const {
auto *anchor = getAnchor();
return anchor && isa<E>(anchor) && getPath().empty();
}

/// Check whether the first element in the path of this locator (if any)
/// is a given \c LocatorPathElt subclass.
template <class T>
bool isFirstElement() const {
auto path = getPath();
return !path.empty() && path.front().is<T>();
}

/// Attempts to cast the first path element of the locator to a specific
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
/// the locator has no path elements.
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/ConstraintLocatorPathElts.def
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ SIMPLE_LOCATOR_PATH_ELT(FunctionArgument)
/// The result type of a function.
SIMPLE_LOCATOR_PATH_ELT(FunctionResult)

/// The result type of a function builder body.
SIMPLE_LOCATOR_PATH_ELT(FunctionBuilderBodyResult)

/// A generic argument.
/// FIXME: Add support for named generic arguments?
CUSTOM_LOCATOR_PATH_ELT(GenericArgument)
Expand Down
13 changes: 13 additions & 0 deletions test/Constraints/function_builder_diags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -572,3 +572,16 @@ wrapperifyInfer(true) { x in // expected-error{{unable to infer type of a closur
intValue + x
}

struct DoesNotConform {}

struct MyView {
@TupleBuilder var value: some P { // expected-error {{return type of property 'value' requires that 'DoesNotConform' conform to 'P'}}
// expected-note@-1 {{opaque return type declared here}}
DoesNotConform()
}

@TupleBuilder func test() -> some P { // expected-error {{return type of instance method 'test()' requires that 'DoesNotConform' conform to 'P'}}
// expected-note@-1 {{opaque return type declared here}}
DoesNotConform()
}
}