diff --git a/SwiftCompilerSources/Sources/AST/Declarations.swift b/SwiftCompilerSources/Sources/AST/Declarations.swift index f93914485f433..6d2385a873ea5 100644 --- a/SwiftCompilerSources/Sources/AST/Declarations.swift +++ b/SwiftCompilerSources/Sources/AST/Declarations.swift @@ -124,6 +124,8 @@ final public class TopLevelCodeDecl: Decl {} final public class ImportDecl: Decl {} +final public class UsingDecl: Decl {} + final public class PrecedenceGroupDecl: Decl {} final public class MissingDecl: Decl {} diff --git a/SwiftCompilerSources/Sources/AST/Registration.swift b/SwiftCompilerSources/Sources/AST/Registration.swift index f1d09ebf4190d..6c4f62bf69cb7 100644 --- a/SwiftCompilerSources/Sources/AST/Registration.swift +++ b/SwiftCompilerSources/Sources/AST/Registration.swift @@ -36,6 +36,7 @@ public func registerAST() { registerDecl(ExtensionDecl.self) registerDecl(TopLevelCodeDecl.self) registerDecl(ImportDecl.self) + registerDecl(UsingDecl.self) registerDecl(PrecedenceGroupDecl.self) registerDecl(MissingDecl.self) registerDecl(MissingMemberDecl.self) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 2bb8a5cf1d5e1..8a66d6d167c21 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -1744,6 +1744,19 @@ BridgedImportDecl BridgedImportDecl_createParsed( BridgedSourceLoc cImportKeywordLoc, BridgedImportKind cImportKind, BridgedSourceLoc cImportKindLoc, BridgedArrayRef cImportPathElements); +enum ENUM_EXTENSIBILITY_ATTR(open) BridgedUsingSpecifier { + BridgedUsingSpecifierMainActor, + BridgedUsingSpecifierNonisolated, +}; + +SWIFT_NAME("BridgedUsingDecl.createParsed(_:declContext:usingKeywordLoc:" + "specifierLoc:specifier:)") +BridgedUsingDecl BridgedUsingDecl_createParsed(BridgedASTContext cContext, + BridgedDeclContext cDeclContext, + BridgedSourceLoc usingKeywordLoc, + BridgedSourceLoc specifierLoc, + BridgedUsingSpecifier specifier); + SWIFT_NAME("BridgedSubscriptDecl.createParsed(_:declContext:staticLoc:" "staticSpelling:subscriptKeywordLoc:genericParamList:parameterList:" "arrowLoc:returnType:genericWhereClause:)") diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index f0b6b6a713062..7e40df15794ea 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -213,7 +213,8 @@ enum class DescriptiveDeclKind : uint8_t { OpaqueResultType, OpaqueVarType, Macro, - MacroExpansion + MacroExpansion, + Using }; /// Describes which spelling was used in the source for the 'static' or 'class' @@ -267,6 +268,16 @@ static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) < "Self Access Kind is too small to fit in SelfAccess kind bits. " "Please expand "); +enum class UsingSpecifier : uint8_t { + MainActor, + Nonisolated, + LastSpecifier = Nonisolated, +}; +enum : unsigned { + NumUsingSpecifierBits = + countBitsUsed(static_cast(UsingSpecifier::LastSpecifier)) +}; + /// Diagnostic printing of \c SelfAccessKind. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK); @@ -827,6 +838,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated, public Swi NumPathElements : 8 ); + SWIFT_INLINE_BITFIELD(UsingDecl, Decl, NumUsingSpecifierBits, + Specifier : NumUsingSpecifierBits + ); + SWIFT_INLINE_BITFIELD(ExtensionDecl, Decl, 4+1, /// An encoding of the default and maximum access level for this extension. /// The value 4 corresponds to AccessLevel::Public @@ -9737,6 +9752,34 @@ class MacroExpansionDecl : public Decl, public FreestandingMacroExpansion { } }; +/// UsingDecl - This represents a single `using` declaration, e.g.: +/// using @MainActor +class UsingDecl : public Decl { + friend class Decl; + +private: + SourceLoc UsingLoc, SpecifierLoc; + + UsingDecl(SourceLoc usingLoc, SourceLoc specifierLoc, + UsingSpecifier specifier, DeclContext *parent); + +public: + UsingSpecifier getSpecifier() const { + return static_cast(Bits.UsingDecl.Specifier); + } + + std::string getSpecifierName() const; + + SourceLoc getLocFromSource() const { return UsingLoc; } + SourceRange getSourceRange() const { return {UsingLoc, SpecifierLoc}; } + + static UsingDecl *create(ASTContext &ctx, SourceLoc usingLoc, + SourceLoc specifierLoc, UsingSpecifier specifier, + DeclContext *parent); + + static bool classof(const Decl *D) { return D->getKind() == DeclKind::Using; } +}; + inline void AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) { Accessors.setInt(accessLevel); diff --git a/include/swift/AST/DeclExportabilityVisitor.h b/include/swift/AST/DeclExportabilityVisitor.h index 6eb9c46c928d9..732113d55a056 100644 --- a/include/swift/AST/DeclExportabilityVisitor.h +++ b/include/swift/AST/DeclExportabilityVisitor.h @@ -158,6 +158,7 @@ class DeclExportabilityVisitor UNREACHABLE(MissingMember); UNREACHABLE(GenericTypeParam); UNREACHABLE(Param); + UNREACHABLE(Using); #undef UNREACHABLE diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 2f02c4bf5aac8..ef83c8a92777f 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -190,6 +190,7 @@ DECL(Missing, Decl) DECL(MissingMember, Decl) DECL(PatternBinding, Decl) DECL(EnumCase, Decl) +DECL(Using, Decl) ABSTRACT_DECL(Operator, Decl) OPERATOR_DECL(InfixOperator, OperatorDecl) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 0d7b038a0ca8c..a7062f6d8fedc 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -2187,5 +2187,14 @@ ERROR(nonisolated_nonsending_expected_rparen,PointsToFirstBadToken, ERROR(nonisolated_nonsending_repeated,none, "parameter may have at most one 'nonisolated(nonsending)' specifier", ()) +//------------------------------------------------------------------------------ +// MARK: using @ or using +//------------------------------------------------------------------------------ +ERROR(using_decl_invalid_specifier,PointsToFirstBadToken, + "default isolation can only be set to '@MainActor' or 'nonisolated'", + ()) +ERROR(experimental_using_decl_disabled,PointsToFirstBadToken, + "'using' is an experimental feature that is currently disabled", ()) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index da779db7a8cb2..a95de7ec3e6fc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8776,5 +8776,13 @@ ERROR(extensible_attr_on_internal_type,none, ERROR(pre_enum_extensibility_without_extensible,none, "%0 can only be used together with '@extensible' attribute", (DeclAttribute)) +//===----------------------------------------------------------------------===// +// MARK: `using` declaration +//===----------------------------------------------------------------------===// +ERROR(invalid_redecl_of_file_isolation,none, + "invalid redeclaration of file-level default actor isolation", ()) +NOTE(invalid_redecl_of_file_isolation_prev,none, + "default isolation was previously declared here", ()) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index a847b43bfd8f9..696129a1a64d5 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -32,6 +32,7 @@ class GeneratedSourceInfo; class PersistentParserState; struct SourceFileExtras; class Token; +enum class DefaultIsolation : uint8_t; /// Kind of import affecting how a decl can be reexported. /// @@ -690,6 +691,11 @@ class SourceFile final : public FileUnit { DelayedParserState = std::move(state); } + /// Retrieve default action isolation to be used for this source file. + /// It's determine based on on top-level `using <>` declaration + /// found in the file. + std::optional getDefaultIsolation() const; + SWIFT_DEBUG_DUMP; void dump(raw_ostream &os, diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 3bd68e74fa17f..f2d59d7881722 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -5332,6 +5332,23 @@ class SemanticAvailabilitySpecRequest void cacheResult(std::optional value) const; }; +class DefaultIsolationInSourceFileRequest + : public SimpleRequest(const SourceFile *), + RequestFlags::Cached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + std::optional evaluate(Evaluator &evaluator, + const SourceFile *file) const; + +public: + bool isCached() const { return true; } +}; + #define SWIFT_TYPEID_ZONE TypeChecker #define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index adccb8ace5927..659b7c4a7579a 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -629,3 +629,7 @@ SWIFT_REQUEST(TypeChecker, SemanticAvailabilitySpecRequest, std::optional (const AvailabilitySpec *, const DeclContext *), SeparatelyCached, NoLocationInfo) + +SWIFT_REQUEST(TypeChecker, DefaultIsolationInSourceFileRequest, + std::optional(const SourceFile *), + Cached, NoLocationInfo) diff --git a/include/swift/AST/TypeMemberVisitor.h b/include/swift/AST/TypeMemberVisitor.h index 7ad863f980968..479a84510d49d 100644 --- a/include/swift/AST/TypeMemberVisitor.h +++ b/include/swift/AST/TypeMemberVisitor.h @@ -41,6 +41,7 @@ class TypeMemberVisitor : public DeclVisitor { BAD_MEMBER(Operator) BAD_MEMBER(PrecedenceGroup) BAD_MEMBER(Macro) + BAD_MEMBER(Using) RetTy visitMacroExpansionDecl(MacroExpansionDecl *D) { // Expansion already visited as auxiliary decls. diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index b22ae9e1145e9..dda0e72f5128e 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -521,6 +521,10 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExtensibleAttribute, false) /// Allow use of `Module::name` syntax EXPERIMENTAL_FEATURE(ModuleSelector, false) +/// Allow use of `using` declaration that control default isolation +/// in a file scope. +EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false) + #undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE #undef EXPERIMENTAL_FEATURE #undef UPCOMING_FEATURE diff --git a/include/swift/IDE/CodeCompletionResult.h b/include/swift/IDE/CodeCompletionResult.h index 83b067aaa3eae..9e247d1552191 100644 --- a/include/swift/IDE/CodeCompletionResult.h +++ b/include/swift/IDE/CodeCompletionResult.h @@ -190,6 +190,7 @@ enum class CodeCompletionKeywordKind : uint8_t { enum class CompletionKind : uint8_t { None, Import, + Using, UnresolvedMember, DotExpr, StmtOrExpr, diff --git a/include/swift/IDE/CompletionLookup.h b/include/swift/IDE/CompletionLookup.h index 35203e1d6d68c..47b00f55eb135 100644 --- a/include/swift/IDE/CompletionLookup.h +++ b/include/swift/IDE/CompletionLookup.h @@ -325,6 +325,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addImportModuleNames(); + void addUsingSpecifiers(); + SemanticContextKind getSemanticContext(const Decl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo); diff --git a/include/swift/Parse/IDEInspectionCallbacks.h b/include/swift/Parse/IDEInspectionCallbacks.h index 3605662f6ac1c..45c2634cbdd8e 100644 --- a/include/swift/Parse/IDEInspectionCallbacks.h +++ b/include/swift/Parse/IDEInspectionCallbacks.h @@ -255,6 +255,10 @@ class CodeCompletionCallbacks { virtual void completeImportDecl(ImportPath::Builder &Path) {}; + /// Complete the 'using' decl with supported specifiers. + virtual void + completeUsingDecl() {}; + /// Complete unresolved members after dot. virtual void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) {}; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 18a1e0b13c0dd..627699538c3a0 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1223,6 +1223,9 @@ class Parser { ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); + ParserResult parseDeclUsing(ParseDeclOptions Flags, + DeclAttributes &Attributes); + /// Parse an inheritance clause into a vector of InheritedEntry's. /// /// \param allowClassRequirement whether to permit parsing of 'class' diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h index ba1a14a64ce30..df041a2270e40 100644 --- a/include/swift/Parse/Token.h +++ b/include/swift/Parse/Token.h @@ -196,8 +196,9 @@ class Token { #define CONTEXTUAL_SIMPLE_DECL_ATTR(KW, ...) CONTEXTUAL_CASE(KW) #include "swift/AST/DeclAttr.def" #undef CONTEXTUAL_CASE - .Case("macro", true) - .Default(false); + .Case("macro", true) + .Case("using", true) + .Default(false); } bool isContextualPunctuator(StringRef ContextPunc) const { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 508a978caa516..78bc7fee4d693 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2114,6 +2114,11 @@ namespace { printFoot(); } + void visitUsingDecl(UsingDecl *UD, Label label) { + printCommon(UD, "using_decl", label); + printFieldQuoted(UD->getSpecifierName(), Label::always("specifier")); + } + void visitExtensionDecl(ExtensionDecl *ED, Label label) { printCommon(ED, "extension_decl", label, ExtensionColor); printFlag(!ED->hasBeenBound(), "unbound"); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index eab548632bcc4..989e0a4e49f90 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -5426,6 +5426,7 @@ ASTMangler::BaseEntitySignature::BaseEntitySignature(const Decl *decl) case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: case DeclKind::MacroExpansion: + case DeclKind::Using: break; }; } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 7277b4fb648af..114dc3d35d1ed 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -383,6 +383,11 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint, } } + // The `using` declarations are private to the file at the moment + // and shouldn't appear in swift interfaces. + if (isa(D)) + return false; + return ShouldPrintChecker::shouldPrint(D, options); } }; @@ -3052,6 +3057,11 @@ void PrintAST::visitImportDecl(ImportDecl *decl) { [&] { Printer << "."; }); } +void PrintAST::visitUsingDecl(UsingDecl *decl) { + Printer.printIntroducerKeyword("using", Options, " "); + Printer << decl->getSpecifierName(); +} + void PrintAST::printExtendedTypeName(TypeLoc ExtendedTypeLoc) { bool OldFullyQualifiedTypesIfAmbiguous = Options.FullyQualifiedTypesIfAmbiguous; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index baac19d2d0aa3..bd314c7d9add7 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -404,6 +404,7 @@ class NodeAdder VISIT_AND_IGNORE(ParamDecl) VISIT_AND_IGNORE(MissingDecl) VISIT_AND_IGNORE(MissingMemberDecl) + VISIT_AND_IGNORE(UsingDecl) // This declaration is handled from the PatternBindingDecl VISIT_AND_IGNORE(VarDecl) diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 0db55fa7ec09c..e20559a241ccf 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -201,6 +201,10 @@ class Traversal : public ASTVisitorgetExtendedTypeRepr()) if (doIt(typeRepr)) diff --git a/lib/AST/Bridging/DeclBridging.cpp b/lib/AST/Bridging/DeclBridging.cpp index f9d5691c0d4c3..331a455a9b0fa 100644 --- a/lib/AST/Bridging/DeclBridging.cpp +++ b/lib/AST/Bridging/DeclBridging.cpp @@ -637,6 +637,17 @@ BridgedImportDecl BridgedImportDecl_createParsed( std::move(builder).get()); } +BridgedUsingDecl BridgedUsingDecl_createParsed(BridgedASTContext cContext, + BridgedDeclContext cDeclContext, + BridgedSourceLoc usingKeywordLoc, + BridgedSourceLoc specifierLoc, + BridgedUsingSpecifier specifier) { + ASTContext &ctx = cContext.unbridged(); + return UsingDecl::create( + ctx, usingKeywordLoc.unbridged(), specifierLoc.unbridged(), + static_cast(specifier), cDeclContext.unbridged()); +} + BridgedSubscriptDecl BridgedSubscriptDecl_createParsed( BridgedASTContext cContext, BridgedDeclContext cDeclContext, BridgedSourceLoc cStaticLoc, BridgedStaticSpelling cStaticSpelling, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index eeeb02ee01f36..b0ed20b315408 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -189,6 +189,7 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const { TRIVIAL_KIND(MissingMember); TRIVIAL_KIND(Macro); TRIVIAL_KIND(MacroExpansion); + TRIVIAL_KIND(Using); case DeclKind::TypeAlias: return cast(this)->getGenericParams() @@ -400,6 +401,7 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) { ENTRY(OpaqueVarType, "type"); ENTRY(Macro, "macro"); ENTRY(MacroExpansion, "pound literal"); + ENTRY(Using, "using"); } #undef ENTRY llvm_unreachable("bad DescriptiveDeclKind"); @@ -1711,6 +1713,7 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) { case DeclKind::Missing: case DeclKind::MissingMember: case DeclKind::MacroExpansion: + case DeclKind::Using: llvm_unreachable("not a ValueDecl"); case DeclKind::AssociatedType: @@ -1838,6 +1841,30 @@ bool ImportDecl::isAccessLevelImplicit() const { return true; } +UsingDecl::UsingDecl(SourceLoc usingLoc, SourceLoc specifierLoc, + UsingSpecifier specifier, DeclContext *parent) + : Decl(DeclKind::Using, parent), UsingLoc(usingLoc), + SpecifierLoc(specifierLoc) { + Bits.UsingDecl.Specifier = static_cast(specifier); + assert(getSpecifier() == specifier && + "not enough bits in UsingDecl flags for specifier"); +} + +std::string UsingDecl::getSpecifierName() const { + switch (getSpecifier()) { + case UsingSpecifier::MainActor: + return "@MainActor"; + case UsingSpecifier::Nonisolated: + return "nonisolated"; + } +} + +UsingDecl *UsingDecl::create(ASTContext &ctx, SourceLoc usingLoc, + SourceLoc specifierLoc, UsingSpecifier specifier, + DeclContext *parent) { + return new (ctx) UsingDecl(usingLoc, specifierLoc, specifier, parent); +} + void NominalTypeDecl::setConformanceLoader(LazyMemberLoader *lazyLoader, uint64_t contextData) { assert(!Bits.NominalTypeDecl.HasLazyConformances && @@ -3652,6 +3679,7 @@ bool ValueDecl::isInstanceMember() const { case DeclKind::Missing: case DeclKind::MissingMember: case DeclKind::MacroExpansion: + case DeclKind::Using: llvm_unreachable("Not a ValueDecl"); case DeclKind::Class: @@ -4765,6 +4793,7 @@ SourceLoc Decl::getAttributeInsertionLoc(bool forModifier) const { case DeclKind::MissingMember: case DeclKind::MacroExpansion: case DeclKind::BuiltinTuple: + case DeclKind::Using: // These don't take attributes. return SourceLoc(); diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index cc8297a3cb3bd..f5b8619dee90b 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -643,6 +643,10 @@ static bool usesFeatureAlwaysInheritActorContext(Decl *decl) { return false; } +static bool usesFeatureDefaultIsolationPerFile(Decl *D) { + return isa(D); +} + UNINTERESTING_FEATURE(BuiltinSelect) // ---------------------------------------------------------------------------- diff --git a/lib/AST/FrontendSourceFileDepGraphFactory.cpp b/lib/AST/FrontendSourceFileDepGraphFactory.cpp index 3b4c88d4158ba..24296257d2747 100644 --- a/lib/AST/FrontendSourceFileDepGraphFactory.cpp +++ b/lib/AST/FrontendSourceFileDepGraphFactory.cpp @@ -221,6 +221,7 @@ StringRef DependencyKey::Builder::getTopLevelName(const Decl *decl) { case DeclKind::MissingMember: case DeclKind::Module: case DeclKind::MacroExpansion: + case DeclKind::Using: return ""; } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index ce2b21a1c4e14..754d1251b67ea 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -3829,6 +3829,12 @@ bool SourceFile::FileIDStr::matches(const SourceFile *file) const { fileName == llvm::sys::path::filename(file->getFilename()); } +std::optional SourceFile::getDefaultIsolation() const { + auto &ctx = getASTContext(); + return evaluateOrDefault( + ctx.evaluator, DefaultIsolationInSourceFileRequest{this}, std::nullopt); +} + namespace { class LocalTypeDeclCollector : public ASTWalker { SmallVectorImpl &results; diff --git a/lib/ASTGen/Sources/ASTGen/Decls.swift b/lib/ASTGen/Sources/ASTGen/Decls.swift index 62e275dac7d55..ec94de1ca597d 100644 --- a/lib/ASTGen/Sources/ASTGen/Decls.swift +++ b/lib/ASTGen/Sources/ASTGen/Decls.swift @@ -69,6 +69,8 @@ extension ASTGenVisitor { return self.generate(typeAliasDecl: node)?.asDecl case .variableDecl(let node): return self.generate(variableDecl: node) + case .usingDecl(let node): + return self.generate(usingDecl: node)?.asDecl } } @@ -1083,6 +1085,37 @@ extension ASTGenVisitor { } } +extension ASTGenVisitor { + func generate(usingDecl node: UsingDeclSyntax) -> BridgedUsingDecl? { + var specifier: BridgedUsingSpecifier? = nil + + switch node.specifier { + case .attribute(let attr): + if let identifier = attr.attributeName.as(IdentifierTypeSyntax.self), + identifier.name.tokenKind == .identifier("MainActor") { + specifier = .mainActor + } + case .modifier(let modifier): + if case .identifier("nonisolated") = modifier.tokenKind { + specifier = .nonisolated + } + } + + guard let specifier else { + self.diagnose(.invalidDefaultIsolationSpecifier(node.specifier)) + return nil + } + + return BridgedUsingDecl.createParsed( + self.ctx, + declContext: self.declContext, + usingKeywordLoc: self.generateSourceLoc(node.usingKeyword), + specifierLoc: self.generateSourceLoc(node.specifier), + specifier: specifier + ) + } +} + extension ASTGenVisitor { func generate(memberBlockItem node: MemberBlockItemSyntax) -> BridgedDecl? { if let node = node.decl.as(MacroExpansionDeclSyntax.self) { diff --git a/lib/ASTGen/Sources/ASTGen/Diagnostics.swift b/lib/ASTGen/Sources/ASTGen/Diagnostics.swift index 3d578d51d2456..ff78907df0f93 100644 --- a/lib/ASTGen/Sources/ASTGen/Diagnostics.swift +++ b/lib/ASTGen/Sources/ASTGen/Diagnostics.swift @@ -146,6 +146,13 @@ extension ASTGenDiagnostic { message: "expressions are not allowed at the top level" ) } + + static func invalidDefaultIsolationSpecifier(_ specifier: some SyntaxProtocol) -> Self { + Self( + node: specifier, + message: "default isolation can only be set to '@MainActor' or 'nonisolated'" + ) + } } /// DeclAttributes diagnostics diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index ada0514e033a8..03c13f0193fa6 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -78,6 +78,7 @@ extension Parser.ExperimentalFeatures { mapFeature(.OldOwnershipOperatorSpellings, to: .oldOwnershipOperatorSpellings) mapFeature(.KeyPathWithMethodMembers, to: .keypathWithMethodMembers) mapFeature(.InlineArrayTypeSugar, to: .inlineArrayTypeSugar) + mapFeature(.DefaultIsolationPerFile, to: .defaultIsolationPerFile) } } diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index bcca73daaca5a..c635ee46b63b6 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -283,6 +283,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks, void completePoundAvailablePlatform() override; void completeImportDecl(ImportPath::Builder &Path) override; + void completeUsingDecl() override; void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) override; void completeCallArg(CodeCompletionExpr *E) override; @@ -550,6 +551,11 @@ void CodeCompletionCallbacksImpl::completeImportDecl( Path.pop_back(); } +void CodeCompletionCallbacksImpl::completeUsingDecl() { + Kind = CompletionKind::Using; + CurDeclContext = P.CurDeclContext; +} + void CodeCompletionCallbacksImpl::completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) { Kind = CompletionKind::UnresolvedMember; @@ -990,6 +996,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, case CompletionKind::AttributeBegin: case CompletionKind::PoundAvailablePlatform: case CompletionKind::Import: + case CompletionKind::Using: case CompletionKind::UnresolvedMember: case CompletionKind::AfterPoundExpr: case CompletionKind::AfterPoundDirective: @@ -1915,7 +1922,10 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) { Lookup.addImportModuleNames(); break; } - + case CompletionKind::Using: { + Lookup.addUsingSpecifiers(); + break; + } case CompletionKind::AfterPoundDirective: { addPoundDirectives(CompletionContext.getResultSink()); diff --git a/lib/IDE/CodeCompletionResult.cpp b/lib/IDE/CodeCompletionResult.cpp index 3a48f610ca8d9..e5490285c5d7d 100644 --- a/lib/IDE/CodeCompletionResult.cpp +++ b/lib/IDE/CodeCompletionResult.cpp @@ -315,6 +315,7 @@ ContextFreeCodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) { case DeclKind::OpaqueType: case DeclKind::BuiltinTuple: case DeclKind::MacroExpansion: + case DeclKind::Using: llvm_unreachable("not expecting such a declaration result"); case DeclKind::Module: return CodeCompletionDeclKind::Module; diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index a02bbec18ba2d..4752c56950af4 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -387,6 +387,23 @@ void CompletionLookup::addImportModuleNames() { } } +void CompletionLookup::addUsingSpecifiers() { + for (unsigned i = 0, + n = static_cast(UsingSpecifier::LastSpecifier) + 1; + i != n; ++i) { + CodeCompletionResultBuilder Builder = makeResultBuilder( + CodeCompletionResultKind::Keyword, SemanticContextKind::None); + switch (static_cast(i)) { + case UsingSpecifier::MainActor: + Builder.addTextChunk("@MainActor"); + break; + case UsingSpecifier::Nonisolated: + Builder.addTextChunk("nonisolated"); + break; + } + } +} + SemanticContextKind CompletionLookup::getSemanticContext(const Decl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index b245c467ed55e..83c2662cb663c 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2661,6 +2661,9 @@ void IRGenModule::emitGlobalDecl(Decl *D) { case DeclKind::MacroExpansion: // Expansion already visited as auxiliary decls. return; + + case DeclKind::Using: + return; } llvm_unreachable("bad decl kind!"); @@ -5793,6 +5796,7 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) { case DeclKind::Param: case DeclKind::Module: case DeclKind::PrecedenceGroup: + case DeclKind::Using: llvm_unreachable("decl not allowed in type context"); case DeclKind::BuiltinTuple: diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index 5e32952d9a477..74e7f9bf3eaef 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -248,6 +248,7 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) { case DeclKind::OpaqueType: case DeclKind::BuiltinTuple: case DeclKind::MacroExpansion: + case DeclKind::Using: break; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 60548ea76ffe4..5bd75f4c8f58a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5938,6 +5938,17 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes, } } + // `using @` or `using `. + if (Tok.isContextualKeyword("using")) { + // `using` declarations don't support attributes or modifiers. + if (hadAttrsOrModifiers) + return false; + + return !Tok2.isAtStartOfLine() && + (Tok2.is(tok::at_sign) || Tok2.is(tok::identifier) || + Tok2.is(tok::code_complete)); + } + // If the next token is obviously not the start of a decl, bail early. if (!isKeywordPossibleDeclStart(Context.LangOpts, Tok2)) return false; @@ -6292,6 +6303,17 @@ ParserStatus Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi, break; } + // `using @` or `using ` + if (Tok.isContextualKeyword("using")) { + auto nextToken = peekToken(); + if (!nextToken.isAtStartOfLine() && + (nextToken.is(tok::at_sign) || nextToken.is(tok::identifier) || + nextToken.is(tok::code_complete))) { + DeclResult = parseDeclUsing(Flags, Attributes); + break; + } + } + if (Flags.contains(PD_HasContainerType) && IsAtStartOfLineOrPreviousHadSemi) { @@ -6639,6 +6661,68 @@ ParserResult Parser::parseDeclImport(ParseDeclOptions Flags, return DCC.fixupParserResult(ID); } +/// Parse an `using` declaration. +/// +/// \verbatim +/// decl-using: +/// 'using' (@ | ) +/// \endverbatim +ParserResult Parser::parseDeclUsing(ParseDeclOptions Flags, + DeclAttributes &Attributes) { + assert(Tok.isContextualKeyword("using")); + DebuggerContextChange DCC(*this); + + if (!Context.LangOpts.hasFeature(Feature::DefaultIsolationPerFile)) { + diagnose(Tok, diag::experimental_using_decl_disabled); + } + + SourceLoc UsingLoc = consumeToken(); + + if (Tok.is(tok::code_complete)) { + if (CodeCompletionCallbacks) { + CodeCompletionCallbacks->completeUsingDecl(); + } + return makeParserCodeCompletionStatus(); + } + + SourceLoc AtLoc; + // @<> + if (Tok.is(tok::at_sign)) + AtLoc = consumeToken(); + + SourceLoc SpecifierLoc; + Identifier RawSpecifier; + + if (parseIdentifier(RawSpecifier, SpecifierLoc, + /*diagnoseDollarPrefix=*/false, + diag::expected_identifier_in_decl, "using")) + return nullptr; + + std::optional Specifier = + llvm::StringSwitch>(RawSpecifier.str()) + .Case("MainActor", UsingSpecifier::MainActor) + .Case("nonisolated", UsingSpecifier::Nonisolated) + .Default(std::nullopt); + + if (!Specifier) { + diagnose(SpecifierLoc, diag::using_decl_invalid_specifier); + return nullptr; + } + + // Complain the `using` not being at top-level only after the specifier + // has been consumed, otherwise the specifier is going to be interpreted + // as a start of another declaration. + if (!CodeCompletionCallbacks && !DCC.movedToTopLevel() && + !(Flags & PD_AllowTopLevel)) { + diagnose(UsingLoc, diag::decl_inner_scope); + return nullptr; + } + + auto *UD = UsingDecl::create(Context, UsingLoc, AtLoc ? AtLoc : SpecifierLoc, + *Specifier, CurDeclContext); + return DCC.fixupParserResult(UD); +} + /// Parse an inheritance clause. /// /// \verbatim diff --git a/lib/SIL/IR/SILSymbolVisitor.cpp b/lib/SIL/IR/SILSymbolVisitor.cpp index a2bd2c68322c8..5c1a14f492aca 100644 --- a/lib/SIL/IR/SILSymbolVisitor.cpp +++ b/lib/SIL/IR/SILSymbolVisitor.cpp @@ -804,6 +804,7 @@ class SILSymbolVisitorImpl : public ASTVisitor { case DeclKind::PostfixOperator: case DeclKind::Macro: case DeclKind::MacroExpansion: + case DeclKind::Using: return false; case DeclKind::Missing: llvm_unreachable("missing decl should not show up here"); @@ -916,6 +917,7 @@ class SILSymbolVisitorImpl : public ASTVisitor { UNINTERESTING_DECL(PrecedenceGroup) UNINTERESTING_DECL(TopLevelCode) UNINTERESTING_DECL(Value) + UNINTERESTING_DECL(Using) #undef UNINTERESTING_DECL }; diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 3cefec2015209..10fc5c358b390 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -266,6 +266,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { void visitDestructorDecl(DestructorDecl *d) {} void visitModuleDecl(ModuleDecl *d) { } void visitMissingMemberDecl(MissingMemberDecl *d) {} + void visitUsingDecl(UsingDecl *) {} // Emitted as part of its storage. void visitAccessorDecl(AccessorDecl *ad) {} diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 3cfbb734b1110..8b8bfdc32229f 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -600,6 +600,7 @@ class AccessControlChecker : public AccessControlCheckerBase, UNREACHABLE(Operator, "cannot appear in a type context") UNREACHABLE(PrecedenceGroup, "cannot appear in a type context") UNREACHABLE(Module, "cannot appear in a type context") + UNREACHABLE(Using, "cannot appear in a type context") UNREACHABLE(Param, "does not have access control") UNREACHABLE(GenericTypeParam, "does not have access control") @@ -1380,6 +1381,7 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, UNREACHABLE(Operator, "cannot appear in a type context") UNREACHABLE(PrecedenceGroup, "cannot appear in a type context") UNREACHABLE(Module, "cannot appear in a type context") + UNREACHABLE(Using, "cannot appear in a type context") UNREACHABLE(Param, "does not have access control") UNREACHABLE(GenericTypeParam, "does not have access control") @@ -1387,6 +1389,7 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, UNREACHABLE(MissingMember, "does not have access control") UNREACHABLE(MacroExpansion, "does not have access control") UNREACHABLE(BuiltinTuple, "BuiltinTupleDecl should not show up here") + #undef UNREACHABLE #define UNINTERESTING(KIND) \ @@ -2170,6 +2173,7 @@ class DeclAvailabilityChecker : public DeclVisitor { UNREACHABLE(TopLevelCode, "not applicable") UNREACHABLE(Module, "not applicable") UNREACHABLE(Missing, "not applicable") + UNREACHABLE(Using, "not applicable") UNREACHABLE(Param, "handled by the enclosing declaration") UNREACHABLE(GenericTypeParam, "handled by the enclosing declaration") diff --git a/lib/Sema/TypeCheckAttrABI.cpp b/lib/Sema/TypeCheckAttrABI.cpp index 07fab92e98a82..9f6cb40b5b735 100644 --- a/lib/Sema/TypeCheckAttrABI.cpp +++ b/lib/Sema/TypeCheckAttrABI.cpp @@ -683,6 +683,7 @@ class ABIDeclChecker : public ASTComparisonVisitor { UNSUPPORTED_DECL(PrefixOperator) UNSUPPORTED_DECL(PostfixOperator) UNSUPPORTED_DECL(MacroExpansion) + UNSUPPORTED_DECL(Using) bool visitAbstractFunctionDecl(AbstractFunctionDecl *api, AbstractFunctionDecl *abi) { diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 7885ed5d56b31..2fdaa43b7904e 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -5410,6 +5410,7 @@ getMemberIsolationPropagation(const ValueDecl *value) { case DeclKind::EnumElement: case DeclKind::Macro: case DeclKind::MacroExpansion: + case DeclKind::Using: return std::nullopt; case DeclKind::PatternBinding: @@ -5830,8 +5831,14 @@ computeDefaultInferredActorIsolation(ValueDecl *value) { return {}; }; + DefaultIsolation defaultIsolation = ctx.LangOpts.DefaultIsolationBehavior; + if (auto *SF = value->getDeclContext()->getParentSourceFile()) { + if (auto defaultIsolationInFile = SF->getDefaultIsolation()) + defaultIsolation = defaultIsolationInFile.value(); + } + // If we are required to use main actor... just use that. - if (ctx.LangOpts.DefaultIsolationBehavior == DefaultIsolation::MainActor) + if (defaultIsolation == DefaultIsolation::MainActor) if (auto result = globalActorHelper(ctx.getMainActorType()->mapTypeOutOfContext())) return *result; @@ -6455,6 +6462,43 @@ DefaultInitializerIsolation::evaluate(Evaluator &evaluator, return requiredIsolation; } +std::optional +DefaultIsolationInSourceFileRequest::evaluate(Evaluator &evaluator, + const SourceFile *file) const { + llvm::SmallVector usingDecls; + llvm::copy_if(file->getTopLevelDecls(), std::back_inserter(usingDecls), + [](Decl *D) { return isa(D); }); + + if (usingDecls.empty()) + return std::nullopt; + + std::optional> isolation; + + auto setIsolation = [&isolation](Decl *D, DefaultIsolation newIsolation) { + if (isolation) { + D->diagnose(diag::invalid_redecl_of_file_isolation); + isolation->first->diagnose(diag::invalid_redecl_of_file_isolation_prev); + return; + } + + isolation = std::make_pair(D, newIsolation); + }; + + for (auto *D : usingDecls) { + switch (cast(D)->getSpecifier()) { + case UsingSpecifier::MainActor: + setIsolation(D, DefaultIsolation::MainActor); + break; + case UsingSpecifier::Nonisolated: + setIsolation(D, DefaultIsolation::Nonisolated); + break; + } + } + + return isolation.has_value() ? std::optional(isolation->second) + : std::nullopt; +} + void swift::checkOverrideActorIsolation(ValueDecl *value) { if (isa(value)) return; @@ -7692,6 +7736,7 @@ static bool isNonValueReference(const ValueDecl *value) { case DeclKind::PrefixOperator: case DeclKind::TopLevelCode: case DeclKind::MacroExpansion: + case DeclKind::Using: return true; case DeclKind::EnumElement: diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 0089ccc9da1a1..72c608f73755a 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2430,6 +2430,7 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const { case DeclKind::Module: case DeclKind::OpaqueType: case DeclKind::MacroExpansion: + case DeclKind::Using: llvm_unreachable("should not get here"); return Type(); diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 9dcf63312e366..ae5498f34e2af 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2506,6 +2506,10 @@ class DeclChecker : public DeclVisitor { } } + void visitUsingDecl(UsingDecl *UD) { + // Nothing to validate yet. + } + void visitOperatorDecl(OperatorDecl *OD) { TypeChecker::checkDeclAttributes(OD); checkRedeclaration(OD); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index b2ea98fe99a18..cb8b74d140238 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -603,7 +603,8 @@ static void diagnoseInvalidDecl(Decl *decl, isa(decl) || isa(decl) || isa(decl) || - isa(decl)) { + isa(decl) || + isa(decl)) { decl->diagnose(diag::invalid_decl_in_macro_expansion, decl); decl->setInvalid(); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 602bace3e9dcc..4d4eaaa813872 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2146,6 +2146,7 @@ static bool shouldSerializeMember(Decl *D) { case DeclKind::Extension: case DeclKind::Module: case DeclKind::PrecedenceGroup: + case DeclKind::Using: if (D->getASTContext().LangOpts.AllowModuleWithCompilerErrors) return false; llvm_unreachable("decl should never be a member"); @@ -5275,6 +5276,10 @@ class Serializer::DeclSerializer : public DeclVisitor { llvm_unreachable("import decls should not be serialized"); } + void visitUsingDecl(const UsingDecl *) { + llvm_unreachable("using decls should not be serialized"); + } + void visitEnumCaseDecl(const EnumCaseDecl *) { llvm_unreachable("enum case decls should not be serialized"); } @@ -6971,7 +6976,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { for (auto D : fileDecls) { if (isa(D) || isa(D) || - isa(D)) { + isa(D) || isa(D)) { continue; } diff --git a/test/ASTGen/decls.swift b/test/ASTGen/decls.swift index afa080b51c81e..aebef050c773d 100644 --- a/test/ASTGen/decls.swift +++ b/test/ASTGen/decls.swift @@ -2,19 +2,22 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend-dump-parse -disable-availability-checking -enable-experimental-move-only -enable-experimental-concurrency -enable-experimental-feature ParserASTGen \ // RUN: -enable-experimental-feature CoroutineAccessors \ +// RUN: -enable-experimental-feature DefaultIsolationPerFile \ // RUN: | %sanitize-address > %t/astgen.ast // RUN: %target-swift-frontend-dump-parse -disable-availability-checking -enable-experimental-move-only -enable-experimental-concurrency \ // RUN: -enable-experimental-feature CoroutineAccessors \ +// RUN: -enable-experimental-feature DefaultIsolationPerFile \ // RUN: | %sanitize-address > %t/cpp-parser.ast // RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast -// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -Xfrontend -enable-experimental-concurrency -enable-experimental-feature CoroutineAccessors -enable-experimental-feature ParserASTGen) +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -Xfrontend -enable-experimental-concurrency -enable-experimental-feature CoroutineAccessors -enable-experimental-feature DefaultIsolationPerFile -enable-experimental-feature ParserASTGen) // REQUIRES: executable_test // REQUIRES: swift_swift_parser // REQUIRES: swift_feature_ParserASTGen // REQUIRES: swift_feature_CoroutineAccessors +// REQUIRES: swift_feature_DefaultIsolationPerFile // rdar://116686158 // UNSUPPORTED: asan @@ -31,6 +34,10 @@ import protocol Swift.Sequence import func Swift.max import var Swift._playgroundPrintHook + +using @MainActor +// FIXME: cannot add `using nonisolated` here because it's a re-declaration + func test1 ( diff --git a/test/ASTGen/diagnostics.swift b/test/ASTGen/diagnostics.swift index 58f9fafe5cbfe..c78ad917d96fb 100644 --- a/test/ASTGen/diagnostics.swift +++ b/test/ASTGen/diagnostics.swift @@ -1,9 +1,14 @@ // RUN: %empty-directory(%t) -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-bare-slash-regex -enable-experimental-feature ParserASTGen +// RUN: %target-typecheck-verify-swift -disable-availability-checking \ +// RUN: -enable-bare-slash-regex \ +// RUN: -enable-experimental-feature ParserASTGen \ +// RUN: -enable-experimental-feature DefaultIsolationPerFile // REQUIRES: swift_swift_parser // REQUIRES: swift_feature_ParserASTGen +// REQUIRES: swift_feature_DefaultIsolationPerFile + // rdar://116686158 // UNSUPPORTED: asan @@ -66,3 +71,12 @@ func misisngPatternTest(arr: [Int]) { for {} // expected-error {{expected pattern, 'in', and expression in 'for' statement}} // expected-note@-1 {{insert pattern, 'in', and expression}} {{7-7=<#pattern#> }} {{7-7=in }} {{7-7=<#expression#> }} } + +using @MainActor // expected-note {{default isolation was previously declared here}} +using nonisolated // expected-error {{invalid redeclaration of file-level default actor isolation}} + +using @Test +// expected-error@-1 {{default isolation can only be set to '@MainActor' or 'nonisolated'}} + +using test +// expected-error@-1 {{default isolation can only be set to '@MainActor' or 'nonisolated'}} \ No newline at end of file diff --git a/test/Concurrency/default_isolation.swift b/test/Concurrency/default_isolation.swift new file mode 100644 index 0000000000000..3a5a101267513 --- /dev/null +++ b/test/Concurrency/default_isolation.swift @@ -0,0 +1,43 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// REQUIRES: concurrency +// REQUIRES: swift_feature_DefaultIsolationPerFile + +// RUN: %target-swift-frontend -enable-experimental-feature DefaultIsolationPerFile -emit-sil -swift-version 6 -disable-availability-checking %t/main.swift %t/concurrent.swift | %FileCheck %s + +//--- main.swift + +using @MainActor + +class C { + // CHECK: // static C.shared.getter + // CHECK-NEXT: // Isolation: global_actor. type: MainActor + static let shared = C() + + // CHECK: // C.init() + // CHECK-NEXT: // Isolation: global_actor. type: MainActor + init() {} +} + +// CHECK: // test() +// CHECK-NEXT: // Isolation: global_actor. type: MainActor +func test() { + // CHECK: // closure #1 in test() + // CHECK-NEXT: // Isolation: nonisolated + Task.detached { + let s = S(value: 0) + } +} + +//--- concurrent.swift + +using nonisolated + +// CHECK: // S.init(value:) +// CHECK-NEXT: // Isolation: unspecified +struct S { + // CHECK: // S.value.getter + // CHECK-NEXT: // Isolation: unspecified + var value: Int +} diff --git a/test/IDE/complete_using.swift b/test/IDE/complete_using.swift new file mode 100644 index 0000000000000..8d6cc2bcf8ef5 --- /dev/null +++ b/test/IDE/complete_using.swift @@ -0,0 +1,6 @@ +// RUN: %batch-code-completion + +// USING-DAG: Keyword/None: @MainActor; name=@MainActor +// USING-DAG: Keyword/None: nonisolated; name=nonisolated + +using #^USING^# diff --git a/test/Interop/Cxx/class/constructor-inherited-from-base-irgen.swift b/test/Interop/Cxx/class/constructor-inherited-from-base-irgen.cpp similarity index 100% rename from test/Interop/Cxx/class/constructor-inherited-from-base-irgen.swift rename to test/Interop/Cxx/class/constructor-inherited-from-base-irgen.cpp diff --git a/test/Interop/Cxx/templates/swift-class-template-specialization-module-xref.swift b/test/Interop/Cxx/templates/swift-class-template-specialization-module-xref.cpp similarity index 100% rename from test/Interop/Cxx/templates/swift-class-template-specialization-module-xref.swift rename to test/Interop/Cxx/templates/swift-class-template-specialization-module-xref.cpp diff --git a/test/ModuleInterface/using.swift b/test/ModuleInterface/using.swift new file mode 100644 index 0000000000000..9b773ce1de003 --- /dev/null +++ b/test/ModuleInterface/using.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -enable-experimental-feature DefaultIsolationPerFile + +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) + +// RUN: %FileCheck %s --input-file %t.swiftinterface + +// REQUIRES: swift_feature_DefaultIsolationPerFile + +using @MainActor + +// CHECK-NOT: using @MainActor diff --git a/test/Parse/using.swift b/test/Parse/using.swift new file mode 100644 index 0000000000000..520a856e450c8 --- /dev/null +++ b/test/Parse/using.swift @@ -0,0 +1,73 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-feature DefaultIsolationPerFile + +// REQUIRES: swift_feature_DefaultIsolationPerFile + +// REQUIRES: concurrency + +using @MainActor +// expected-note@-1 {{default isolation was previously declared here}} + +using nonisolated +// expected-error@-1 {{invalid redeclaration of file-level default actor isolation}} + +using @Test // expected-error {{default isolation can only be set to '@MainActor' or 'nonisolated'}} +using test // expected-error {{default isolation can only be set to '@MainActor' or 'nonisolated'}} + +do { + using // expected-warning {{expression of type 'Int' is unused}} + @MainActor +// expected-error@+1 {{expected declaration}} +} + +do { + using // expected-warning {{expression of type 'Int' is unused}} + nonisolated // expected-error {{cannot find 'nonisolated' in scope}} +} + +do { + func + using (x: Int) {} + + using(x: 42) +} + +do { + func + using + (x: Int) {} + + using(x: 42) +} + +let + using = 42 + +let (x: Int, using: String) = (x: 42, using: "") + +do { + using @MainActor // expected-error {{declaration is only valid at file scope}} +} + +func test() { + using @MainActor // expected-error {{declaration is only valid at file scope}} +} + +struct S { + var x: Int { + using @MainActor // expected-error {{declaration is only valid at file scope}} + } + + using @MainActor func test() {} + // expected-error@-1 {{declaration is only valid at file scope}} + // expected-error@-2 {{consecutive declarations on a line must be separated by ';'}} + + using nonisolated subscript(a: Int) -> Bool { false } + // expected-error@-1 {{declaration is only valid at file scope}} + // expected-error@-2 {{consecutive declarations on a line must be separated by ';'}} +} + +do { + @objc using @MainActor + // expected-error@-1 {{expected expression}} + // expected-error@-2 {{declaration is only valid at file scope}} +} diff --git a/test/Serialization/using.swift b/test/Serialization/using.swift new file mode 100644 index 0000000000000..634337f30d886 --- /dev/null +++ b/test/Serialization/using.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t %s -module-name Using -enable-experimental-feature DefaultIsolationPerFile +// RUN: %target-swift-frontend -typecheck -I %t %s -module-name main -DMAIN -verify -enable-experimental-feature DefaultIsolationPerFile + +// REQUIRES: swift_feature_DefaultIsolationPerFile + +using @MainActor + +public func test() {} diff --git a/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.cpp b/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.cpp index 8f404dcd289e8..01067871cf73f 100644 --- a/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.cpp +++ b/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.cpp @@ -489,6 +489,8 @@ swiftide_completion_result_get_kind(swiftide_completion_response_t _response) { return SWIFTIDE_COMPLETION_KIND_NONE; case CompletionKind::Import: return SWIFTIDE_COMPLETION_KIND_IMPORT; + case CompletionKind::Using: + return SWIFTIDE_COMPLETION_KIND_USING; case CompletionKind::UnresolvedMember: return SWIFTIDE_COMPLETION_KIND_UNRESOLVEDMEMBER; case CompletionKind::DotExpr: diff --git a/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.h b/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.h index a3b5f1aa7e4f3..2df944d74f4ed 100644 --- a/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.h +++ b/tools/SourceKit/tools/sourcekitd/bin/InProc/CodeCompletionSwiftInterop.h @@ -123,6 +123,7 @@ typedef enum swiftide_completion_kind_t: uint32_t { SWIFTIDE_COMPLETION_KIND_TYPEPOSSIBLEFUNCTIONPARAMBEGINNING = 42, SWIFTIDE_COMPLETION_KIND_TYPEATTRINHERITANCEBEGINNING = 43, SWIFTIDE_COMPLETION_KIND_TYPESIMPLEINVERTED = 44, + SWIFTIDE_COMPLETION_KIND_USING = 45, } swiftide_completion_kind_t; typedef enum swiftide_completion_item_kind_t: uint32_t {