Skip to content

[AST] Introduce Argument::implicitInOut #60438

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

Merged
merged 3 commits into from
Aug 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/AST/ArgumentList.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class Argument final {
return Argument(SourceLoc(), Identifier(), expr);
}

/// Make an implicit unlabeled 'inout' argument.
static Argument implicitInOut(ASTContext &ctx, Expr *expr);

SourceLoc getStartLoc() const { return getSourceRange().Start; }
SourceLoc getEndLoc() const { return getSourceRange().End; }
SourceRange getSourceRange() const;
Expand All @@ -65,6 +68,11 @@ class Argument final {
/// The argument label written in the call.
Identifier getLabel() const { return Label; }

/// Whether the argument has a non-empty label. Note that this returns `false`
/// for an explicitly specified empty label e.g `_: {}` for a trailing
/// closure.
bool hasLabel() const { return !Label.empty(); }

/// Set a new argument label.
///
/// Note this is marked \c & to prevent its use on an rvalue Argument vended
Expand Down
7 changes: 6 additions & 1 deletion include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4736,8 +4736,13 @@ class DotSyntaxCallExpr : public SelfApplyExpr {
}

public:
/// Create a new method reference to \p fnExpr on the base value \p baseArg.
///
/// If this is for a 'mutating' method, \p baseArg should be created using
/// \c Argument::implicitInOut. Otherwise, \p Argument::unlabeled should be
/// used. \p baseArg must not be labeled.
static DotSyntaxCallExpr *create(ASTContext &ctx, Expr *fnExpr,
SourceLoc dotLoc, Expr *baseExpr,
SourceLoc dotLoc, Argument baseArg,
Type ty = Type());

SourceLoc getDotLoc() const { return DotLoc; }
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/ArgumentList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ SourceRange Argument::getSourceRange() const {
return SourceRange(labelLoc, exprEndLoc);
}

Argument Argument::implicitInOut(ASTContext &ctx, Expr *expr) {
assert(!isa<InOutExpr>(expr) && "Cannot nest InOutExpr");

// Eventually this will set an 'inout' bit on Argument, but for now,
// synthesize in the InOutExpr.
Type objectTy;
if (auto subTy = expr->getType())
objectTy = subTy->castTo<LValueType>()->getObjectType();

return Argument::unlabeled(
new (ctx) InOutExpr(SourceLoc(), expr, objectTy, /*isImplicit*/ true));
}

bool Argument::isInOut() const {
return ArgExpr->isSemanticallyInOutExpr();
}
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1571,9 +1571,10 @@ BinaryExpr *BinaryExpr::create(ASTContext &ctx, Expr *lhs, Expr *fn, Expr *rhs,
}

DotSyntaxCallExpr *DotSyntaxCallExpr::create(ASTContext &ctx, Expr *fnExpr,
SourceLoc dotLoc, Expr *baseExpr,
SourceLoc dotLoc, Argument baseArg,
Type ty) {
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseExpr});
assert(!baseArg.hasLabel());
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {baseArg.getExpr()});
return new (ctx) DotSyntaxCallExpr(fnExpr, dotLoc, argList, ty);
}

Expand Down
147 changes: 68 additions & 79 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4444,29 +4444,23 @@ DeclRefExpr *getInteropStaticCastDeclRefExpr(ASTContext &ctx,
// %2 = __swift_interopStaticCast<UnsafeMutablePointer<Base>?>(%1)
// %3 = %2!
// return %3.pointee
MemberRefExpr *getInOutSelfInteropStaticCast(FuncDecl *funcDecl,
NominalTypeDecl *baseStruct,
NominalTypeDecl *derivedStruct) {
MemberRefExpr *getSelfInteropStaticCast(FuncDecl *funcDecl,
NominalTypeDecl *baseStruct,
NominalTypeDecl *derivedStruct) {
auto &ctx = funcDecl->getASTContext();

auto inoutSelf = [&ctx](FuncDecl *funcDecl) {
auto inoutSelfDecl = funcDecl->getImplicitSelfDecl();
auto mutableSelf = [&ctx](FuncDecl *funcDecl) {
auto selfDecl = funcDecl->getImplicitSelfDecl();

auto inoutSelfRef =
new (ctx) DeclRefExpr(inoutSelfDecl, DeclNameLoc(), /*implicit*/ true);
inoutSelfRef->setType(LValueType::get(inoutSelfDecl->getInterfaceType()));
auto selfRef =
new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true);
selfRef->setType(LValueType::get(selfDecl->getInterfaceType()));

auto inoutSelf = new (ctx) InOutExpr(
SourceLoc(), inoutSelfRef,
funcDecl->mapTypeIntoContext(inoutSelfDecl->getValueInterfaceType()),
/*implicit*/ true);
inoutSelf->setType(InOutType::get(inoutSelfDecl->getInterfaceType()));

return inoutSelf;
return selfRef;
}(funcDecl);

auto createCallToBuiltin = [&](Identifier name, ArrayRef<Type> substTypes,
Expr *arg) {
Argument arg) {
auto builtinFn = cast<FuncDecl>(getBuiltinValueDecl(ctx, name));
auto substMap =
SubstitutionMap::get(builtinFn->getGenericSignature(), substTypes,
Expand All @@ -4479,22 +4473,23 @@ MemberRefExpr *getInOutSelfInteropStaticCast(FuncDecl *funcDecl,
if (auto genericFnType = dyn_cast<GenericFunctionType>(fnType.getPointer()))
fnType = genericFnType->substGenericArgs(substMap);
builtinFnRefExpr->setType(fnType);
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {arg});
auto *argList = ArgumentList::createImplicit(ctx, {arg});
auto callExpr = CallExpr::create(ctx, builtinFnRefExpr, argList, /*implicit*/ true);
callExpr->setThrows(false);
return callExpr;
};

auto rawSelfPointer =
createCallToBuiltin(ctx.getIdentifier("addressof"),
{derivedStruct->getSelfInterfaceType()}, inoutSelf);
auto rawSelfPointer = createCallToBuiltin(
ctx.getIdentifier("addressof"), {derivedStruct->getSelfInterfaceType()},
Argument::implicitInOut(ctx, mutableSelf));
rawSelfPointer->setType(ctx.TheRawPointerType);

auto derivedPtrType = derivedStruct->getSelfInterfaceType()->wrapInPointer(
PTK_UnsafeMutablePointer);
auto selfPointer = createCallToBuiltin(
ctx.getIdentifier("reinterpretCast"),
{ctx.TheRawPointerType, derivedPtrType}, rawSelfPointer);
auto selfPointer =
createCallToBuiltin(ctx.getIdentifier("reinterpretCast"),
{ctx.TheRawPointerType, derivedPtrType},
Argument::unlabeled(rawSelfPointer));
selfPointer->setType(derivedPtrType);

auto staticCastRefExpr = getInteropStaticCastDeclRefExpr(
Expand Down Expand Up @@ -4554,14 +4549,11 @@ synthesizeBaseClassMethodBody(AbstractFunctionDecl *afd, void *context) {
forwardingParams.push_back(paramRefExpr);
}

Expr *casted = nullptr;
if (funcDecl->isMutating()) {
auto pointeeMemberRefExpr =
getInOutSelfInteropStaticCast(funcDecl, baseStruct, derivedStruct);
casted = new (ctx) InOutExpr(SourceLoc(), pointeeMemberRefExpr, baseType,
/*implicit*/ true);
casted->setType(InOutType::get(baseType));
} else {
Argument casted = [&]() {
if (funcDecl->isMutating()) {
return Argument::implicitInOut(
ctx, getSelfInteropStaticCast(funcDecl, baseStruct, derivedStruct));
}
auto *selfDecl = funcDecl->getImplicitSelfDecl();
auto selfExpr = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(),
/*implicit*/ true);
Expand All @@ -4575,8 +4567,8 @@ synthesizeBaseClassMethodBody(AbstractFunctionDecl *afd, void *context) {
auto castedCall = CallExpr::createImplicit(ctx, staticCastRefExpr, argList);
castedCall->setType(baseType);
castedCall->setThrows(false);
casted = castedCall;
}
return Argument::unlabeled(castedCall);
}();

auto *baseMemberExpr =
new (ctx) DeclRefExpr(ConcreteDeclRef(baseMember), DeclNameLoc(),
Expand Down Expand Up @@ -4680,7 +4672,7 @@ synthesizeBaseClassFieldSetterBody(AbstractFunctionDecl *afd, void *context) {
cast<NominalTypeDecl>(setterDecl->getDeclContext()->getAsDecl());

auto *pointeePropertyRefExpr =
getInOutSelfInteropStaticCast(setterDecl, baseStruct, derivedStruct);
getSelfInteropStaticCast(setterDecl, baseStruct, derivedStruct);

Expr *storedRef = nullptr;
if (auto subscript = dyn_cast<SubscriptDecl>(baseClassVar)) {
Expand Down Expand Up @@ -5378,7 +5370,7 @@ static ValueDecl *rewriteIntegerTypes(SubstitutionMap subst, ValueDecl *oldDecl,
return newDecl;
}

static Expr *createSelfExpr(FuncDecl *fnDecl) {
static Argument createSelfArg(FuncDecl *fnDecl) {
ASTContext &ctx = fnDecl->getASTContext();

auto selfDecl = fnDecl->getImplicitSelfDecl();
Expand All @@ -5387,16 +5379,10 @@ static Expr *createSelfExpr(FuncDecl *fnDecl) {

if (!fnDecl->isMutating()) {
selfRefExpr->setType(selfDecl->getInterfaceType());
return selfRefExpr;
return Argument::unlabeled(selfRefExpr);
}
selfRefExpr->setType(LValueType::get(selfDecl->getInterfaceType()));

auto inoutSelfExpr = new (ctx) InOutExpr(
SourceLoc(), selfRefExpr,
fnDecl->mapTypeIntoContext(selfDecl->getValueInterfaceType()),
/*isImplicit*/ true);
inoutSelfExpr->setType(InOutType::get(selfDecl->getInterfaceType()));
return inoutSelfExpr;
return Argument::implicitInOut(ctx, selfRefExpr);
}

// Synthesize a thunk body for the function created in
Expand All @@ -5417,30 +5403,30 @@ synthesizeDependentTypeThunkParamForwarding(AbstractFunctionDecl *afd, void *con
paramIndex++;
continue;
}
auto paramTy = param->getType();
auto isInOut = param->isInOut();
auto specParamTy =
specializedFuncDecl->getParameters()->get(paramIndex)->getType();

Expr *paramRefExpr = new (ctx) DeclRefExpr(param, DeclNameLoc(),
/*Implicit=*/true);
paramRefExpr->setType(param->getType());

if (param->isInOut()) {
paramRefExpr->setType(LValueType::get(param->getType()));

paramRefExpr = new (ctx) InOutExpr(
SourceLoc(), paramRefExpr, param->getType(), /*isImplicit*/ true);
paramRefExpr->setType(InOutType::get(param->getType()));
}

auto specParamTy = specializedFuncDecl->getParameters()->get(paramIndex)->getType();
paramRefExpr->setType(isInOut ? LValueType::get(paramTy) : paramTy);

Expr *argExpr = nullptr;
if (specParamTy->isEqual(param->getType())) {
argExpr = paramRefExpr;
} else {
argExpr = ForcedCheckedCastExpr::createImplicit(ctx, paramRefExpr,
specParamTy);
}

forwardingParams.push_back(Argument(SourceLoc(), Identifier(), argExpr));
Argument arg = [&]() {
if (isInOut) {
assert(specParamTy->isEqual(paramTy));
return Argument::implicitInOut(ctx, paramRefExpr);
}
Expr *argExpr = nullptr;
if (specParamTy->isEqual(paramTy)) {
argExpr = paramRefExpr;
} else {
argExpr = ForcedCheckedCastExpr::createImplicit(ctx, paramRefExpr,
specParamTy);
}
return Argument::unlabeled(argExpr);
}();
forwardingParams.push_back(arg);
paramIndex++;
}

Expand All @@ -5449,8 +5435,9 @@ synthesizeDependentTypeThunkParamForwarding(AbstractFunctionDecl *afd, void *con
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());

if (specializedFuncDecl->isInstanceMember()) {
auto selfExpr = createSelfExpr(thunkDecl);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
auto selfArg = createSelfArg(thunkDecl);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef,
SourceLoc(), selfArg);
memberCall->setThrows(false);
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
specializedFuncDeclRef = memberCall;
Expand All @@ -5459,7 +5446,9 @@ synthesizeDependentTypeThunkParamForwarding(AbstractFunctionDecl *afd, void *con
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
auto *memberCall =
DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(),
Argument::unlabeled(selfTypeExpr));
memberCall->setThrows(false);
specializedFuncDeclRef = memberCall;
specializedFuncDeclRef->setType(resultType);
Expand Down Expand Up @@ -5559,28 +5548,26 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
if (isa<MetatypeType>(param->getType().getPointer())) {
continue;
}
auto paramTy = param->getType();
auto isInOut = param->isInOut();

Expr *paramRefExpr = new (ctx) DeclRefExpr(param, DeclNameLoc(),
/*Implicit=*/true);
paramRefExpr->setType(param->getType());

if (param->isInOut()) {
paramRefExpr->setType(LValueType::get(param->getType()));

paramRefExpr = new (ctx) InOutExpr(
SourceLoc(), paramRefExpr, param->getType(), /*isImplicit*/ true);
paramRefExpr->setType(InOutType::get(param->getType()));
}
paramRefExpr->setType(isInOut ? LValueType::get(paramTy) : paramTy);

forwardingParams.push_back(Argument(SourceLoc(), Identifier(), paramRefExpr));
auto arg = isInOut ? Argument::implicitInOut(ctx, paramRefExpr)
: Argument::unlabeled(paramRefExpr);
forwardingParams.push_back(arg);
}

Expr *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
DeclNameLoc(), true);
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());

if (specializedFuncDecl->isInstanceMember()) {
auto selfExpr = createSelfExpr(thunkDecl);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
auto selfArg = createSelfArg(thunkDecl);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef,
SourceLoc(), selfArg);
memberCall->setThrows(false);
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
specializedFuncDeclRef = memberCall;
Expand All @@ -5589,7 +5576,9 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
auto *memberCall =
DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(),
Argument::unlabeled(selfTypeExpr));
memberCall->setThrows(false);
specializedFuncDeclRef = memberCall;
specializedFuncDeclRef->setType(resultType);
Expand Down
5 changes: 3 additions & 2 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5457,8 +5457,9 @@ Decl *SwiftDeclConverter::importEnumCaseAlias(
/*implicit*/ true);
constantRef->setType(enumElt->getInterfaceType());

auto instantiate = DotSyntaxCallExpr::create(Impl.SwiftContext, constantRef,
SourceLoc(), typeRef);
auto instantiate =
DotSyntaxCallExpr::create(Impl.SwiftContext, constantRef, SourceLoc(),
Argument::unlabeled(typeRef));
instantiate->setType(importedEnumTy);
instantiate->setThrows(false);

Expand Down
Loading