Skip to content

[6.2][AST] ASTPrinter: Improvements to specifier and attribute printing #80892

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
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
15 changes: 15 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6911,6 +6911,9 @@ class ParamDecl : public VarDecl {

/// Whether or not this parameter is 'sending'.
IsSending = 1 << 4,

/// Whether or not this parameter is isolated to a caller.
IsCallerIsolated = 1 << 5,
};

/// The type repr and 3 bits used for flags.
Expand Down Expand Up @@ -7199,6 +7202,18 @@ class ParamDecl : public VarDecl {
removeFlag(Flag::IsSending);
}

/// Whether or not this parameter is marked with 'nonisolated(nonsending)'.
bool isCallerIsolated() const {
return getOptions().contains(Flag::IsCallerIsolated);
}

void setCallerIsolated(bool value = true) {
if (value)
addFlag(Flag::IsCallerIsolated);
else
removeFlag(Flag::IsCallerIsolated);
}

/// Whether or not this parameter is marked with '@_addressable'.
bool isAddressable() const {
return getOptions().contains(Flag::IsAddressable);
Expand Down
56 changes: 40 additions & 16 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3847,13 +3847,13 @@ static void printParameterFlags(ASTPrinter &printer,
const PrintOptions &options,
const ParamDecl *param,
ParameterTypeFlags flags,
bool escaping) {
if (!options.excludeAttrKind(TypeAttrKind::Autoclosure) &&
flags.isAutoClosure())
printer.printAttrName("@autoclosure ");
if (!options.excludeAttrKind(TypeAttrKind::NoDerivative) &&
flags.isNoDerivative())
printer.printAttrName("@noDerivative ");
bool escaping,
bool isIsolatedToCaller = false) {
// Always print `nonisolated(nonsending)` specifier on a parameter
// first, to avoid any issues with ordering.
if (isIsolatedToCaller) {
printer.printKeyword("nonisolated(nonsending)", options, " ");
}

switch (flags.getOwnershipSpecifier()) {
case ParamSpecifier::Default:
Expand Down Expand Up @@ -3882,7 +3882,7 @@ static void printParameterFlags(ASTPrinter &printer,

if (flags.isSending()) {
if (!options.SuppressSendingArgsAndResults) {
printer.printAttrName("sending ");
printer.printKeyword("sending", options, " ");
} else if (flags.getOwnershipSpecifier() ==
ParamSpecifier::ImplicitlyCopyableConsuming) {
// Ok. We are suppressing sending. If our ownership specifier was
Expand All @@ -3900,14 +3900,24 @@ static void printParameterFlags(ASTPrinter &printer,
printer.printKeyword("isolated", options, " ");
}

if (!options.excludeAttrKind(TypeAttrKind::Escaping) && escaping)
printer.printKeyword("@escaping", options, " ");

if (flags.isCompileTimeLiteral())
printer.printKeyword("_const", options, " ");


if (!options.excludeAttrKind(TypeAttrKind::Autoclosure) &&
flags.isAutoClosure())
printer.printAttrName("@autoclosure ");
if (!options.excludeAttrKind(TypeAttrKind::NoDerivative) &&
flags.isNoDerivative())
printer.printAttrName("@noDerivative ");

// `inout` implies `@escaping`
if (flags.getOwnershipSpecifier() != ParamSpecifier::InOut) {
if (!options.excludeAttrKind(TypeAttrKind::Escaping) && escaping)
printer.printAttrName("@escaping ");
}

if (flags.isConstValue())
printer.printKeyword("@const", options, " ");
printer.printAttrName("@const ");
}

void PrintAST::visitVarDecl(VarDecl *decl) {
Expand Down Expand Up @@ -4016,11 +4026,24 @@ void PrintAST::printOneParameter(const ParamDecl *param,

printArgName();

auto interfaceTy = param->getInterfaceType();

// If type of this parameter is isolated to a caller, let's
// strip the isolation from the type to avoid printing it as
// part of the function type because that would break ordering
// between specifiers and attributes.
if (param->isCallerIsolated()) {
if (auto *funcTy = dyn_cast<AnyFunctionType>(interfaceTy.getPointer())) {
interfaceTy =
funcTy->withIsolation(FunctionTypeIsolation::forNonIsolated());
}
}

TypeLoc TheTypeLoc;
if (auto *repr = param->getTypeRepr()) {
TheTypeLoc = TypeLoc(repr, param->getInterfaceType());
TheTypeLoc = TypeLoc(repr, interfaceTy);
} else {
TheTypeLoc = TypeLoc::withoutLoc(param->getInterfaceType());
TheTypeLoc = TypeLoc::withoutLoc(interfaceTy);
}

{
Expand All @@ -4032,7 +4055,8 @@ void PrintAST::printOneParameter(const ParamDecl *param,
!willUseTypeReprPrinting(TheTypeLoc, CurrentType, Options)) {
auto type = TheTypeLoc.getType();
printParameterFlags(Printer, Options, param, paramFlags,
isEscaping(type));
isEscaping(type),
param->isCallerIsolated());
}

printTypeLocForImplicitlyUnwrappedOptional(
Expand Down
9 changes: 9 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9010,6 +9010,12 @@ void ParamDecl::setTypeRepr(TypeRepr *repr) {
continue;
}

if (auto *callerIsolated =
dyn_cast<CallerIsolatedTypeRepr>(unwrappedType)) {
setCallerIsolated(true);
unwrappedType = callerIsolated->getBase();
}

break;
}
}
Expand Down Expand Up @@ -11095,6 +11101,9 @@ AccessorDecl *AccessorDecl::createParsed(
if (subscriptParam->isSending())
param->setSending();

if (subscriptParam->isCallerIsolated())
param->setCallerIsolated();

newParams.push_back(param);
}

Expand Down
3 changes: 3 additions & 0 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4117,6 +4117,7 @@ class DeclDeserializer {
bool isIsolated;
bool isCompileTimeLiteral, isConstValue;
bool isSending;
bool isCallerIsolated;
uint8_t rawDefaultArg;
TypeID defaultExprType;
uint8_t rawDefaultArgIsolation;
Expand All @@ -4129,6 +4130,7 @@ class DeclDeserializer {
isCompileTimeLiteral,
isConstValue,
isSending,
isCallerIsolated,
rawDefaultArg,
defaultExprType,
rawDefaultArgIsolation,
Expand Down Expand Up @@ -4174,6 +4176,7 @@ class DeclDeserializer {
param->setCompileTimeLiteral(isCompileTimeLiteral);
param->setConstValue(isConstValue);
param->setSending(isSending);
param->setCallerIsolated(isCallerIsolated);

// Decode the default argument kind.
// FIXME: Default argument expression, if available.
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 937; // remove @execution attr
const uint16_t SWIFTMODULE_VERSION_MINOR = 938; // `isCallerIsolated` parameter flag

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -1733,6 +1733,7 @@ namespace decls_block {
BCFixed<1>, // isCompileTimeLiteral?
BCFixed<1>, // isConst?
BCFixed<1>, // isSending?
BCFixed<1>, // isCallerIsolated?
DefaultArgumentField, // default argument kind
TypeIDField, // default argument type
ActorIsolationField, // default argument isolation
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4750,6 +4750,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
param->isCompileTimeLiteral(),
param->isConstVal(),
param->isSending(),
param->isCallerIsolated(),
getRawStableDefaultArgumentKind(argKind),
S.addTypeRef(defaultExprType),
getRawStableActorIsolationKind(isolation.getKind()),
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ func rdar17170728() {
}

let _ = [i, j, k].reduce(0 as Int?) { // expected-error {{missing argument label 'into:' in call}}
// expected-error@-1 {{cannot convert value of type 'Int?' to expected argument type '(inout @escaping (Bool, Bool) -> Bool?, Int?) throws -> ()'}}
// expected-error@-1 {{cannot convert value of type 'Int?' to expected argument type '(inout (Bool, Bool) -> Bool?, Int?) throws -> ()'}}
$0 && $1 ? $0 + $1 : ($0 ? $0 : ($1 ? $1 : nil))
// expected-error@-1 {{binary operator '+' cannot be applied to two 'Bool' operands}}
}
Expand Down
9 changes: 9 additions & 0 deletions test/ModuleInterface/attrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,12 @@ public func testExecutionConcurrent() async {}
nonisolated(nonsending)
public func testExecutionCaller() async {}
// CHECK: nonisolated(nonsending) public func testExecutionCaller() async

public struct TestPlacementOfAttrsAndSpecifiers {
// CHECK: public func test1<T>(_: sending @autoclosure () -> T)
public func test1<T>(_: sending @autoclosure () -> T) {}
// CHECK: public func test2<T>(_: borrowing @autoclosure () -> T)
public func test2<T>(_: borrowing @autoclosure () -> T) {}
// CHECK: public func test3<T>(_: inout () async -> T)
public func test3<T>(_: inout () async -> T) {}
}
12 changes: 12 additions & 0 deletions test/ModuleInterface/execution_behavior_attrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@

// REQUIRES: concurrency

public struct TestWithAttrs {
// CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes
// CHECK-NEXT: public func test(_: nonisolated(nonsending) @escaping () async -> Swift.Void)
// CHECK-NEXT: #endif
public func test(_: nonisolated(nonsending) @escaping () async -> Void) {}

// CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes
// CHECK-NEXT: public func withInOut(fn: nonisolated(nonsending) inout () async -> Swift.Void)
// CHECK-NEXT: #endif
public func withInOut(fn: nonisolated(nonsending) inout () async -> Void) {}
}

public struct Test {
// CHECK: #if compiler(>=5.3) && $AsyncExecutionBehaviorAttributes
// CHECK-NEXT: nonisolated(nonsending) public init() async
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ public func foo<S>(f: @escaping () -> (), ext int: Int = 2, s: S) where S: Seque
// CHECK-NEXT: "spelling": ": "
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "kind": "keyword",
// CHECK-NEXT: "spelling": "@escaping"
// CHECK-NEXT: "kind": "attribute",
// CHECK-NEXT: "spelling": "@escaping "
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "kind": "text",
// CHECK-NEXT: "spelling": " () -> (), "
// CHECK-NEXT: "spelling": "() -> (), "
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "kind": "externalParam",
Expand Down