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(
|
if (auto result = cs.matchFunctionBuilder(
|
||||||
func, builderType, resultContextType, resultConstraintKind,
|
func, builderType, resultContextType, resultConstraintKind,
|
||||||
cs.getConstraintLocator(func->getBody()),
|
|
||||||
cs.getConstraintLocator(func->getBody()))) {
|
cs.getConstraintLocator(func->getBody()))) {
|
||||||
if (result->isFailure())
|
if (result->isFailure())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1583,7 +1582,7 @@ Optional<ConstraintSystem::TypeMatchResult>
|
|||||||
ConstraintSystem::matchFunctionBuilder(
|
ConstraintSystem::matchFunctionBuilder(
|
||||||
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
||||||
ConstraintKind bodyResultConstraintKind,
|
ConstraintKind bodyResultConstraintKind,
|
||||||
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator) {
|
ConstraintLocatorBuilder locator) {
|
||||||
auto builder = builderType->getAnyNominal();
|
auto builder = builderType->getAnyNominal();
|
||||||
assert(builder && "Bad function builder type");
|
assert(builder && "Bad function builder type");
|
||||||
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
|
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
|
||||||
@@ -1657,8 +1656,12 @@ ConstraintSystem::matchFunctionBuilder(
|
|||||||
// If builder is applied to the closure expression then
|
// If builder is applied to the closure expression then
|
||||||
// `closure body` to `closure result` matching should
|
// `closure body` to `closure result` matching should
|
||||||
// use special locator.
|
// use special locator.
|
||||||
if (auto *closure = fn.getAbstractClosureExpr())
|
if (auto *closure = fn.getAbstractClosureExpr()) {
|
||||||
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
|
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
|
||||||
|
} else {
|
||||||
|
locator = getConstraintLocator(fn.getAbstractFunctionDecl(),
|
||||||
|
ConstraintLocator::FunctionBuilderBodyResult);
|
||||||
|
}
|
||||||
|
|
||||||
// Bind the body result type to the type of the transformed expression.
|
// Bind the body result type to the type of the transformed expression.
|
||||||
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,
|
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,
|
||||||
|
|||||||
@@ -240,6 +240,13 @@ ValueDecl *RequirementFailure::getDeclRef() const {
|
|||||||
return type->getAnyGeneric();
|
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())
|
if (isFromContextualType())
|
||||||
return getAffectedDeclFromType(getContextualType(getRawAnchor()));
|
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 there is a function builder to apply, do so now.
|
||||||
if (functionBuilderType) {
|
if (functionBuilderType) {
|
||||||
auto *calleeLocator = getCalleeLocator(getConstraintLocator(locator));
|
|
||||||
if (auto result = matchFunctionBuilder(
|
if (auto result = matchFunctionBuilder(
|
||||||
closure, functionBuilderType, closureType->getResult(),
|
closure, functionBuilderType, closureType->getResult(),
|
||||||
ConstraintKind::Conversion, calleeLocator, locator)) {
|
ConstraintKind::Conversion, locator)) {
|
||||||
return result->isSuccess();
|
return result->isSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
|
|||||||
case ConstraintLocator::ClosureResult:
|
case ConstraintLocator::ClosureResult:
|
||||||
case ConstraintLocator::ClosureBody:
|
case ConstraintLocator::ClosureBody:
|
||||||
case ConstraintLocator::ConstructorMember:
|
case ConstraintLocator::ConstructorMember:
|
||||||
|
case ConstraintLocator::FunctionBuilderBodyResult:
|
||||||
case ConstraintLocator::InstanceType:
|
case ConstraintLocator::InstanceType:
|
||||||
case ConstraintLocator::AutoclosureResult:
|
case ConstraintLocator::AutoclosureResult:
|
||||||
case ConstraintLocator::OptionalPayload:
|
case ConstraintLocator::OptionalPayload:
|
||||||
@@ -249,6 +250,10 @@ bool ConstraintLocator::isForOptionalTry() const {
|
|||||||
return directlyAt<OptionalTryExpr>();
|
return directlyAt<OptionalTryExpr>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ConstraintLocator::isForFunctionBuilderBodyResult() const {
|
||||||
|
return isFirstElement<LocatorPathElt::FunctionBuilderBodyResult>();
|
||||||
|
}
|
||||||
|
|
||||||
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
|
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
|
||||||
// Check whether we have a path that terminates at a generic parameter.
|
// Check whether we have a path that terminates at a generic parameter.
|
||||||
return isForGenericParameter() ?
|
return isForGenericParameter() ?
|
||||||
@@ -347,6 +352,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
|
|||||||
out << "function result";
|
out << "function result";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FunctionBuilderBodyResult:
|
||||||
|
out << "function builder body result";
|
||||||
|
break;
|
||||||
|
|
||||||
case SequenceElementType:
|
case SequenceElementType:
|
||||||
out << "sequence element type";
|
out << "sequence element type";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -381,6 +381,9 @@ public:
|
|||||||
/// Determine whether this locator points to the `try?` expression.
|
/// Determine whether this locator points to the `try?` expression.
|
||||||
bool isForOptionalTry() const;
|
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.
|
/// Determine whether this locator points directly to a given expression.
|
||||||
template <typename E> bool directlyAt() const {
|
template <typename E> bool directlyAt() const {
|
||||||
if (auto *expr = getAnchor().dyn_cast<Expr *>())
|
if (auto *expr = getAnchor().dyn_cast<Expr *>())
|
||||||
@@ -388,6 +391,14 @@ public:
|
|||||||
return false;
|
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
|
/// Attempts to cast the first path element of the locator to a specific
|
||||||
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
|
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
|
||||||
/// the locator has no path elements.
|
/// the locator has no path elements.
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ SIMPLE_LOCATOR_PATH_ELT(FunctionArgument)
|
|||||||
/// The result type of a function.
|
/// The result type of a function.
|
||||||
SIMPLE_LOCATOR_PATH_ELT(FunctionResult)
|
SIMPLE_LOCATOR_PATH_ELT(FunctionResult)
|
||||||
|
|
||||||
|
/// The result type of a function builder body.
|
||||||
|
SIMPLE_LOCATOR_PATH_ELT(FunctionBuilderBodyResult)
|
||||||
|
|
||||||
/// A generic argument.
|
/// A generic argument.
|
||||||
/// FIXME: Add support for named generic arguments?
|
/// FIXME: Add support for named generic arguments?
|
||||||
CUSTOM_LOCATOR_PATH_ELT(GenericArgument)
|
CUSTOM_LOCATOR_PATH_ELT(GenericArgument)
|
||||||
|
|||||||
@@ -486,6 +486,12 @@ template <typename T> bool isExpr(ASTNode node) {
|
|||||||
return isa<T>(E);
|
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);
|
SourceLoc getLoc(ASTNode node);
|
||||||
SourceRange getSourceRange(ASTNode node);
|
SourceRange getSourceRange(ASTNode node);
|
||||||
|
|
||||||
@@ -4383,7 +4389,7 @@ public:
|
|||||||
Optional<TypeMatchResult> matchFunctionBuilder(
|
Optional<TypeMatchResult> matchFunctionBuilder(
|
||||||
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
AnyFunctionRef fn, Type builderType, Type bodyResultType,
|
||||||
ConstraintKind bodyResultConstraintKind,
|
ConstraintKind bodyResultConstraintKind,
|
||||||
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator);
|
ConstraintLocatorBuilder locator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The kind of bindings that are permitted.
|
/// 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
|
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