Skip to content

Commit 8c123e8

Browse files
committed
[Concurrency] Hard-code support for importing @mainactor.
Our name lookup rules for the resolution of custom attributes don't allow for them to find MainActor within the _Concurrency library. Therefore, hardcode @mainactor to map to _Concurrency.MainActor. While here, make sure we drop concurrency-specific attributes that show up in Clang attributes when we aren't in concurrency mode.
1 parent cd0380b commit 8c123e8

File tree

10 files changed

+107
-14
lines changed

10 files changed

+107
-14
lines changed

include/swift/Parse/Parser.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,10 +1038,12 @@ class Parser {
10381038
SourceLoc Loc);
10391039

10401040
/// Parse a specific attribute.
1041-
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc);
1041+
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
1042+
bool isFromClangAttribute = false);
10421043

10431044
bool parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
1044-
DeclAttrKind DK);
1045+
DeclAttrKind DK,
1046+
bool isFromClangAttribute = false);
10451047

10461048
/// Parse a version tuple of the form x[.y[.z]]. Returns true if there was
10471049
/// an error parsing.

lib/AST/UnqualifiedLookup.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,12 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() {
273273
"performUnqualifedLookup",
274274
DC->getParentSourceFile());
275275

276-
if (Loc.isValid()) {
276+
if (Loc.isValid() && DC->getParentSourceFile()) {
277277
// Operator lookup is always global, for the time being.
278278
if (!Name.isOperator())
279279
lookInASTScopes();
280280
} else {
281-
assert(DC->isModuleScopeContext() &&
281+
assert((DC->isModuleScopeContext() || !DC->getParentSourceFile()) &&
282282
"Unqualified lookup without a source location must start from "
283283
"a module-scope context");
284284

lib/ClangImporter/ImportDecl.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7738,6 +7738,35 @@ static bool isObjCMethodLikelyAsyncHandler(
77387738
return false;
77397739
}
77407740

7741+
Type ClangImporter::Implementation::getMainActorType() {
7742+
if (MainActorType)
7743+
return *MainActorType;
7744+
7745+
auto finish = [&](Type type) -> Type {
7746+
MainActorType = type;
7747+
return type;
7748+
};
7749+
7750+
if (!SwiftContext.LangOpts.EnableExperimentalConcurrency) {
7751+
return finish(Type());
7752+
}
7753+
7754+
auto module = SwiftContext.getLoadedModule(SwiftContext.Id_Concurrency);
7755+
if (!module)
7756+
return finish(Type());
7757+
7758+
SmallVector<ValueDecl *, 1> decls;
7759+
module->lookupValue(
7760+
SwiftContext.getIdentifier("MainActor"),
7761+
NLKind::QualifiedLookup, decls);
7762+
for (auto decl : decls) {
7763+
if (auto typeDecl = dyn_cast<TypeDecl>(decl))
7764+
return finish(typeDecl->getDeclaredInterfaceType());
7765+
}
7766+
7767+
return finish(Type());
7768+
}
7769+
77417770
unsigned ClangImporter::Implementation::getClangSwiftAttrSourceBuffer(
77427771
StringRef attributeText) {
77437772
auto known = ClangSwiftAttrSourceBuffers.find(attributeText);
@@ -7920,6 +7949,18 @@ void ClangImporter::Implementation::importAttributes(
79207949
// __attribute__((swift_attr("attribute")))
79217950
//
79227951
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(*AI)) {
7952+
// FIXME: Hard-core @MainActor, because we don't have a point at which to
7953+
// do name lookup for imported entities.
7954+
if (swiftAttr->getAttribute() == "@MainActor") {
7955+
if (Type mainActorType = getMainActorType()) {
7956+
auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext);
7957+
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr);
7958+
MappedDecl->getAttrs().add(attr);
7959+
}
7960+
7961+
continue;
7962+
}
7963+
79237964
// Dig out a buffer with the attribute text.
79247965
unsigned bufferID = getClangSwiftAttrSourceBuffer(
79257966
swiftAttr->getAttribute());
@@ -7934,10 +7975,10 @@ void ClangImporter::Implementation::importAttributes(
79347975
// Prime the lexer.
79357976
parser.consumeTokenWithoutFeedingReceiver();
79367977

7937-
79387978
SourceLoc atLoc;
79397979
if (parser.consumeIf(tok::at_sign, atLoc)) {
7940-
(void)parser.parseDeclAttribute(MappedDecl->getAttrs(), atLoc);
7980+
(void)parser.parseDeclAttribute(
7981+
MappedDecl->getAttrs(), atLoc, /*isFromClangAttribute=*/true);
79417982
} else {
79427983
// Complain about the missing '@'.
79437984
auto &clangSrcMgr = getClangASTContext().getSourceManager();

lib/ClangImporter/ImporterImpl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
401401
/// Clang arguments used to create the Clang invocation.
402402
std::vector<std::string> ClangArgs;
403403

404+
/// The main actor type, populated the first time we look for it.
405+
Optional<Type> MainActorType;
406+
404407
/// Mapping from Clang swift_attr attribute text to the Swift source buffer
405408
/// IDs that contain that attribute text. These are re-used when parsing the
406409
/// Swift attributes on import.
@@ -778,6 +781,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
778781
/// Map a Clang identifier name to its imported Swift equivalent.
779782
StringRef getSwiftNameFromClangName(StringRef name);
780783

784+
/// Look for the MainActor type in the _Concurrency library.
785+
Type getMainActorType();
786+
781787
/// Retrieve the Swift source buffer ID that corresponds to the given
782788
/// swift_attr attribute text, creating one if necessary.
783789
unsigned getClangSwiftAttrSourceBuffer(StringRef attributeText);

lib/Parse/ParseDecl.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,7 +1536,7 @@ void Parser::parseAllAvailabilityMacroArguments() {
15361536
}
15371537

15381538
bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
1539-
DeclAttrKind DK) {
1539+
DeclAttrKind DK, bool isFromClangAttribute) {
15401540
// Ok, it is a valid attribute, eat it, and then process it.
15411541
StringRef AttrName = Tok.getText();
15421542
SourceLoc Loc = consumeToken();
@@ -1550,7 +1550,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
15501550
// Delay issuing the diagnostic until we parse the attribute.
15511551
DiscardAttribute = true;
15521552
}
1553-
1553+
15541554
// If this is a SIL-only attribute, reject it.
15551555
if ((DeclAttribute::getOptions(DK) & DeclAttribute::SILOnly) != 0 &&
15561556
!isInSILMode()) {
@@ -1561,9 +1561,13 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
15611561
// If this attribute is only permitted when concurrency is enabled, reject it.
15621562
if (DeclAttribute::isConcurrencyOnly(DK) &&
15631563
!shouldParseExperimentalConcurrency()) {
1564-
diagnose(
1565-
Loc, diag::attr_requires_concurrency, AttrName,
1566-
DeclAttribute::isDeclModifier(DK));
1564+
// Ignore concurrency-only attributes that come from Clang.
1565+
if (!isFromClangAttribute) {
1566+
diagnose(
1567+
Loc, diag::attr_requires_concurrency, AttrName,
1568+
DeclAttribute::isDeclModifier(DK));
1569+
}
1570+
15671571
DiscardAttribute = true;
15681572
}
15691573

@@ -2682,7 +2686,8 @@ static PatternBindingInitializer *findAttributeInitContent(
26822686
/// Note that various attributes (like mutating, weak, and unowned) are parsed
26832687
/// but rejected since they have context-sensitive keywords.
26842688
///
2685-
ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc) {
2689+
ParserStatus Parser::parseDeclAttribute(
2690+
DeclAttributes &Attributes, SourceLoc AtLoc, bool isFromClangAttribute) {
26862691
// If this not an identifier, the attribute is malformed.
26872692
if (Tok.isNot(tok::identifier) &&
26882693
Tok.isNot(tok::kw_in) &&
@@ -2789,7 +2794,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc At
27892794
}
27902795

27912796
if (DK != DAK_Count && !DeclAttribute::shouldBeRejectedByParser(DK)) {
2792-
parseNewDeclAttribute(Attributes, AtLoc, DK);
2797+
parseNewDeclAttribute(Attributes, AtLoc, DK, isFromClangAttribute);
27932798
return makeParserSuccess();
27942799
}
27952800

test/ClangImporter/objc_async.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func testSlowServerOldSchool(slowServer: SlowServer) {
6969
func globalAsync() async { }
7070

7171
actor class MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
72-
func syncMethod() { } // expected-note{{calls to instance method 'syncMethod()' from outside of its actor context are implicitly asynchronous}}
72+
func syncMethod() { } // expected-note 2{{calls to instance method 'syncMethod()' from outside of its actor context are implicitly asynchronous}}
7373

7474
func independentMethod() {
7575
syncMethod() // expected-error{{ctor-isolated instance method 'syncMethod()' can not be referenced from an '@actorIndependent' context}}
@@ -78,4 +78,8 @@ actor class MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
7878
func asyncHandlerMethod() {
7979
await globalAsync() // okay because we infer @asyncHandler from the protocol
8080
}
81+
82+
func mainActorMethod() {
83+
syncMethod() // expected-error{{actor-isolated instance method 'syncMethod()' can not be referenced from context of global actor 'MainActor'}}
84+
}
8185
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules %s -verify
2+
3+
// REQUIRES: objc_interop
4+
import Foundation
5+
import ObjCConcurrency
6+
7+
func testSlowServerSynchronous(slowServer: SlowServer) {
8+
// synchronous version
9+
let _: Int = slowServer.doSomethingConflicted("thinking")
10+
slowServer.poorlyNamed("hello") { (i: Int) in print(i) }
11+
slowServer.customize(with: "hello") { (i: Int) in print(i) }
12+
13+
slowServer.dance("jig") { s in print(s + "") }
14+
slowServer.leap(17) { s in print(s + "") }
15+
slowServer.repeatTrick("jump") { i in print(i + 1) }
16+
}
17+
18+
func testSlowServerOldSchool(slowServer: SlowServer) {
19+
slowServer.doSomethingSlow("mail") { i in
20+
_ = i
21+
}
22+
23+
_ = slowServer.allOperations
24+
}

test/IDE/print_clang_objc_async.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
// REQUIRES: objc_interop
77
// REQUIRES: concurrency
8+
import _Concurrency
89

910
// CHECK-LABEL: class SlowServer : NSObject, ServiceProvider {
1011
// CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
@@ -38,5 +39,6 @@
3839
// CHECK-LABEL: protocol ProtocolWithSwiftAttributes {
3940
// CHECK-NEXT: @actorIndependent func independentMethod()
4041
// CHECK-NEXT: @asyncHandler func asyncHandlerMethod()
42+
// CHECK-NEXT: @MainActor func mainActorMethod()
4143
// CHECK-NEXT: {{^}} optional func missingAtAttributeMethod()
4244
// CHECK-NEXT: {{^[}]$}}

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
6767
@protocol ProtocolWithSwiftAttributes
6868
-(void)independentMethod __attribute__((__swift_attr__("@actorIndependent")));
6969
-(void)asyncHandlerMethod __attribute__((__swift_attr__("@asyncHandler")));
70+
-(void)mainActorMethod __attribute__((__swift_attr__("@MainActor")));
7071

7172
@optional
7273
-(void)missingAtAttributeMethod __attribute__((__swift_attr__("asyncHandler")));

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,6 +2613,14 @@ static int doPrintModules(const CompilerInvocation &InitInvok,
26132613
return 1;
26142614
}
26152615

2616+
// If needed, load _Concurrency library so that the Clang importer can use it.
2617+
if (Context.LangOpts.EnableExperimentalConcurrency) {
2618+
if (!getModuleByFullName(Context, Context.Id_Concurrency)) {
2619+
llvm::errs() << "Failed loading _Concurrency library\n";
2620+
return 1;
2621+
}
2622+
}
2623+
26162624
int ExitCode = 0;
26172625

26182626
std::unique_ptr<ASTPrinter> Printer;

0 commit comments

Comments
 (0)