Skip to content

Commit 15a34a5

Browse files
committed
[sending] Look through the sending type repr when printing the type of a function result using the type repr fallback path.
When we print types in the AST printer if for some reason we cannot find the appropriate type to print or if the user explicitly asks, we fall back and use a type repr instead. This behavior causes a problem due to the implementation of sending results using a sending type repr to communicate that the relevant function has a sending result, but we actually do not use the sending type repr from that point on. So as a result, in this fallback case, we put in one too many sending on the result. rdar://135594964
1 parent 9546d69 commit 15a34a5

File tree

4 files changed

+105
-4
lines changed

4 files changed

+105
-4
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4127,8 +4127,35 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
41274127
}
41284128

41294129
PrintWithOpaqueResultTypeKeywordRAII x(Options);
4130-
printTypeLocForImplicitlyUnwrappedOptional(
4131-
ResultTyLoc, decl->isImplicitlyUnwrappedOptional());
4130+
4131+
// Check if we would go down the type repr path... in such a case, see if
4132+
// we can find a type repr and if that type has a sending type repr. In
4133+
// such a case, look through the sending type repr since we handle it here
4134+
// ourselves.
4135+
bool usedTypeReprPrinting = false;
4136+
{
4137+
llvm::SaveAndRestore<PrintOptions> printOptions(Options);
4138+
Options.PrintOptionalAsImplicitlyUnwrapped =
4139+
decl->isImplicitlyUnwrappedOptional();
4140+
if (willUseTypeReprPrinting(ResultTyLoc, CurrentType, Options)) {
4141+
if (auto repr = ResultTyLoc.getTypeRepr()) {
4142+
// If we are printing a sending result... and we found that we have
4143+
// to use type repr printing, look through sending type repr.
4144+
// Sending was already applied in our caller.
4145+
if (auto *sendingRepr = dyn_cast<SendingTypeRepr>(repr)) {
4146+
repr = sendingRepr->getBase();
4147+
}
4148+
repr->print(Printer, Options);
4149+
usedTypeReprPrinting = true;
4150+
}
4151+
}
4152+
}
4153+
4154+
// If we printed using type repr printing, do not print again.
4155+
if (!usedTypeReprPrinting) {
4156+
printTypeLocForImplicitlyUnwrappedOptional(
4157+
ResultTyLoc, decl->isImplicitlyUnwrappedOptional());
4158+
}
41324159
Printer.printStructurePost(PrintStructureKind::FunctionReturnType);
41334160
}
41344161
printDeclGenericRequirements(decl);

lib/AST/TypeRepr.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,21 @@ void FunctionTypeRepr::printImpl(ASTPrinter &Printer,
435435
}
436436
Printer << " -> ";
437437
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
438-
printTypeRepr(RetTy, Printer, Opts);
438+
439+
// Check if we are supposed to suppress sending results. If so, look through
440+
// the ret ty if it is a Sending TypeRepr.
441+
//
442+
// DISCUSSION: The reason why we do this is that Sending TypeRepr is used for
443+
// arguments and results... and we need the arguments case when we suppress to
444+
// print __owned. So this lets us handle both cases.
445+
auto ActualRetTy = RetTy;
446+
if (Opts.SuppressSendingArgsAndResults) {
447+
if (auto *x = dyn_cast<SendingTypeRepr>(RetTy)) {
448+
ActualRetTy = x->getBase();
449+
}
450+
}
451+
printTypeRepr(ActualRetTy, Printer, Opts);
452+
439453
Printer.printStructurePost(PrintStructureKind::FunctionReturnType);
440454
Printer.printStructurePost(PrintStructureKind::FunctionType);
441455
}
@@ -853,7 +867,13 @@ void SpecifierTypeRepr::printImpl(ASTPrinter &Printer,
853867
Printer.printKeyword("isolated", Opts, " ");
854868
break;
855869
case TypeReprKind::Sending:
856-
Printer.printKeyword("sending", Opts, " ");
870+
// This handles the argument case. The result case is handled in
871+
// FunctionTypeRepr.
872+
if (!Opts.SuppressSendingArgsAndResults) {
873+
Printer.printKeyword("sending", Opts, " ");
874+
} else {
875+
Printer.printKeyword("__owned", Opts, " ");
876+
}
857877
break;
858878
case TypeReprKind::CompileTimeConst:
859879
Printer.printKeyword("_const", Opts, " ");
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
3+
// CHECK-NEXT: public func test() -> sending NonSendableKlass
4+
// CHECK-NEXT: #else
5+
// CHECK-NEXT: public func test() -> NonSendableKlass
6+
// CHECK-NEXT: #endif
7+
8+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
9+
// CHECK-NEXT: public func test2(_ x: sending NonSendableKlass)
10+
// CHECK-NEXT: #else
11+
// CHECK-NEXT: public func test2(_ x: __owned NonSendableKlass)
12+
// CHECK-NEXT: #endif
13+
14+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
15+
// CHECK-NEXT: @_Concurrency.MainActor public var closure: () -> sending NonSendableKlass
16+
// CHECK-NEXT: #else
17+
// CHECK-NEXT: @_Concurrency.MainActor public var closure: () -> NonSendableKlass
18+
// CHECK-NEXT: #endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -enable-library-evolution -parse-as-library -emit-module-interface-path - -module-name MyFile -swift-version 6 | %FileCheck %s
3+
// RUN: %target-swift-frontend %s -typecheck -enable-library-evolution -parse-as-library -emit-module-interface-path - -module-name MyFile -swift-version 6 -module-interface-preserve-types-as-written | %FileCheck %S/Inputs/sending_interfacefile_printing_repr_filecheck
4+
5+
// The force printing type reprs option is only available in asserts builds.
6+
// REQUIRES: asserts
7+
8+
// This test validates that when we produce interface files we produce the
9+
// correct interface file for sending when printing normally or with type reprs
10+
// enabled.
11+
12+
public class NonSendableKlass {}
13+
14+
// The two possible outputs are MyFile.NonSendableKlass and NonSendableKlass.
15+
//
16+
// So we just check for an optional M
17+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
18+
// CHECK-NEXT: public func test() -> sending MyFile.NonSendableKlass
19+
// CHECK-NEXT: #else
20+
// CHECK-NEXT: public func test() -> MyFile.NonSendableKlass
21+
// CHECK-NEXT: #endif
22+
public func test() -> sending NonSendableKlass { NonSendableKlass() }
23+
24+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
25+
// CHECK-NEXT: public func test2(_ x: sending MyFile.NonSendableKlass)
26+
// CHECK-NEXT: #else
27+
// CHECK-NEXT: public func test2(_ x: __owned MyFile.NonSendableKlass)
28+
// CHECK-NEXT: #endif
29+
public func test2(_ x: sending NonSendableKlass) {}
30+
31+
// CHECK: #if compiler(>=5.3) && $SendingArgsAndResults
32+
// CHECK-NEXT: @_Concurrency.MainActor public var closure: () -> sending MyFile.NonSendableKlass
33+
// CHECK-NEXT: #else
34+
// CHECK-NEXT: @_Concurrency.MainActor public var closure: () -> MyFile.NonSendableKlass
35+
// CHECK-NEXT: #endif
36+
@MainActor public var closure: () -> sending NonSendableKlass = { NonSendableKlass() }

0 commit comments

Comments
 (0)