-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Function builders] Infer function builder from a protocol requirement. #32005
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
[Function builders] Infer function builder from a protocol requirement. #32005
Conversation
Allow a protocol requirement for a function or property to declare a function builder. A witness to such a protocol requirement will infer that function builder when all of the following are two: * The witness does not explicitly adopt a function builder * The witness is declared within the same context that conforms to the protocol requirement (e.g., same extension or primary type declaration) * The witness's body does not contain a "return" statement (since those disable the function builder transform).
@swift-ci please smoke test |
@swift-ci please test source compatibility |
Now that this request will be triggered more often, due to inference of function builders, cache the result.
Eliminates both circular references and unwanted dependencies.
@swift-ci please smoke test |
@swift-ci please test source compatibility |
@swift-ci smoke test macOS |
Debug source compatibility failure in |
I think it's reasonable to have that as a diagnostic path---if there's are explicit |
To make it easier for diagnostics would it be possible to make return of this function reacher e.g. either type or a failure kind - return in the body, used on getter etc.? |
When we do that diagnostic, we'll want to go through |
I asking because instead of assuming that ‘return`s could be a problem we can get an indication from this method what exactly went from and act on that when trying to call the method again for diagnostics... |
If we need more than what I'm suggesting, we can extend the return type. We shouldn't do it proactively because (1) we want to minimize dependencies when not in recovery mode, and (2) we might not need the extra information until we have that diagnostic. |
I see that there is a new diagnostic about adding explicit |
Happy to look at a general improvement for function builders diagnostics to try to address this failure case (an explicit |
Sure! It would be great to address that sooner than later though because not having a good diagnostic there is very confusing. |
@swift-ci please smoke test |
1 similar comment
@swift-ci please smoke test |
@swift-ci smoke test Linux |
// Fast path: most declarations (especially parameters, which is where | ||
// this is hottest) do not have any custom attributes at all. | ||
if (!getAttrs().hasAttribute<CustomAttr>()) return nullptr; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Losing these hot paths seems abstractly unfortunate. I never profiled them, of course, so who knows, but this does get called for every parameter of every direct call, at least when the argument is a closure. Have you measured compile time/memory impact?
You're only inferring function builders for method bodies, I think, which should let us more selectively weaken the fast-path check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request-evaluator needs to be fast enough so that we don't need to scatter hot paths like this everywhere, because they suppress incremental dependency generation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like the statement "[it just] needs to be fast enough" is doing a lot of work for something that inherently looks up and permanently allocates a hash-table entry.
@@ -5038,10 +5038,11 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { | |||
} | |||
} | |||
|
|||
SmallVector<ProtocolConformance *, 2> | |||
std::vector<ProtocolConformance *> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this use the typedef if you're relying on equivalence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it should. Good call.
diag::function_builder_infer_ambig, lookupDecl->getName(), | ||
functionBuilderType, otherFunctionBuilderType); | ||
decl->diagnose(diag::function_builder_infer_add_return) | ||
.fixItInsert(funcDecl->getBodySourceRange().End, "return <#expr#>\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this can't have official source-compatibility impact given that we haven't standardized the feature.
It seems unfortunate that this gets diagnosed here eagerly. I would not expect calling getFunctionBuilderType()
to be an authoritative statement by the caller that it wants to try to use the function-builder transform on a method body, and I don't think it's reasonable to diagnose in other cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You would prefer that we return the (ambiguous) set of possible function builders rather than diagnose here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be a more reasonable design, yeah. Or if you really need this behavior, consider renaming the function in a way that makes it clearer that it's not "logically pure" on otherwise-valid code — it triggers query-specific diagnostics if there's no unambiguous function builder type.
I'll do some cleanup after this PR for stuff that still needs it. |
Allow a protocol requirement for a function or property to declare
a function builder. A witness to such a protocol requirement will
infer that function builder when all of the following are two:
protocol requirement (e.g., same extension or primary type declaration)
disable the function builder transform).