mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #33149 from hborla/function-builder-body-result-diags
[Function Builders] Teach diagnostics about function builder body result types...
This commit is contained in:
@@ -1529,7 +1529,6 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
|
||||
|
||||
if (auto result = cs.matchFunctionBuilder(
|
||||
func, builderType, resultContextType, resultConstraintKind,
|
||||
cs.getConstraintLocator(func->getBody()),
|
||||
cs.getConstraintLocator(func->getBody()))) {
|
||||
if (result->isFailure())
|
||||
return nullptr;
|
||||
@@ -1583,7 +1582,7 @@ Optional<ConstraintSystem::TypeMatchResult>
|
||||
ConstraintSystem::matchFunctionBuilder(
|
||||
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
||||
ConstraintKind bodyResultConstraintKind,
|
||||
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator) {
|
||||
ConstraintLocatorBuilder locator) {
|
||||
auto builder = builderType->getAnyNominal();
|
||||
assert(builder && "Bad function builder type");
|
||||
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
|
||||
@@ -1657,8 +1656,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(fn.getAbstractFunctionDecl(),
|
||||
ConstraintLocator::FunctionBuilderBodyResult);
|
||||
}
|
||||
|
||||
// Bind the body result type to the type of the transformed expression.
|
||||
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,
|
||||
|
||||
@@ -240,6 +240,13 @@ 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 = getAsDecl<FuncDecl>(getAnchor());
|
||||
return getAffectedDeclFromType(func->getResultInterfaceType());
|
||||
}
|
||||
|
||||
if (isFromContextualType())
|
||||
return getAffectedDeclFromType(getContextualType(getRawAnchor()));
|
||||
|
||||
|
||||
@@ -7556,10 +7556,9 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
|
||||
|
||||
// If there is a function builder to apply, do so now.
|
||||
if (functionBuilderType) {
|
||||
auto *calleeLocator = getCalleeLocator(getConstraintLocator(locator));
|
||||
if (auto result = matchFunctionBuilder(
|
||||
closure, functionBuilderType, closureType->getResult(),
|
||||
ConstraintKind::Conversion, calleeLocator, locator)) {
|
||||
ConstraintKind::Conversion, locator)) {
|
||||
return result->isSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,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:
|
||||
@@ -249,6 +250,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() ?
|
||||
@@ -347,6 +352,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;
|
||||
|
||||
@@ -381,6 +381,9 @@ public:
|
||||
/// 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 <typename E> bool directlyAt() const {
|
||||
if (auto *expr = getAnchor().dyn_cast<Expr *>())
|
||||
@@ -388,6 +391,14 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -486,6 +486,12 @@ template <typename T> bool isExpr(ASTNode node) {
|
||||
return isa<T>(E);
|
||||
}
|
||||
|
||||
template <typename T = Decl> T *getAsDecl(ASTNode node) {
|
||||
if (auto *E = node.dyn_cast<Decl *>())
|
||||
return dyn_cast_or_null<T>(E);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SourceLoc getLoc(ASTNode node);
|
||||
SourceRange getSourceRange(ASTNode node);
|
||||
|
||||
@@ -4383,7 +4389,7 @@ public:
|
||||
Optional<TypeMatchResult> matchFunctionBuilder(
|
||||
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
||||
ConstraintKind bodyResultConstraintKind,
|
||||
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator);
|
||||
ConstraintLocatorBuilder locator);
|
||||
|
||||
private:
|
||||
/// The kind of bindings that are permitted.
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user