Skip to content

Commit cf71a10

Browse files
committed
[Refactoring] Move async refactorings into their own files
1 parent 3074dbe commit cf71a10

14 files changed

+4866
-4381
lines changed

lib/Refactoring/Async/AsyncConverter.cpp

Lines changed: 1886 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "AsyncRefactoring.h"
14+
15+
using namespace swift;
16+
using namespace swift::refactoring::asyncrefactorings;
17+
18+
/// Whether the given type is (or conforms to) the stdlib Error type
19+
static bool isErrorType(Type Ty, ModuleDecl *MD) {
20+
if (!Ty)
21+
return false;
22+
return !MD->conformsToProtocol(Ty, Ty->getASTContext().getErrorDecl())
23+
.isInvalid();
24+
}
25+
26+
AsyncHandlerDesc AsyncHandlerDesc::get(const ValueDecl *Handler,
27+
bool RequireName) {
28+
AsyncHandlerDesc HandlerDesc;
29+
if (auto Var = dyn_cast<VarDecl>(Handler)) {
30+
HandlerDesc.Handler = Var;
31+
} else if (auto Func = dyn_cast<AbstractFunctionDecl>(Handler)) {
32+
HandlerDesc.Handler = Func;
33+
} else {
34+
// The handler must be a variable or function
35+
return AsyncHandlerDesc();
36+
}
37+
38+
// Callback must have a completion-like name
39+
if (RequireName && !isCompletionHandlerParamName(HandlerDesc.getNameStr()))
40+
return AsyncHandlerDesc();
41+
42+
// Callback must be a function type and return void. Doesn't need to have
43+
// any parameters - may just be a "I'm done" callback
44+
auto *HandlerTy = HandlerDesc.getType()->getAs<AnyFunctionType>();
45+
if (!HandlerTy || !HandlerTy->getResult()->isVoid())
46+
return AsyncHandlerDesc();
47+
48+
// Find the type of result in the handler (eg. whether it's a Result<...>,
49+
// just parameters, or nothing).
50+
auto HandlerParams = HandlerTy->getParams();
51+
if (HandlerParams.size() == 1) {
52+
auto ParamTy =
53+
HandlerParams.back().getPlainType()->getAs<BoundGenericType>();
54+
if (ParamTy && ParamTy->isResult()) {
55+
auto GenericArgs = ParamTy->getGenericArgs();
56+
assert(GenericArgs.size() == 2 && "Result should have two params");
57+
HandlerDesc.Type = HandlerType::RESULT;
58+
HandlerDesc.HasError = !GenericArgs.back()->isUninhabited();
59+
}
60+
}
61+
62+
if (HandlerDesc.Type != HandlerType::RESULT) {
63+
// Only handle non-result parameters
64+
for (auto &Param : HandlerParams) {
65+
if (Param.getPlainType() && Param.getPlainType()->isResult())
66+
return AsyncHandlerDesc();
67+
}
68+
69+
HandlerDesc.Type = HandlerType::PARAMS;
70+
if (!HandlerParams.empty()) {
71+
auto LastParamTy = HandlerParams.back().getParameterType();
72+
HandlerDesc.HasError = isErrorType(LastParamTy->getOptionalObjectType(),
73+
Handler->getModuleContext());
74+
}
75+
}
76+
77+
return HandlerDesc;
78+
}
79+
80+
const ValueDecl *AsyncHandlerDesc::getHandler() const {
81+
if (!Handler) {
82+
return nullptr;
83+
}
84+
if (auto Var = Handler.dyn_cast<const VarDecl *>()) {
85+
return Var;
86+
} else if (auto Func = Handler.dyn_cast<const AbstractFunctionDecl *>()) {
87+
return Func;
88+
} else {
89+
llvm_unreachable("Unknown handler type");
90+
}
91+
}
92+
93+
StringRef AsyncHandlerDesc::getNameStr() const {
94+
if (auto Var = Handler.dyn_cast<const VarDecl *>()) {
95+
return Var->getNameStr();
96+
} else if (auto Func = Handler.dyn_cast<const AbstractFunctionDecl *>()) {
97+
return Func->getNameStr();
98+
} else {
99+
llvm_unreachable("Unknown handler type");
100+
}
101+
}
102+
103+
swift::Type AsyncHandlerDesc::getType() const {
104+
if (auto Var = Handler.dyn_cast<const VarDecl *>()) {
105+
return Var->getTypeInContext();
106+
} else if (auto Func = Handler.dyn_cast<const AbstractFunctionDecl *>()) {
107+
auto Type = Func->getInterfaceType();
108+
// Undo the self curry thunk if we are referencing a member function.
109+
if (Func->hasImplicitSelfDecl()) {
110+
assert(Type->is<AnyFunctionType>());
111+
Type = Type->getAs<AnyFunctionType>()->getResult();
112+
}
113+
return Type;
114+
} else {
115+
llvm_unreachable("Unknown handler type");
116+
}
117+
}
118+
119+
ArrayRef<AnyFunctionType::Param> AsyncHandlerDesc::params() const {
120+
auto Ty = getType()->getAs<AnyFunctionType>();
121+
assert(Ty && "Type must be a function type");
122+
return Ty->getParams();
123+
}
124+
125+
ArrayRef<AnyFunctionType::Param> AsyncHandlerDesc::getSuccessParams() const {
126+
if (HasError && Type == HandlerType::PARAMS)
127+
return params().drop_back();
128+
return params();
129+
}
130+
131+
llvm::Optional<AnyFunctionType::Param> AsyncHandlerDesc::getErrorParam() const {
132+
if (HasError && Type == HandlerType::PARAMS)
133+
return params().back();
134+
return llvm::None;
135+
}
136+
137+
llvm::Optional<swift::Type> AsyncHandlerDesc::getErrorType() const {
138+
if (HasError) {
139+
switch (Type) {
140+
case HandlerType::INVALID:
141+
return llvm::None;
142+
case HandlerType::PARAMS:
143+
// The last parameter of the completion handler is the error param
144+
return params().back().getPlainType()->lookThroughSingleOptionalType();
145+
case HandlerType::RESULT:
146+
assert(
147+
params().size() == 1 &&
148+
"Result handler should have the Result type as the only parameter");
149+
auto ResultType =
150+
params().back().getPlainType()->getAs<BoundGenericType>();
151+
auto GenericArgs = ResultType->getGenericArgs();
152+
assert(GenericArgs.size() == 2 && "Result should have two params");
153+
// The second (last) generic parameter of the Result type is the error
154+
// type.
155+
return GenericArgs.back();
156+
}
157+
} else {
158+
return llvm::None;
159+
}
160+
}
161+
162+
CallExpr *AsyncHandlerDesc::getAsHandlerCall(ASTNode Node) const {
163+
if (!isValid())
164+
return nullptr;
165+
166+
if (auto E = Node.dyn_cast<Expr *>()) {
167+
if (auto *CE = dyn_cast<CallExpr>(E->getSemanticsProvidingExpr())) {
168+
if (CE->getFn()->getReferencedDecl().getDecl() == getHandler()) {
169+
return CE;
170+
}
171+
}
172+
}
173+
return nullptr;
174+
}
175+
176+
bool AsyncHandlerDesc::isAmbiguousCallToParamHandler(const CallExpr *CE) const {
177+
if (!HasError || Type != HandlerType::PARAMS) {
178+
// Only param handlers with an error can pass both an error AND a result.
179+
return false;
180+
}
181+
auto Args = CE->getArgs()->getArgExprs();
182+
if (!isa<NilLiteralExpr>(Args.back())) {
183+
// We've got an error parameter. If any of the success params is not nil,
184+
// the call is ambiguous.
185+
for (auto &Arg : Args.drop_back()) {
186+
if (!isa<NilLiteralExpr>(Arg)) {
187+
return true;
188+
}
189+
}
190+
}
191+
return false;
192+
}
193+
194+
HandlerResult
195+
AsyncHandlerDesc::extractResultArgs(const CallExpr *CE,
196+
bool ReturnErrorArgsIfAmbiguous) const {
197+
auto *ArgList = CE->getArgs();
198+
SmallVector<Argument, 2> Scratch(ArgList->begin(), ArgList->end());
199+
auto Args = llvm::makeArrayRef(Scratch);
200+
201+
if (Type == HandlerType::PARAMS) {
202+
bool IsErrorResult;
203+
if (isAmbiguousCallToParamHandler(CE)) {
204+
IsErrorResult = ReturnErrorArgsIfAmbiguous;
205+
} else {
206+
// If there's an error parameter and the user isn't passing nil to it,
207+
// assume this is the error path.
208+
IsErrorResult = (HasError && !isa<NilLiteralExpr>(Args.back().getExpr()));
209+
}
210+
if (IsErrorResult)
211+
return HandlerResult(Args.back(), true);
212+
213+
// We can drop the args altogether if they're just Void.
214+
if (willAsyncReturnVoid())
215+
return HandlerResult();
216+
217+
return HandlerResult(HasError ? Args.drop_back() : Args);
218+
} else if (Type == HandlerType::RESULT) {
219+
if (Args.size() != 1)
220+
return HandlerResult(Args);
221+
222+
auto *ResultCE = dyn_cast<CallExpr>(Args[0].getExpr());
223+
if (!ResultCE)
224+
return HandlerResult(Args);
225+
226+
auto *DSC = dyn_cast<DotSyntaxCallExpr>(ResultCE->getFn());
227+
if (!DSC)
228+
return HandlerResult(Args);
229+
230+
auto *D =
231+
dyn_cast<EnumElementDecl>(DSC->getFn()->getReferencedDecl().getDecl());
232+
if (!D)
233+
return HandlerResult(Args);
234+
235+
auto ResultArgList = ResultCE->getArgs();
236+
auto isFailure = D->getNameStr() == StringRef("failure");
237+
238+
// We can drop the arg altogether if it's just Void.
239+
if (!isFailure && willAsyncReturnVoid())
240+
return HandlerResult();
241+
242+
// Otherwise the arg gets the .success() or .failure() call dropped.
243+
return HandlerResult(ResultArgList->get(0), isFailure);
244+
}
245+
246+
llvm_unreachable("Unhandled result type");
247+
}
248+
249+
swift::Type
250+
AsyncHandlerDesc::getSuccessParamAsyncReturnType(swift::Type Ty) const {
251+
switch (Type) {
252+
case HandlerType::PARAMS: {
253+
// If there's an Error parameter in the handler, the success branch can
254+
// be unwrapped.
255+
if (HasError)
256+
Ty = Ty->lookThroughSingleOptionalType();
257+
258+
return Ty;
259+
}
260+
case HandlerType::RESULT: {
261+
// Result<T, U> maps to T.
262+
return Ty->castTo<BoundGenericType>()->getGenericArgs()[0];
263+
}
264+
case HandlerType::INVALID:
265+
llvm_unreachable("Invalid handler type");
266+
}
267+
}
268+
269+
Identifier AsyncHandlerDesc::getAsyncReturnTypeLabel(size_t Index) const {
270+
assert(Index < getSuccessParams().size());
271+
if (getSuccessParams().size() <= 1) {
272+
// There can't be any labels if the async function doesn't return a tuple.
273+
return Identifier();
274+
} else {
275+
return getSuccessParams()[Index].getInternalLabel();
276+
}
277+
}
278+
279+
ArrayRef<LabeledReturnType> AsyncHandlerDesc::getAsyncReturnTypes(
280+
SmallVectorImpl<LabeledReturnType> &Scratch) const {
281+
for (size_t I = 0; I < getSuccessParams().size(); ++I) {
282+
auto Ty = getSuccessParams()[I].getParameterType();
283+
Scratch.emplace_back(getAsyncReturnTypeLabel(I),
284+
getSuccessParamAsyncReturnType(Ty));
285+
}
286+
return Scratch;
287+
}
288+
289+
bool AsyncHandlerDesc::willAsyncReturnVoid() const {
290+
// If all of the success params will be converted to Void return types,
291+
// this will be a Void async function.
292+
return llvm::all_of(getSuccessParams(), [&](auto &param) {
293+
auto Ty = param.getParameterType();
294+
return getSuccessParamAsyncReturnType(Ty)->isVoid();
295+
});
296+
}

0 commit comments

Comments
 (0)