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:
Holly Borla
2020-07-29 09:04:14 -07:00
committed by GitHub
8 changed files with 57 additions and 6 deletions

View File

@@ -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,

View File

@@ -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()));

View File

@@ -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();
} }
} }

View File

@@ -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;

View File

@@ -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.

View File

@@ -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)

View File

@@ -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.

View File

@@ -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()
}
}